1
- # frozen_string_literal: false
2
- # = monitor.rb
3
- #
4
- # Copyright (C) 2001 Shugo Maeda <shugo@ruby-lang.org>
5
- #
6
- # This library is distributed under the terms of the Ruby license.
7
- # You can freely distribute/modify this library.
8
- #
1
+ # truffleruby_primitives: true
9
2
3
+ # Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. This
4
+ # code is released under a tri EPL/GPL/LGPL license. You can use it,
5
+ # redistribute it and/or modify it under the terms of the:
10
6
#
7
+ # Eclipse Public License version 2.0, or
8
+ # GNU General Public License version 2, or
9
+ # GNU Lesser General Public License version 2.1.
10
+
11
+ # Original version licensed under LICENSE.RUBY as it is derived from
12
+ # lib/ruby/stdlib/digest.rb and is Copyright (C) 2001 Shugo Maeda
13
+ # <shugo@ruby-lang.org>
14
+
11
15
# In concurrent programming, a monitor is an object or module intended to be
12
16
# used safely by more than one thread. The defining characteristic of a
13
17
# monitor is that its methods are executed with mutual exclusion. That is, at
87
91
# MonitorMixin module.
88
92
#
89
93
module MonitorMixin
90
- EXCEPTION_NEVER = { Exception => :never } . freeze
91
- EXCEPTION_IMMEDIATE = { Exception => :immediate } . freeze
92
-
93
94
#
94
95
# FIXME: This isn't documented in Nutshell.
95
96
#
96
97
# Since MonitorMixin.new_cond returns a ConditionVariable, and the example
97
98
# above calls while_wait and signal, this class should be documented.
98
99
#
100
+
99
101
class ConditionVariable
100
- class Timeout < Exception ; end
101
102
102
103
#
103
104
# Releases the lock held in the associated monitor and waits; reacquires the lock on wakeup.
@@ -106,18 +107,7 @@ class Timeout < Exception; end
106
107
# even if no other thread doesn't signal.
107
108
#
108
109
def wait ( timeout = nil )
109
- Thread . handle_interrupt ( EXCEPTION_NEVER ) do
110
- @monitor . __send__ ( :mon_check_owner )
111
- count = @monitor . __send__ ( :mon_exit_for_cond )
112
- begin
113
- Thread . handle_interrupt ( EXCEPTION_IMMEDIATE ) do
114
- @cond . wait ( @monitor . instance_variable_get ( :@mon_mutex ) , timeout )
115
- end
116
- return true
117
- ensure
118
- @monitor . __send__ ( :mon_enter_for_cond , count )
119
- end
120
- end
110
+ @cond . wait ( @mon_mutex , timeout )
121
111
end
122
112
123
113
#
@@ -142,23 +132,27 @@ def wait_until
142
132
# Wakes up the first thread in line waiting for this lock.
143
133
#
144
134
def signal
145
- @monitor . __send__ ( :mon_check_owner )
135
+ check_owner
146
136
@cond . signal
147
137
end
148
138
149
139
#
150
140
# Wakes up all threads waiting for this lock.
151
141
#
152
142
def broadcast
153
- @monitor . __send__ ( :mon_check_owner )
143
+ check_owner
154
144
@cond . broadcast
155
145
end
156
146
157
147
private
158
148
159
- def initialize ( monitor )
160
- @monitor = monitor
161
- @cond = Thread ::ConditionVariable . new
149
+ def check_owner
150
+ raise ThreadError , "current thread not owner" unless @mon_mutex . owned?
151
+ end
152
+
153
+ def initialize ( mutex )
154
+ @cond = ::ConditionVariable . new
155
+ @mon_mutex = mutex
162
156
end
163
157
end
164
158
@@ -171,15 +165,7 @@ def self.extend_object(obj)
171
165
# Attempts to enter exclusive section. Returns +false+ if lock fails.
172
166
#
173
167
def mon_try_enter
174
- if @mon_owner != Thread . current
175
- unless @mon_mutex . try_lock
176
- return false
177
- end
178
- @mon_owner = Thread . current
179
- @mon_count = 0
180
- end
181
- @mon_count += 1
182
- return true
168
+ Primitive . monitor_try_enter ( @mon_mutex )
183
169
end
184
170
# For backward compatibility
185
171
alias try_mon_enter mon_try_enter
@@ -188,24 +174,14 @@ def mon_try_enter
188
174
# Enters exclusive section.
189
175
#
190
176
def mon_enter
191
- if @mon_owner != Thread . current
192
- @mon_mutex . lock
193
- @mon_owner = Thread . current
194
- @mon_count = 0
195
- end
196
- @mon_count += 1
177
+ Primitive . monitor_enter ( @mon_mutex )
197
178
end
198
179
199
180
#
200
181
# Leaves exclusive section.
201
182
#
202
183
def mon_exit
203
- mon_check_owner
204
- @mon_count -=1
205
- if @mon_count == 0
206
- @mon_owner = nil
207
- @mon_mutex . unlock
208
- end
184
+ Primitive . monitor_exit ( @mon_mutex )
209
185
end
210
186
211
187
#
@@ -219,27 +195,16 @@ def mon_locked?
219
195
# Returns true if this monitor is locked by current thread.
220
196
#
221
197
def mon_owned?
222
- @mon_mutex . locked? && @mon_owner == Thread . current
198
+ @mon_mutex . owned?
223
199
end
224
200
225
201
#
226
202
# Enters exclusive section and executes the block. Leaves the exclusive
227
203
# section automatically when the block exits. See example under
228
204
# +MonitorMixin+.
229
205
#
230
- def mon_synchronize
231
- # Prevent interrupt on handling interrupts; for example timeout errors
232
- # it may break locking state.
233
- Thread . handle_interrupt ( EXCEPTION_NEVER ) do
234
- mon_enter
235
- begin
236
- Thread . handle_interrupt ( EXCEPTION_IMMEDIATE ) do
237
- yield
238
- end
239
- ensure
240
- mon_exit
241
- end
242
- end
206
+ def mon_synchronize ( &block )
207
+ Primitive . monitor_synchronize ( @mon_mutex , block )
243
208
end
244
209
alias synchronize mon_synchronize
245
210
@@ -248,11 +213,9 @@ def mon_synchronize
248
213
# receiver.
249
214
#
250
215
def new_cond
251
- return ConditionVariable . new ( self )
216
+ ConditionVariable . new ( @mon_mutex )
252
217
end
253
218
254
- private
255
-
256
219
# Use <tt>extend MonitorMixin</tt> or <tt>include MonitorMixin</tt> instead
257
220
# of this constructor. Have look at the examples above to understand how to
258
221
# use this module.
@@ -264,32 +227,13 @@ def initialize(*args)
264
227
# Initializes the MonitorMixin after being included in a class or when an
265
228
# object has been extended with the MonitorMixin
266
229
def mon_initialize
267
- if defined? ( @mon_mutex ) && @mon_mutex_owner_object_id == object_id
268
- raise ThreadError , " already initialized"
230
+ if defined? ( @mon_mutex ) && Primitive . object_equal ( @mon_mutex_owner_object , self )
231
+ raise ThreadError , ' already initialized'
269
232
end
270
233
@mon_mutex = Thread ::Mutex . new
271
- @mon_mutex_owner_object_id = object_id
272
- @mon_owner = nil
273
- @mon_count = 0
234
+ @mon_mutex_owner_object = self
274
235
end
275
236
276
- def mon_check_owner
277
- if @mon_owner != Thread . current
278
- raise ThreadError , "current thread not owner"
279
- end
280
- end
281
-
282
- def mon_enter_for_cond ( count )
283
- @mon_owner = Thread . current
284
- @mon_count = count
285
- end
286
-
287
- def mon_exit_for_cond
288
- count = @mon_count
289
- @mon_owner = nil
290
- @mon_count = 0
291
- return count
292
- end
293
237
end
294
238
295
239
# Use the Monitor class when you want to have a lock object for blocks with
0 commit comments