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.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -1
  3. data/Gemfile +1 -2
  4. data/README.md +23 -20
  5. data/Rakefile +75 -65
  6. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +10 -25
  7. data/lib/concurrent-ruby/concurrent/agent.rb +2 -1
  8. data/lib/concurrent-ruby/concurrent/array.rb +3 -13
  9. data/lib/concurrent-ruby/concurrent/atom.rb +1 -1
  10. data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +5 -4
  11. data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +5 -4
  12. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +3 -0
  13. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +81 -151
  14. data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +1 -1
  15. data/lib/concurrent-ruby/concurrent/atomic/event.rb +1 -1
  16. data/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb +109 -0
  17. data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +1 -0
  18. data/lib/concurrent-ruby/concurrent/atomic/locals.rb +189 -0
  19. data/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb +28 -0
  20. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +11 -5
  21. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +11 -5
  22. data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +1 -1
  23. data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +1 -1
  24. data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +2 -1
  25. data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +5 -3
  26. data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +6 -9
  27. data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +96 -89
  28. data/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb +37 -0
  29. data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +15 -4
  30. data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +1 -1
  31. data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +1 -1
  32. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +2 -0
  33. data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +2 -2
  34. data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +16 -8
  35. data/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb +23 -20
  36. data/lib/concurrent-ruby/concurrent/concern/logging.rb +86 -2
  37. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  38. data/lib/concurrent-ruby/concurrent/configuration.rb +4 -87
  39. data/lib/concurrent-ruby/concurrent/delay.rb +2 -2
  40. data/lib/concurrent-ruby/concurrent/errors.rb +5 -0
  41. data/lib/concurrent-ruby/concurrent/exchanger.rb +1 -0
  42. data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +1 -1
  43. data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +4 -0
  44. data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +6 -9
  45. data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +5 -0
  46. data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +7 -0
  47. data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +1 -1
  48. data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +1 -1
  49. data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +4 -1
  50. data/lib/concurrent-ruby/concurrent/executor/timer_set.rb +6 -2
  51. data/lib/concurrent-ruby/concurrent/hash.rb +5 -12
  52. data/lib/concurrent-ruby/concurrent/immutable_struct.rb +1 -1
  53. data/lib/concurrent-ruby/concurrent/ivar.rb +2 -1
  54. data/lib/concurrent-ruby/concurrent/map.rb +43 -39
  55. data/lib/concurrent-ruby/concurrent/maybe.rb +1 -1
  56. data/lib/concurrent-ruby/concurrent/mutable_struct.rb +1 -1
  57. data/lib/concurrent-ruby/concurrent/mvar.rb +1 -1
  58. data/lib/concurrent-ruby/concurrent/promise.rb +1 -1
  59. data/lib/concurrent-ruby/concurrent/promises.rb +40 -29
  60. data/lib/concurrent-ruby/concurrent/re_include.rb +2 -0
  61. data/lib/concurrent-ruby/concurrent/scheduled_task.rb +1 -1
  62. data/lib/concurrent-ruby/concurrent/set.rb +0 -10
  63. data/lib/concurrent-ruby/concurrent/settable_struct.rb +2 -2
  64. data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +5 -1
  65. data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +1 -3
  66. data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +2 -0
  67. data/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb +29 -0
  68. data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +3 -1
  69. data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +2 -0
  70. data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +5 -2
  71. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +6 -5
  72. data/lib/concurrent-ruby/concurrent/synchronization/object.rb +12 -44
  73. data/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb +36 -0
  74. data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +77 -12
  75. data/lib/concurrent-ruby/concurrent/synchronization.rb +1 -18
  76. data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +36 -39
  77. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +1 -37
  78. data/lib/concurrent-ruby/concurrent/timer_task.rb +59 -9
  79. data/lib/concurrent-ruby/concurrent/tuple.rb +1 -5
  80. data/lib/concurrent-ruby/concurrent/tvar.rb +2 -1
  81. data/lib/concurrent-ruby/concurrent/utility/engine.rb +5 -16
  82. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +3 -74
  83. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +8 -10
  84. data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +1 -0
  85. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +118 -58
  86. data/lib/concurrent-ruby/concurrent/version.rb +1 -1
  87. metadata +13 -17
  88. data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +0 -66
  89. data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +0 -37
  90. data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +0 -181
  91. data/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb +0 -927
  92. data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +0 -45
  93. data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +0 -44
  94. data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +0 -71
  95. data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +0 -49
  96. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +0 -47
  97. 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 @yeild section).
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
- # Created resolvable event, user is responsible for resolving the event once by
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 rejection with
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 with will be fulfilled with the given value.
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 with will be rejected with the given reason.
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 of futures_and_or_events is fulfilled.
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 resolved future.
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 [Future]
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 of the futures_and_or_events resolves.
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, @DefaultExecutor, executor, args, &task).future
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
- unless resolved?
775
- @Condition.wait @Lock, timeout
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, @DefaultExecutor, executor, args, &task).future
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, @DefaultExecutor, executor, args, &task).future
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 returner when raise_on_reassign is false and the receiver
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, future, index)
2078
- future.fulfilled? ||
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
@@ -31,6 +31,8 @@ module Concurrent
31
31
  #
32
32
  # C1.new.respond_to? :a # => false
33
33
  # C2.new.respond_to? :a # => true
34
+ #
35
+ # @!visibility private
34
36
  module ReInclude
35
37
  # @!visibility private
36
38
  def included(base)
@@ -57,7 +57,7 @@ module Concurrent
57
57
  #
58
58
  # @example Basic usage
59
59
  #
60
- # require 'concurrent'
60
+ # require 'concurrent/scheduled_task'
61
61
  # require 'csv'
62
62
  # require 'open-uri'
63
63
  #
@@ -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,6 +1,6 @@
1
- require 'concurrent/synchronization/abstract_struct'
2
1
  require 'concurrent/errors'
3
- require 'concurrent/synchronization'
2
+ require 'concurrent/synchronization/abstract_struct'
3
+ require 'concurrent/synchronization/lockable_object'
4
4
 
5
5
  module Concurrent
6
6
 
@@ -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 = Concurrent.monotonic_time
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
- raise NotImplementedError
8
+ # nothing to do
11
9
  end
12
10
 
13
11
  # @!visibility private
@@ -1,3 +1,5 @@
1
+ require 'concurrent/synchronization/lockable_object'
2
+
1
3
  module Concurrent
2
4
  module Synchronization
3
5
 
@@ -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? && Concurrent.java_extensions_loaded?
6
+ if Concurrent.on_jruby?
5
7
 
6
8
  # @!visibility private
7
9
  # @!macro internal_implementation_note
@@ -1,3 +1,5 @@
1
+ require 'concurrent/synchronization/lockable_object'
2
+
1
3
  module Concurrent
2
4
  module Synchronization
3
5
 
@@ -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(*defaults)
30
- super(*defaults)
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(*defaults)
65
- super(*defaults)
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
- class Object < ObjectImplementation
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
- # define only once, and not again in children
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
- @safe_initialization = false unless defined? @safe_initialization
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
- Volatile = case
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
- # {include:file:docs-source/synchronization.md}
26
- # {include:file:docs-source/synchronization-notes.md}
9
+ # @!visibility private
27
10
  module Synchronization
28
11
  end
29
12
  end