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.
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