concurrent-ruby 1.1.10 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|