concurrent-ruby 1.1.10 → 1.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +47 -1
- data/Gemfile +1 -2
- data/README.md +23 -20
- data/Rakefile +75 -65
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +10 -25
- data/lib/concurrent-ruby/concurrent/agent.rb +2 -1
- data/lib/concurrent-ruby/concurrent/array.rb +3 -13
- data/lib/concurrent-ruby/concurrent/atom.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +5 -4
- data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +5 -4
- data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +3 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +81 -151
- data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/event.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb +109 -0
- data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +1 -0
- data/lib/concurrent-ruby/concurrent/atomic/locals.rb +189 -0
- data/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb +28 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +11 -5
- data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +11 -5
- data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +2 -1
- data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +5 -3
- data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +6 -9
- data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +96 -89
- data/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb +37 -0
- data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +15 -4
- data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +1 -1
- data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +1 -1
- data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +2 -0
- data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +2 -2
- data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +16 -8
- data/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb +23 -20
- data/lib/concurrent-ruby/concurrent/concern/logging.rb +86 -2
- data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent-ruby/concurrent/configuration.rb +4 -87
- data/lib/concurrent-ruby/concurrent/delay.rb +2 -2
- data/lib/concurrent-ruby/concurrent/errors.rb +5 -0
- data/lib/concurrent-ruby/concurrent/exchanger.rb +1 -0
- data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +1 -1
- data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +4 -0
- data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +6 -9
- data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +5 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +7 -0
- data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +1 -1
- data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +1 -1
- data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +4 -1
- data/lib/concurrent-ruby/concurrent/executor/timer_set.rb +6 -2
- data/lib/concurrent-ruby/concurrent/hash.rb +5 -12
- data/lib/concurrent-ruby/concurrent/immutable_struct.rb +1 -1
- data/lib/concurrent-ruby/concurrent/ivar.rb +2 -1
- data/lib/concurrent-ruby/concurrent/map.rb +43 -39
- data/lib/concurrent-ruby/concurrent/maybe.rb +1 -1
- data/lib/concurrent-ruby/concurrent/mutable_struct.rb +1 -1
- data/lib/concurrent-ruby/concurrent/mvar.rb +1 -1
- data/lib/concurrent-ruby/concurrent/promise.rb +1 -1
- data/lib/concurrent-ruby/concurrent/promises.rb +40 -29
- data/lib/concurrent-ruby/concurrent/re_include.rb +2 -0
- data/lib/concurrent-ruby/concurrent/scheduled_task.rb +1 -1
- data/lib/concurrent-ruby/concurrent/set.rb +0 -10
- data/lib/concurrent-ruby/concurrent/settable_struct.rb +2 -2
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +5 -1
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +1 -3
- data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +2 -0
- data/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb +29 -0
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +3 -1
- data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +2 -0
- data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +5 -2
- data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +6 -5
- data/lib/concurrent-ruby/concurrent/synchronization/object.rb +12 -44
- data/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb +36 -0
- data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +77 -12
- data/lib/concurrent-ruby/concurrent/synchronization.rb +1 -18
- data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +36 -39
- data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +1 -37
- data/lib/concurrent-ruby/concurrent/timer_task.rb +59 -9
- data/lib/concurrent-ruby/concurrent/tuple.rb +1 -5
- data/lib/concurrent-ruby/concurrent/tvar.rb +2 -1
- data/lib/concurrent-ruby/concurrent/utility/engine.rb +5 -16
- data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +3 -74
- data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +8 -10
- data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +1 -0
- data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +118 -58
- data/lib/concurrent-ruby/concurrent/version.rb +1 -1
- metadata +13 -17
- data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +0 -66
- data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +0 -37
- data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +0 -181
- data/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb +0 -927
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +0 -45
- data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +0 -44
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +0 -71
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +0 -49
- data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +0 -47
- data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +0 -118
@@ -1,9 +1,11 @@
|
|
1
|
-
require 'concurrent/synchronization'
|
1
|
+
require 'concurrent/synchronization/object'
|
2
2
|
require 'concurrent/atomic/atomic_boolean'
|
3
3
|
require 'concurrent/atomic/atomic_fixnum'
|
4
4
|
require 'concurrent/collection/lock_free_stack'
|
5
|
+
require 'concurrent/configuration'
|
5
6
|
require 'concurrent/errors'
|
6
7
|
require 'concurrent/re_include'
|
8
|
+
require 'concurrent/utility/monotonic_time'
|
7
9
|
|
8
10
|
module Concurrent
|
9
11
|
|
@@ -21,7 +23,7 @@ module Concurrent
|
|
21
23
|
#
|
22
24
|
# @!macro promises.param.args
|
23
25
|
# @param [Object] args arguments which are passed to the task when it's executed.
|
24
|
-
# (It might be prepended with other arguments, see the @
|
26
|
+
# (It might be prepended with other arguments, see the @yield section).
|
25
27
|
#
|
26
28
|
# @!macro promises.shortcut.on
|
27
29
|
# Shortcut of {#$0_on} with default `:io` executor supplied.
|
@@ -62,8 +64,8 @@ module Concurrent
|
|
62
64
|
resolvable_event_on default_executor
|
63
65
|
end
|
64
66
|
|
65
|
-
#
|
66
|
-
# {Promises::ResolvableEvent#resolve}.
|
67
|
+
# Creates a resolvable event, user is responsible for resolving the event once
|
68
|
+
# by calling {Promises::ResolvableEvent#resolve}.
|
67
69
|
#
|
68
70
|
# @!macro promises.param.default_executor
|
69
71
|
# @return [ResolvableEvent]
|
@@ -93,7 +95,7 @@ module Concurrent
|
|
93
95
|
future_on(default_executor, *args, &task)
|
94
96
|
end
|
95
97
|
|
96
|
-
# Constructs new Future which will be resolved after block is evaluated on default executor.
|
98
|
+
# Constructs a new Future which will be resolved after block is evaluated on default executor.
|
97
99
|
# Evaluation begins immediately.
|
98
100
|
#
|
99
101
|
# @!macro promises.param.default_executor
|
@@ -105,7 +107,7 @@ module Concurrent
|
|
105
107
|
ImmediateEventPromise.new(default_executor).future.then(*args, &task)
|
106
108
|
end
|
107
109
|
|
108
|
-
# Creates resolved future with will be either fulfilled with the given value or
|
110
|
+
# Creates a resolved future with will be either fulfilled with the given value or rejected with
|
109
111
|
# the given reason.
|
110
112
|
#
|
111
113
|
# @param [true, false] fulfilled
|
@@ -117,7 +119,7 @@ module Concurrent
|
|
117
119
|
ImmediateFuturePromise.new(default_executor, fulfilled, value, reason).future
|
118
120
|
end
|
119
121
|
|
120
|
-
# Creates resolved future
|
122
|
+
# Creates a resolved future which will be fulfilled with the given value.
|
121
123
|
#
|
122
124
|
# @!macro promises.param.default_executor
|
123
125
|
# @param [Object] value
|
@@ -126,7 +128,7 @@ module Concurrent
|
|
126
128
|
resolved_future true, value, nil, default_executor
|
127
129
|
end
|
128
130
|
|
129
|
-
# Creates resolved future
|
131
|
+
# Creates a resolved future which will be rejected with the given reason.
|
130
132
|
#
|
131
133
|
# @!macro promises.param.default_executor
|
132
134
|
# @param [Object] reason
|
@@ -189,7 +191,7 @@ module Concurrent
|
|
189
191
|
delay_on default_executor, *args, &task
|
190
192
|
end
|
191
193
|
|
192
|
-
# Creates new event or future which is resolved only after it is touched,
|
194
|
+
# Creates a new event or future which is resolved only after it is touched,
|
193
195
|
# see {Concurrent::AbstractEventFuture#touch}.
|
194
196
|
#
|
195
197
|
# @!macro promises.param.default_executor
|
@@ -213,7 +215,7 @@ module Concurrent
|
|
213
215
|
schedule_on default_executor, intended_time, *args, &task
|
214
216
|
end
|
215
217
|
|
216
|
-
# Creates new event or future which is resolved in intended_time.
|
218
|
+
# Creates a new event or future which is resolved in intended_time.
|
217
219
|
#
|
218
220
|
# @!macro promises.param.default_executor
|
219
221
|
# @!macro promises.param.intended_time
|
@@ -239,8 +241,8 @@ module Concurrent
|
|
239
241
|
zip_futures_on default_executor, *futures_and_or_events
|
240
242
|
end
|
241
243
|
|
242
|
-
# Creates new future which is resolved after all futures_and_or_events are resolved.
|
243
|
-
# Its value is array of zipped future values. Its reason is array of reasons for rejection.
|
244
|
+
# Creates a new future which is resolved after all futures_and_or_events are resolved.
|
245
|
+
# Its value is an array of zipped future values. Its reason is an array of reasons for rejection.
|
244
246
|
# If there is an error it rejects.
|
245
247
|
# @!macro promises.event-conversion
|
246
248
|
# If event is supplied, which does not have value and can be only resolved, it's
|
@@ -261,7 +263,7 @@ module Concurrent
|
|
261
263
|
zip_events_on default_executor, *futures_and_or_events
|
262
264
|
end
|
263
265
|
|
264
|
-
# Creates new event which is resolved after all futures_and_or_events are resolved.
|
266
|
+
# Creates a new event which is resolved after all futures_and_or_events are resolved.
|
265
267
|
# (Future is resolved when fulfilled or rejected.)
|
266
268
|
#
|
267
269
|
# @!macro promises.param.default_executor
|
@@ -279,8 +281,8 @@ module Concurrent
|
|
279
281
|
|
280
282
|
alias_method :any, :any_resolved_future
|
281
283
|
|
282
|
-
# Creates new future which is resolved after first futures_and_or_events is resolved.
|
283
|
-
# Its result equals result of the first resolved future.
|
284
|
+
# Creates a new future which is resolved after the first futures_and_or_events is resolved.
|
285
|
+
# Its result equals the result of the first resolved future.
|
284
286
|
# @!macro promises.any-touch
|
285
287
|
# If resolved it does not propagate {Concurrent::AbstractEventFuture#touch}, leaving delayed
|
286
288
|
# futures un-executed if they are not required any more.
|
@@ -299,9 +301,9 @@ module Concurrent
|
|
299
301
|
any_fulfilled_future_on default_executor, *futures_and_or_events
|
300
302
|
end
|
301
303
|
|
302
|
-
# Creates new future which is resolved after first
|
303
|
-
# Its result equals result of the first resolved future or if all futures_and_or_events reject,
|
304
|
-
# it has reason of the last
|
304
|
+
# Creates a new future which is resolved after the first futures_and_or_events is fulfilled.
|
305
|
+
# Its result equals the result of the first resolved future or if all futures_and_or_events reject,
|
306
|
+
# it has reason of the last rejected future.
|
305
307
|
# @!macro promises.any-touch
|
306
308
|
# @!macro promises.event-conversion
|
307
309
|
#
|
@@ -313,12 +315,12 @@ module Concurrent
|
|
313
315
|
end
|
314
316
|
|
315
317
|
# @!macro promises.shortcut.on
|
316
|
-
# @return [
|
318
|
+
# @return [Event]
|
317
319
|
def any_event(*futures_and_or_events)
|
318
320
|
any_event_on default_executor, *futures_and_or_events
|
319
321
|
end
|
320
322
|
|
321
|
-
# Creates new event which becomes resolved after first
|
323
|
+
# Creates a new event which becomes resolved after the first futures_and_or_events resolves.
|
322
324
|
# @!macro promises.any-touch
|
323
325
|
#
|
324
326
|
# @!macro promises.param.default_executor
|
@@ -610,7 +612,7 @@ module Concurrent
|
|
610
612
|
# @yieldparam [Object] value
|
611
613
|
# @yieldparam [Object] reason
|
612
614
|
def chain_on(executor, *args, &task)
|
613
|
-
ChainPromise.new_blocked_by1(self,
|
615
|
+
ChainPromise.new_blocked_by1(self, executor, executor, args, &task).future
|
614
616
|
end
|
615
617
|
|
616
618
|
# @return [String] Short string representation.
|
@@ -771,8 +773,17 @@ module Concurrent
|
|
771
773
|
@Lock.synchronize do
|
772
774
|
@Waiters.increment
|
773
775
|
begin
|
774
|
-
|
775
|
-
|
776
|
+
if timeout
|
777
|
+
start = Concurrent.monotonic_time
|
778
|
+
until resolved?
|
779
|
+
break if @Condition.wait(@Lock, timeout) == nil # nil means timeout
|
780
|
+
timeout -= (Concurrent.monotonic_time - start)
|
781
|
+
break if timeout <= 0
|
782
|
+
end
|
783
|
+
else
|
784
|
+
until resolved?
|
785
|
+
@Condition.wait(@Lock, timeout)
|
786
|
+
end
|
776
787
|
end
|
777
788
|
ensure
|
778
789
|
# JRuby may raise ConcurrencyError
|
@@ -892,7 +903,7 @@ module Concurrent
|
|
892
903
|
private
|
893
904
|
|
894
905
|
def rejected_resolution(raise_on_reassign, state)
|
895
|
-
Concurrent::MultipleAssignmentError.new('Event can be resolved only once') if raise_on_reassign
|
906
|
+
raise Concurrent::MultipleAssignmentError.new('Event can be resolved only once') if raise_on_reassign
|
896
907
|
return false
|
897
908
|
end
|
898
909
|
|
@@ -1033,7 +1044,7 @@ module Concurrent
|
|
1033
1044
|
# @return [Future]
|
1034
1045
|
# @yield [value, *args] to the task.
|
1035
1046
|
def then_on(executor, *args, &task)
|
1036
|
-
ThenPromise.new_blocked_by1(self,
|
1047
|
+
ThenPromise.new_blocked_by1(self, executor, executor, args, &task).future
|
1037
1048
|
end
|
1038
1049
|
|
1039
1050
|
# @!macro promises.shortcut.on
|
@@ -1051,7 +1062,7 @@ module Concurrent
|
|
1051
1062
|
# @return [Future]
|
1052
1063
|
# @yield [reason, *args] to the task.
|
1053
1064
|
def rescue_on(executor, *args, &task)
|
1054
|
-
RescuePromise.new_blocked_by1(self,
|
1065
|
+
RescuePromise.new_blocked_by1(self, executor, executor, args, &task).future
|
1055
1066
|
end
|
1056
1067
|
|
1057
1068
|
# @!macro promises.method.zip
|
@@ -1298,7 +1309,7 @@ module Concurrent
|
|
1298
1309
|
|
1299
1310
|
# @!macro promise.param.raise_on_reassign
|
1300
1311
|
# @param [Boolean] raise_on_reassign should method raise exception if already resolved
|
1301
|
-
# @return [self, false] false is
|
1312
|
+
# @return [self, false] false is returned when raise_on_reassign is false and the receiver
|
1302
1313
|
# is already resolved.
|
1303
1314
|
#
|
1304
1315
|
|
@@ -2074,8 +2085,8 @@ module Concurrent
|
|
2074
2085
|
|
2075
2086
|
private
|
2076
2087
|
|
2077
|
-
def resolvable?(countdown,
|
2078
|
-
|
2088
|
+
def resolvable?(countdown, event_or_future, index)
|
2089
|
+
(event_or_future.is_a?(Event) ? event_or_future.resolved? : event_or_future.fulfilled?) ||
|
2079
2090
|
# inlined super from BlockedPromise
|
2080
2091
|
countdown.zero?
|
2081
2092
|
end
|
@@ -42,16 +42,6 @@ module Concurrent
|
|
42
42
|
|
43
43
|
JRubySet
|
44
44
|
|
45
|
-
when Concurrent.on_rbx?
|
46
|
-
require 'monitor'
|
47
|
-
require 'concurrent/thread_safe/util/data_structures'
|
48
|
-
|
49
|
-
class RbxSet < ::Set
|
50
|
-
end
|
51
|
-
|
52
|
-
ThreadSafe::Util.make_synchronized_on_rbx RbxSet
|
53
|
-
RbxSet
|
54
|
-
|
55
45
|
when Concurrent.on_truffleruby?
|
56
46
|
require 'concurrent/thread_safe/util/data_structures'
|
57
47
|
|
@@ -1,3 +1,7 @@
|
|
1
|
+
require 'concurrent/utility/native_extension_loader' # load native parts first
|
2
|
+
require 'concurrent/utility/monotonic_time'
|
3
|
+
require 'concurrent/synchronization/object'
|
4
|
+
|
1
5
|
module Concurrent
|
2
6
|
module Synchronization
|
3
7
|
|
@@ -34,7 +38,7 @@ module Concurrent
|
|
34
38
|
if timeout
|
35
39
|
wait_until = Concurrent.monotonic_time + timeout
|
36
40
|
loop do
|
37
|
-
now
|
41
|
+
now = Concurrent.monotonic_time
|
38
42
|
condition_result = condition.call
|
39
43
|
return condition_result if now >= wait_until || condition_result
|
40
44
|
ns_wait wait_until - now
|
@@ -4,10 +4,8 @@ module Concurrent
|
|
4
4
|
# @!visibility private
|
5
5
|
# @!macro internal_implementation_note
|
6
6
|
class AbstractObject
|
7
|
-
|
8
|
-
# @abstract has to be implemented based on Ruby runtime
|
9
7
|
def initialize
|
10
|
-
|
8
|
+
# nothing to do
|
11
9
|
end
|
12
10
|
|
13
11
|
# @!visibility private
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'concurrent/utility/native_extension_loader' # load native parts first
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
module Synchronization
|
5
|
+
case
|
6
|
+
when Concurrent.on_cruby?
|
7
|
+
def self.full_memory_barrier
|
8
|
+
# relying on undocumented behavior of CRuby, GVL acquire has lock which ensures visibility of ivars
|
9
|
+
# https://github.com/ruby/ruby/blob/ruby_2_2/thread_pthread.c#L204-L211
|
10
|
+
end
|
11
|
+
|
12
|
+
when Concurrent.on_jruby?
|
13
|
+
require 'concurrent/utility/native_extension_loader'
|
14
|
+
def self.full_memory_barrier
|
15
|
+
JRubyAttrVolatile.full_memory_barrier
|
16
|
+
end
|
17
|
+
|
18
|
+
when Concurrent.on_truffleruby?
|
19
|
+
def self.full_memory_barrier
|
20
|
+
TruffleRuby.full_memory_barrier
|
21
|
+
end
|
22
|
+
|
23
|
+
else
|
24
|
+
warn 'Possibly unsupported Ruby implementation'
|
25
|
+
def self.full_memory_barrier
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
require 'concurrent/utility/native_extension_loader' # load native parts first
|
2
|
+
|
1
3
|
module Concurrent
|
2
4
|
module Synchronization
|
3
5
|
|
4
|
-
if Concurrent.on_jruby?
|
6
|
+
if Concurrent.on_jruby?
|
5
7
|
|
6
8
|
# @!visibility private
|
7
9
|
# @!macro internal_implementation_note
|
@@ -1,3 +1,8 @@
|
|
1
|
+
require 'concurrent/utility/engine'
|
2
|
+
require 'concurrent/synchronization/abstract_lockable_object'
|
3
|
+
require 'concurrent/synchronization/mutex_lockable_object'
|
4
|
+
require 'concurrent/synchronization/jruby_lockable_object'
|
5
|
+
|
1
6
|
module Concurrent
|
2
7
|
module Synchronization
|
3
8
|
|
@@ -8,8 +13,6 @@ module Concurrent
|
|
8
13
|
MutexLockableObject
|
9
14
|
when Concurrent.on_jruby?
|
10
15
|
JRubyLockableObject
|
11
|
-
when Concurrent.on_rbx?
|
12
|
-
RbxLockableObject
|
13
16
|
when Concurrent.on_truffleruby?
|
14
17
|
MutexLockableObject
|
15
18
|
else
|
@@ -1,5 +1,6 @@
|
|
1
|
+
require 'concurrent/synchronization/abstract_lockable_object'
|
2
|
+
|
1
3
|
module Concurrent
|
2
|
-
# noinspection RubyInstanceVariableNamingConvention
|
3
4
|
module Synchronization
|
4
5
|
|
5
6
|
# @!visibility private
|
@@ -26,8 +27,8 @@ module Concurrent
|
|
26
27
|
|
27
28
|
safe_initialization!
|
28
29
|
|
29
|
-
def initialize
|
30
|
-
super(
|
30
|
+
def initialize
|
31
|
+
super()
|
31
32
|
@__Lock__ = ::Mutex.new
|
32
33
|
@__Condition__ = ::ConditionVariable.new
|
33
34
|
end
|
@@ -61,8 +62,8 @@ module Concurrent
|
|
61
62
|
|
62
63
|
safe_initialization!
|
63
64
|
|
64
|
-
def initialize
|
65
|
-
super(
|
65
|
+
def initialize
|
66
|
+
super()
|
66
67
|
@__Lock__ = ::Monitor.new
|
67
68
|
@__Condition__ = @__Lock__.new_cond
|
68
69
|
end
|
@@ -1,28 +1,20 @@
|
|
1
|
+
require 'concurrent/utility/native_extension_loader' # load native parts first
|
2
|
+
|
3
|
+
require 'concurrent/synchronization/safe_initialization'
|
4
|
+
require 'concurrent/synchronization/volatile'
|
5
|
+
require 'concurrent/atomic/atomic_reference'
|
6
|
+
|
1
7
|
module Concurrent
|
2
8
|
module Synchronization
|
3
9
|
|
4
|
-
# @!visibility private
|
5
|
-
# @!macro internal_implementation_note
|
6
|
-
ObjectImplementation = case
|
7
|
-
when Concurrent.on_cruby?
|
8
|
-
MriObject
|
9
|
-
when Concurrent.on_jruby?
|
10
|
-
JRubyObject
|
11
|
-
when Concurrent.on_rbx?
|
12
|
-
RbxObject
|
13
|
-
when Concurrent.on_truffleruby?
|
14
|
-
TruffleRubyObject
|
15
|
-
else
|
16
|
-
warn 'Possibly unsupported Ruby implementation'
|
17
|
-
MriObject
|
18
|
-
end
|
19
|
-
private_constant :ObjectImplementation
|
20
|
-
|
21
10
|
# Abstract object providing final, volatile, ans CAS extensions to build other concurrent abstractions.
|
22
11
|
# - final instance variables see {Object.safe_initialization!}
|
23
12
|
# - volatile instance variables see {Object.attr_volatile}
|
24
13
|
# - volatile instance variables see {Object.attr_atomic}
|
25
|
-
|
14
|
+
# @!visibility private
|
15
|
+
class Object < AbstractObject
|
16
|
+
include Volatile
|
17
|
+
|
26
18
|
# TODO make it a module if possible
|
27
19
|
|
28
20
|
# @!method self.attr_volatile(*names)
|
@@ -38,36 +30,12 @@ module Concurrent
|
|
38
30
|
__initialize_atomic_fields__
|
39
31
|
end
|
40
32
|
|
41
|
-
# By calling this method on a class, it and all its children are marked to be constructed safely. Meaning that
|
42
|
-
# all writes (ivar initializations) are made visible to all readers of newly constructed object. It ensures
|
43
|
-
# same behaviour as Java's final fields.
|
44
|
-
# @example
|
45
|
-
# class AClass < Concurrent::Synchronization::Object
|
46
|
-
# safe_initialization!
|
47
|
-
#
|
48
|
-
# def initialize
|
49
|
-
# @AFinalValue = 'value' # published safely, does not have to be synchronized
|
50
|
-
# end
|
51
|
-
# end
|
52
|
-
# @return [true]
|
53
33
|
def self.safe_initialization!
|
54
|
-
|
55
|
-
return if safe_initialization?
|
56
|
-
|
57
|
-
# @!visibility private
|
58
|
-
def self.new(*args, &block)
|
59
|
-
object = super(*args, &block)
|
60
|
-
ensure
|
61
|
-
object.full_memory_barrier if object
|
62
|
-
end
|
63
|
-
|
64
|
-
@safe_initialization = true
|
34
|
+
extend SafeInitialization unless safe_initialization?
|
65
35
|
end
|
66
36
|
|
67
|
-
# @return [true, false] if this class is safely initialized.
|
68
37
|
def self.safe_initialization?
|
69
|
-
|
70
|
-
@safe_initialization || (superclass.respond_to?(:safe_initialization?) && superclass.safe_initialization?)
|
38
|
+
self.singleton_class < SafeInitialization
|
71
39
|
end
|
72
40
|
|
73
41
|
# For testing purposes, quite slow. Injects assert code to new method which will raise if class instance contains
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'concurrent/synchronization/full_memory_barrier'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
module Synchronization
|
5
|
+
|
6
|
+
# @!visibility private
|
7
|
+
# @!macro internal_implementation_note
|
8
|
+
#
|
9
|
+
# By extending this module, a class and all its children are marked to be constructed safely. Meaning that
|
10
|
+
# all writes (ivar initializations) are made visible to all readers of newly constructed object. It ensures
|
11
|
+
# same behaviour as Java's final fields.
|
12
|
+
#
|
13
|
+
# Due to using Kernel#extend, the module is not included again if already present in the ancestors,
|
14
|
+
# which avoids extra overhead.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# class AClass < Concurrent::Synchronization::Object
|
18
|
+
# extend Concurrent::Synchronization::SafeInitialization
|
19
|
+
#
|
20
|
+
# def initialize
|
21
|
+
# @AFinalValue = 'value' # published safely, #foo will never return nil
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# def foo
|
25
|
+
# @AFinalValue
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
module SafeInitialization
|
29
|
+
def new(*args, &block)
|
30
|
+
super(*args, &block)
|
31
|
+
ensure
|
32
|
+
Concurrent::Synchronization.full_memory_barrier
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,3 +1,7 @@
|
|
1
|
+
require 'concurrent/utility/native_extension_loader' # load native parts first
|
2
|
+
require 'concurrent/utility/engine'
|
3
|
+
require 'concurrent/synchronization/full_memory_barrier'
|
4
|
+
|
1
5
|
module Concurrent
|
2
6
|
module Synchronization
|
3
7
|
|
@@ -19,18 +23,79 @@ module Concurrent
|
|
19
23
|
# => 1
|
20
24
|
# foo.bar = 2
|
21
25
|
# => 2
|
26
|
+
#
|
27
|
+
# @!visibility private
|
28
|
+
module Volatile
|
29
|
+
def self.included(base)
|
30
|
+
base.extend(ClassMethods)
|
31
|
+
end
|
32
|
+
|
33
|
+
def full_memory_barrier
|
34
|
+
Synchronization.full_memory_barrier
|
35
|
+
end
|
36
|
+
|
37
|
+
module ClassMethods
|
38
|
+
if Concurrent.on_cruby?
|
39
|
+
def attr_volatile(*names)
|
40
|
+
names.each do |name|
|
41
|
+
ivar = :"@volatile_#{name}"
|
42
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
43
|
+
def #{name}
|
44
|
+
#{ivar}
|
45
|
+
end
|
46
|
+
|
47
|
+
def #{name}=(value)
|
48
|
+
#{ivar} = value
|
49
|
+
end
|
50
|
+
RUBY
|
51
|
+
end
|
52
|
+
names.map { |n| [n, :"#{n}="] }.flatten
|
53
|
+
end
|
54
|
+
|
55
|
+
elsif Concurrent.on_jruby?
|
56
|
+
def attr_volatile(*names)
|
57
|
+
names.each do |name|
|
58
|
+
ivar = :"@volatile_#{name}"
|
59
|
+
|
60
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
61
|
+
def #{name}
|
62
|
+
::Concurrent::Synchronization::JRubyAttrVolatile.instance_variable_get_volatile(self, :#{ivar})
|
63
|
+
end
|
64
|
+
|
65
|
+
def #{name}=(value)
|
66
|
+
::Concurrent::Synchronization::JRubyAttrVolatile.instance_variable_set_volatile(self, :#{ivar}, value)
|
67
|
+
end
|
68
|
+
RUBY
|
69
|
+
|
70
|
+
end
|
71
|
+
names.map { |n| [n, :"#{n}="] }.flatten
|
72
|
+
end
|
73
|
+
|
74
|
+
else
|
75
|
+
warn 'Possibly unsupported Ruby implementation' unless Concurrent.on_truffleruby?
|
76
|
+
|
77
|
+
def attr_volatile(*names)
|
78
|
+
names.each do |name|
|
79
|
+
ivar = :"@volatile_#{name}"
|
80
|
+
|
81
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
82
|
+
def #{name}
|
83
|
+
::Concurrent::Synchronization.full_memory_barrier
|
84
|
+
#{ivar}
|
85
|
+
end
|
86
|
+
|
87
|
+
def #{name}=(value)
|
88
|
+
#{ivar} = value
|
89
|
+
::Concurrent::Synchronization.full_memory_barrier
|
90
|
+
end
|
91
|
+
RUBY
|
92
|
+
end
|
93
|
+
|
94
|
+
names.map { |n| [n, :"#{n}="] }.flatten
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
22
98
|
|
23
|
-
|
24
|
-
when Concurrent.on_cruby?
|
25
|
-
MriAttrVolatile
|
26
|
-
when Concurrent.on_jruby?
|
27
|
-
JRubyAttrVolatile
|
28
|
-
when Concurrent.on_rbx?
|
29
|
-
RbxAttrVolatile
|
30
|
-
when Concurrent.on_truffleruby?
|
31
|
-
TruffleRubyAttrVolatile
|
32
|
-
else
|
33
|
-
MriAttrVolatile
|
34
|
-
end
|
99
|
+
end
|
35
100
|
end
|
36
101
|
end
|
@@ -1,29 +1,12 @@
|
|
1
|
-
require 'concurrent/utility/engine'
|
2
|
-
|
3
|
-
require 'concurrent/synchronization/abstract_object'
|
4
1
|
require 'concurrent/utility/native_extension_loader' # load native parts first
|
5
|
-
Concurrent.load_native_extensions
|
6
2
|
|
7
|
-
require 'concurrent/synchronization/mri_object'
|
8
|
-
require 'concurrent/synchronization/jruby_object'
|
9
|
-
require 'concurrent/synchronization/rbx_object'
|
10
|
-
require 'concurrent/synchronization/truffleruby_object'
|
11
3
|
require 'concurrent/synchronization/object'
|
12
|
-
require 'concurrent/synchronization/volatile'
|
13
|
-
|
14
|
-
require 'concurrent/synchronization/abstract_lockable_object'
|
15
|
-
require 'concurrent/synchronization/mutex_lockable_object'
|
16
|
-
require 'concurrent/synchronization/jruby_lockable_object'
|
17
|
-
require 'concurrent/synchronization/rbx_lockable_object'
|
18
|
-
|
19
4
|
require 'concurrent/synchronization/lockable_object'
|
20
|
-
|
21
5
|
require 'concurrent/synchronization/condition'
|
22
6
|
require 'concurrent/synchronization/lock'
|
23
7
|
|
24
8
|
module Concurrent
|
25
|
-
#
|
26
|
-
# {include:file:docs-source/synchronization-notes.md}
|
9
|
+
# @!visibility private
|
27
10
|
module Synchronization
|
28
11
|
end
|
29
12
|
end
|