concurrent-ruby 1.0.5 → 1.1.6

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 (161) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +115 -0
  3. data/Gemfile +42 -0
  4. data/{LICENSE.txt → LICENSE.md} +2 -0
  5. data/README.md +242 -105
  6. data/Rakefile +332 -0
  7. data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
  9. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
  10. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
  11. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
  12. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +159 -0
  13. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +307 -0
  14. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
  15. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
  16. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
  17. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
  18. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
  19. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
  20. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
  21. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
  22. data/lib/concurrent-ruby/concurrent-ruby.rb +1 -0
  23. data/lib/{concurrent.rb → concurrent-ruby/concurrent.rb} +24 -20
  24. data/lib/{concurrent → concurrent-ruby/concurrent}/agent.rb +7 -7
  25. data/lib/concurrent-ruby/concurrent/array.rb +66 -0
  26. data/lib/{concurrent → concurrent-ruby/concurrent}/async.rb +18 -4
  27. data/lib/{concurrent → concurrent-ruby/concurrent}/atom.rb +10 -10
  28. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/abstract_thread_local_var.rb +0 -0
  29. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_boolean.rb +26 -22
  30. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_fixnum.rb +27 -23
  31. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
  32. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +204 -0
  33. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/count_down_latch.rb +7 -7
  34. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/cyclic_barrier.rb +1 -1
  35. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/event.rb +1 -1
  36. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_count_down_latch.rb +9 -6
  37. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_thread_local_var.rb +0 -0
  38. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_boolean.rb +2 -0
  39. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_fixnum.rb +0 -0
  40. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_count_down_latch.rb +1 -0
  41. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_semaphore.rb +0 -0
  42. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/read_write_lock.rb +2 -1
  43. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/reentrant_read_write_lock.rb +3 -1
  44. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/ruby_thread_local_var.rb +43 -33
  45. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/semaphore.rb +8 -8
  46. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/thread_local_var.rb +8 -8
  47. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/mutex_atomic.rb +3 -8
  48. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/numeric_cas_wrapper.rb +1 -1
  49. data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
  50. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_notify_observer_set.rb +0 -0
  51. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_write_observer_set.rb +0 -0
  52. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/java_non_concurrent_priority_queue.rb +0 -0
  53. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
  54. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/atomic_reference_map_backend.rb +3 -3
  55. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/mri_map_backend.rb +0 -0
  56. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/non_concurrent_map_backend.rb +1 -2
  57. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/synchronized_map_backend.rb +0 -0
  58. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/non_concurrent_priority_queue.rb +30 -30
  59. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb +0 -0
  60. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/deprecation.rb +0 -0
  61. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/dereferenceable.rb +3 -3
  62. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/logging.rb +6 -1
  63. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/obligation.rb +0 -0
  64. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/observable.rb +7 -7
  65. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  66. data/lib/{concurrent → concurrent-ruby/concurrent}/configuration.rb +15 -15
  67. data/lib/{concurrent → concurrent-ruby/concurrent}/constants.rb +1 -1
  68. data/lib/{concurrent → concurrent-ruby/concurrent}/dataflow.rb +2 -1
  69. data/lib/{concurrent → concurrent-ruby/concurrent}/delay.rb +9 -7
  70. data/lib/{concurrent → concurrent-ruby/concurrent}/errors.rb +0 -0
  71. data/lib/{concurrent → concurrent-ruby/concurrent}/exchanger.rb +21 -25
  72. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/abstract_executor_service.rb +19 -25
  73. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/cached_thread_pool.rb +5 -5
  74. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/executor_service.rb +17 -17
  75. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/fixed_thread_pool.rb +27 -30
  76. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/immediate_executor.rb +0 -0
  77. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/indirect_immediate_executor.rb +0 -0
  78. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_executor_service.rb +19 -16
  79. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_single_thread_executor.rb +4 -3
  80. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_thread_pool_executor.rb +12 -8
  81. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_executor_service.rb +0 -2
  82. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_single_thread_executor.rb +0 -1
  83. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_thread_pool_executor.rb +9 -4
  84. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/safe_task_executor.rb +0 -0
  85. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serial_executor_service.rb +0 -0
  86. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution.rb +0 -0
  87. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution_delegator.rb +0 -0
  88. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/simple_executor_service.rb +1 -1
  89. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/single_thread_executor.rb +3 -2
  90. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/thread_pool_executor.rb +6 -6
  91. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/timer_set.rb +14 -17
  92. data/lib/{concurrent → concurrent-ruby/concurrent}/executors.rb +0 -0
  93. data/lib/{concurrent → concurrent-ruby/concurrent}/future.rb +4 -1
  94. data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
  95. data/lib/{concurrent → concurrent-ruby/concurrent}/immutable_struct.rb +8 -0
  96. data/lib/{concurrent → concurrent-ruby/concurrent}/ivar.rb +5 -6
  97. data/lib/concurrent-ruby/concurrent/map.rb +337 -0
  98. data/lib/{concurrent → concurrent-ruby/concurrent}/maybe.rb +1 -1
  99. data/lib/{concurrent → concurrent-ruby/concurrent}/mutable_struct.rb +25 -14
  100. data/lib/{concurrent → concurrent-ruby/concurrent}/mvar.rb +2 -2
  101. data/lib/{concurrent → concurrent-ruby/concurrent}/options.rb +0 -0
  102. data/lib/{concurrent → concurrent-ruby/concurrent}/promise.rb +53 -21
  103. data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
  104. data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
  105. data/lib/{concurrent → concurrent-ruby/concurrent}/scheduled_task.rb +0 -0
  106. data/lib/concurrent-ruby/concurrent/set.rb +66 -0
  107. data/lib/{concurrent → concurrent-ruby/concurrent}/settable_struct.rb +11 -0
  108. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization.rb +4 -5
  109. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_lockable_object.rb +5 -5
  110. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_object.rb +0 -0
  111. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_struct.rb +18 -4
  112. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/condition.rb +2 -0
  113. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_lockable_object.rb +0 -0
  114. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_object.rb +1 -0
  115. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lock.rb +2 -0
  116. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lockable_object.rb +6 -6
  117. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mri_object.rb +1 -0
  118. data/lib/{concurrent/synchronization/mri_lockable_object.rb → concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb} +19 -14
  119. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/object.rb +53 -23
  120. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_lockable_object.rb +0 -0
  121. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_object.rb +1 -0
  122. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
  123. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/volatile.rb +11 -9
  124. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/synchronized_delegator.rb +0 -0
  125. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util.rb +0 -0
  126. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/adder.rb +0 -0
  127. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/cheap_lockable.rb +0 -0
  128. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +63 -0
  129. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/power_of_two_tuple.rb +0 -0
  130. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/striped64.rb +9 -4
  131. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/volatile.rb +0 -0
  132. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/xor_shift_random.rb +0 -0
  133. data/lib/{concurrent → concurrent-ruby/concurrent}/timer_task.rb +5 -2
  134. data/lib/{concurrent → concurrent-ruby/concurrent}/tuple.rb +1 -1
  135. data/lib/{concurrent → concurrent-ruby/concurrent}/tvar.rb +2 -2
  136. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/engine.rb +4 -4
  137. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/monotonic_time.rb +3 -3
  138. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
  139. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_integer.rb +0 -0
  140. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/processor_counter.rb +5 -2
  141. data/lib/concurrent-ruby/concurrent/version.rb +3 -0
  142. metadata +146 -131
  143. data/lib/concurrent/array.rb +0 -39
  144. data/lib/concurrent/atomic/atomic_reference.rb +0 -51
  145. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +0 -8
  146. data/lib/concurrent/atomic_reference/direct_update.rb +0 -81
  147. data/lib/concurrent/atomic_reference/jruby+truffle.rb +0 -2
  148. data/lib/concurrent/atomic_reference/jruby.rb +0 -16
  149. data/lib/concurrent/atomic_reference/rbx.rb +0 -22
  150. data/lib/concurrent/atomic_reference/ruby.rb +0 -32
  151. data/lib/concurrent/atomics.rb +0 -53
  152. data/lib/concurrent/edge.rb +0 -26
  153. data/lib/concurrent/hash.rb +0 -36
  154. data/lib/concurrent/lazy_register.rb +0 -81
  155. data/lib/concurrent/map.rb +0 -240
  156. data/lib/concurrent/synchronization/truffle_lockable_object.rb +0 -9
  157. data/lib/concurrent/synchronization/truffle_object.rb +0 -31
  158. data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +0 -30
  159. data/lib/concurrent/utility/at_exit.rb +0 -97
  160. data/lib/concurrent/utility/native_extension_loader.rb +0 -73
  161. data/lib/concurrent/version.rb +0 -4
@@ -0,0 +1,204 @@
1
+ require 'concurrent/synchronization'
2
+ require 'concurrent/utility/engine'
3
+ require 'concurrent/atomic_reference/numeric_cas_wrapper'
4
+
5
+ # Shim for TruffleRuby::AtomicReference
6
+ if Concurrent.on_truffleruby? && !defined?(TruffleRuby::AtomicReference)
7
+ # @!visibility private
8
+ module TruffleRuby
9
+ AtomicReference = Truffle::AtomicReference
10
+ end
11
+ end
12
+
13
+ module Concurrent
14
+
15
+ # Define update methods that use direct paths
16
+ #
17
+ # @!visibility private
18
+ # @!macro internal_implementation_note
19
+ module AtomicDirectUpdate
20
+
21
+ # @!macro atomic_reference_method_update
22
+ #
23
+ # Pass the current value to the given block, replacing it
24
+ # with the block's result. May retry if the value changes
25
+ # during the block's execution.
26
+ #
27
+ # @yield [Object] Calculate a new value for the atomic reference using
28
+ # given (old) value
29
+ # @yieldparam [Object] old_value the starting value of the atomic reference
30
+ # @return [Object] the new value
31
+ def update
32
+ true until compare_and_set(old_value = get, new_value = yield(old_value))
33
+ new_value
34
+ end
35
+
36
+ # @!macro atomic_reference_method_try_update
37
+ #
38
+ # Pass the current value to the given block, replacing it
39
+ # with the block's result. Return nil if the update fails.
40
+ #
41
+ # @yield [Object] Calculate a new value for the atomic reference using
42
+ # given (old) value
43
+ # @yieldparam [Object] old_value the starting value of the atomic reference
44
+ # @note This method was altered to avoid raising an exception by default.
45
+ # Instead, this method now returns `nil` in case of failure. For more info,
46
+ # please see: https://github.com/ruby-concurrency/concurrent-ruby/pull/336
47
+ # @return [Object] the new value, or nil if update failed
48
+ def try_update
49
+ old_value = get
50
+ new_value = yield old_value
51
+
52
+ return unless compare_and_set old_value, new_value
53
+
54
+ new_value
55
+ end
56
+
57
+ # @!macro atomic_reference_method_try_update!
58
+ #
59
+ # Pass the current value to the given block, replacing it
60
+ # with the block's result. Raise an exception if the update
61
+ # fails.
62
+ #
63
+ # @yield [Object] Calculate a new value for the atomic reference using
64
+ # given (old) value
65
+ # @yieldparam [Object] old_value the starting value of the atomic reference
66
+ # @note This behavior mimics the behavior of the original
67
+ # `AtomicReference#try_update` API. The reason this was changed was to
68
+ # avoid raising exceptions (which are inherently slow) by default. For more
69
+ # info: https://github.com/ruby-concurrency/concurrent-ruby/pull/336
70
+ # @return [Object] the new value
71
+ # @raise [Concurrent::ConcurrentUpdateError] if the update fails
72
+ def try_update!
73
+ old_value = get
74
+ new_value = yield old_value
75
+ unless compare_and_set(old_value, new_value)
76
+ if $VERBOSE
77
+ raise ConcurrentUpdateError, "Update failed"
78
+ else
79
+ raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE
80
+ end
81
+ end
82
+ new_value
83
+ end
84
+ end
85
+
86
+ require 'concurrent/atomic_reference/mutex_atomic'
87
+
88
+ # @!macro atomic_reference
89
+ #
90
+ # An object reference that may be updated atomically. All read and write
91
+ # operations have java volatile semantic.
92
+ #
93
+ # @!macro thread_safe_variable_comparison
94
+ #
95
+ # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html
96
+ # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html
97
+ #
98
+ # @!method initialize(value = nil)
99
+ # @!macro atomic_reference_method_initialize
100
+ # @param [Object] value The initial value.
101
+ #
102
+ # @!method get
103
+ # @!macro atomic_reference_method_get
104
+ # Gets the current value.
105
+ # @return [Object] the current value
106
+ #
107
+ # @!method set(new_value)
108
+ # @!macro atomic_reference_method_set
109
+ # Sets to the given value.
110
+ # @param [Object] new_value the new value
111
+ # @return [Object] the new value
112
+ #
113
+ # @!method get_and_set(new_value)
114
+ # @!macro atomic_reference_method_get_and_set
115
+ # Atomically sets to the given value and returns the old value.
116
+ # @param [Object] new_value the new value
117
+ # @return [Object] the old value
118
+ #
119
+ # @!method compare_and_set(old_value, new_value)
120
+ # @!macro atomic_reference_method_compare_and_set
121
+ #
122
+ # Atomically sets the value to the given updated value if
123
+ # the current value == the expected value.
124
+ #
125
+ # @param [Object] old_value the expected value
126
+ # @param [Object] new_value the new value
127
+ #
128
+ # @return [Boolean] `true` if successful. A `false` return indicates
129
+ # that the actual value was not equal to the expected value.
130
+ #
131
+ # @!method update
132
+ # @!macro atomic_reference_method_update
133
+ #
134
+ # @!method try_update
135
+ # @!macro atomic_reference_method_try_update
136
+ #
137
+ # @!method try_update!
138
+ # @!macro atomic_reference_method_try_update!
139
+
140
+
141
+ # @!macro internal_implementation_note
142
+ class ConcurrentUpdateError < ThreadError
143
+ # frozen pre-allocated backtrace to speed ConcurrentUpdateError
144
+ CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze
145
+ end
146
+
147
+ # @!macro internal_implementation_note
148
+ AtomicReferenceImplementation = case
149
+ when Concurrent.on_cruby? && Concurrent.c_extensions_loaded?
150
+ # @!visibility private
151
+ # @!macro internal_implementation_note
152
+ class CAtomicReference
153
+ include AtomicDirectUpdate
154
+ include AtomicNumericCompareAndSetWrapper
155
+ alias_method :compare_and_swap, :compare_and_set
156
+ end
157
+ CAtomicReference
158
+ when Concurrent.on_jruby?
159
+ # @!visibility private
160
+ # @!macro internal_implementation_note
161
+ class JavaAtomicReference
162
+ include AtomicDirectUpdate
163
+ end
164
+ JavaAtomicReference
165
+ when Concurrent.on_truffleruby?
166
+ class TruffleRubyAtomicReference < TruffleRuby::AtomicReference
167
+ include AtomicDirectUpdate
168
+ alias_method :value, :get
169
+ alias_method :value=, :set
170
+ alias_method :compare_and_swap, :compare_and_set
171
+ alias_method :swap, :get_and_set
172
+ end
173
+ when Concurrent.on_rbx?
174
+ # @note Extends `Rubinius::AtomicReference` version adding aliases
175
+ # and numeric logic.
176
+ #
177
+ # @!visibility private
178
+ # @!macro internal_implementation_note
179
+ class RbxAtomicReference < Rubinius::AtomicReference
180
+ alias_method :_compare_and_set, :compare_and_set
181
+ include AtomicDirectUpdate
182
+ include AtomicNumericCompareAndSetWrapper
183
+ alias_method :value, :get
184
+ alias_method :value=, :set
185
+ alias_method :swap, :get_and_set
186
+ alias_method :compare_and_swap, :compare_and_set
187
+ end
188
+ RbxAtomicReference
189
+ else
190
+ MutexAtomicReference
191
+ end
192
+ private_constant :AtomicReferenceImplementation
193
+
194
+ # @!macro atomic_reference
195
+ class AtomicReference < AtomicReferenceImplementation
196
+
197
+ # @return [String] Short string representation.
198
+ def to_s
199
+ format '%s value:%s>', super[0..-2], get
200
+ end
201
+
202
+ alias_method :inspect, :to_s
203
+ end
204
+ end
@@ -1,12 +1,12 @@
1
+ require 'concurrent/utility/engine'
1
2
  require 'concurrent/atomic/mutex_count_down_latch'
2
3
  require 'concurrent/atomic/java_count_down_latch'
3
- require 'concurrent/utility/engine'
4
4
 
5
5
  module Concurrent
6
6
 
7
7
  ###################################################################
8
8
 
9
- # @!macro [new] count_down_latch_method_initialize
9
+ # @!macro count_down_latch_method_initialize
10
10
  #
11
11
  # Create a new `CountDownLatch` with the initial `count`.
12
12
  #
@@ -14,7 +14,7 @@ module Concurrent
14
14
  #
15
15
  # @raise [ArgumentError] if `count` is not an integer or is less than zero
16
16
 
17
- # @!macro [new] count_down_latch_method_wait
17
+ # @!macro count_down_latch_method_wait
18
18
  #
19
19
  # Block on the latch until the counter reaches zero or until `timeout` is reached.
20
20
  #
@@ -22,12 +22,12 @@ module Concurrent
22
22
  # to block indefinitely
23
23
  # @return [Boolean] `true` if the `count` reaches zero else false on `timeout`
24
24
 
25
- # @!macro [new] count_down_latch_method_count_down
25
+ # @!macro count_down_latch_method_count_down
26
26
  #
27
27
  # Signal the latch to decrement the counter. Will signal all blocked threads when
28
28
  # the `count` reaches zero.
29
29
 
30
- # @!macro [attach] count_down_latch_method_count
30
+ # @!macro count_down_latch_method_count
31
31
  #
32
32
  # The current value of the counter.
33
33
  #
@@ -35,7 +35,7 @@ module Concurrent
35
35
 
36
36
  ###################################################################
37
37
 
38
- # @!macro [new] count_down_latch_public_api
38
+ # @!macro count_down_latch_public_api
39
39
  #
40
40
  # @!method initialize(count = 1)
41
41
  # @!macro count_down_latch_method_initialize
@@ -61,7 +61,7 @@ module Concurrent
61
61
  end
62
62
  private_constant :CountDownLatchImplementation
63
63
 
64
- # @!macro [attach] count_down_latch
64
+ # @!macro count_down_latch
65
65
  #
66
66
  # A synchronization object that allows one thread to wait on multiple other threads.
67
67
  # The thread that will wait creates a `CountDownLatch` and sets the initial value
@@ -23,7 +23,7 @@ module Concurrent
23
23
  # # use main as well
24
24
  # process.call 2
25
25
  #
26
- # # here we can be sure that all jobs are processed
26
+ # # here we can be sure that all jobs are processed
27
27
  class CyclicBarrier < Synchronization::LockableObject
28
28
 
29
29
  # @!visibility private
@@ -32,7 +32,7 @@ module Concurrent
32
32
  # # prints:
33
33
  # # t2 calling set
34
34
  # # t1 is waiting
35
- # # event ocurred
35
+ # # event occurred
36
36
  class Event < Synchronization::LockableObject
37
37
 
38
38
  # Creates a new `Event` in the unset state. Threads calling `#wait` on the
@@ -9,20 +9,23 @@ if Concurrent.on_jruby?
9
9
 
10
10
  # @!macro count_down_latch_method_initialize
11
11
  def initialize(count = 1)
12
- unless count.is_a?(Fixnum) && count >= 0
13
- raise ArgumentError.new('count must be in integer greater than or equal zero')
14
- end
12
+ Utility::NativeInteger.ensure_integer_and_bounds(count)
13
+ Utility::NativeInteger.ensure_positive(count)
15
14
  @latch = java.util.concurrent.CountDownLatch.new(count)
16
15
  end
17
16
 
18
17
  # @!macro count_down_latch_method_wait
19
18
  def wait(timeout = nil)
19
+ result = nil
20
20
  if timeout.nil?
21
- @latch.await
22
- true
21
+ Synchronization::JRuby.sleep_interruptibly { @latch.await }
22
+ result = true
23
23
  else
24
- @latch.await(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
24
+ Synchronization::JRuby.sleep_interruptibly do
25
+ result = @latch.await(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
26
+ end
25
27
  end
28
+ result
26
29
  end
27
30
 
28
31
  # @!macro count_down_latch_method_count_down
@@ -50,6 +50,8 @@ module Concurrent
50
50
  @value = !!initial
51
51
  end
52
52
 
53
+ private
54
+
53
55
  # @!visibility private
54
56
  def ns_make_value(value)
55
57
  old = @value
@@ -1,4 +1,5 @@
1
1
  require 'concurrent/synchronization'
2
+ require 'concurrent/utility/native_integer'
2
3
 
3
4
  module Concurrent
4
5
 
@@ -193,7 +193,8 @@ module Concurrent
193
193
  #
194
194
  # @return [Boolean] true if the lock is successfully released
195
195
  def release_write_lock
196
- c = @Counter.update { |counter| counter-RUNNING_WRITER }
196
+ return true unless running_writer?
197
+ c = @Counter.update { |counter| counter - RUNNING_WRITER }
197
198
  @ReadLock.broadcast
198
199
  @WriteLock.signal if waiting_writers(c) > 0
199
200
  true
@@ -21,7 +21,9 @@ module Concurrent
21
21
  # also acquire a read lock OR a write lock more than once. Only when the read (or
22
22
  # write) lock is released as many times as it was acquired, will the thread
23
23
  # actually let it go, allowing other threads which might have been waiting
24
- # to proceed.
24
+ # to proceed. Therefore the lock can be upgraded by first acquiring
25
+ # read lock and then write lock and that the lock can be downgraded by first
26
+ # having both read and write lock a releasing just the write lock.
25
27
  #
26
28
  # If both read and write locks are acquired by the same thread, it is not strictly
27
29
  # necessary to release them in the same order they were acquired. In other words,
@@ -32,12 +32,38 @@ module Concurrent
32
32
  FREE = []
33
33
  LOCK = Mutex.new
34
34
  ARRAYS = {} # used as a hash set
35
+ # noinspection RubyClassVariableUsageInspection
35
36
  @@next = 0
36
- private_constant :FREE, :LOCK, :ARRAYS
37
+ QUEUE = Queue.new
38
+ THREAD = Thread.new do
39
+ while true
40
+ method, i = QUEUE.pop
41
+ case method
42
+ when :thread_local_finalizer
43
+ LOCK.synchronize do
44
+ FREE.push(i)
45
+ # The cost of GC'ing a TLV is linear in the number of threads using TLVs
46
+ # But that is natural! More threads means more storage is used per TLV
47
+ # So naturally more CPU time is required to free more storage
48
+ ARRAYS.each_value do |array|
49
+ array[i] = nil
50
+ end
51
+ end
52
+ when :thread_finalizer
53
+ LOCK.synchronize do
54
+ # The thread which used this thread-local array is now gone
55
+ # So don't hold onto a reference to the array (thus blocking GC)
56
+ ARRAYS.delete(i)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ private_constant :FREE, :LOCK, :ARRAYS, :QUEUE, :THREAD
37
63
 
38
64
  # @!macro thread_local_var_method_get
39
65
  def value
40
- if array = get_threadlocal_array
66
+ if (array = get_threadlocal_array)
41
67
  value = array[@index]
42
68
  if value.nil?
43
69
  default
@@ -57,10 +83,10 @@ module Concurrent
57
83
  # We could keep the thread-local arrays in a hash, keyed by Thread
58
84
  # But why? That would require locking
59
85
  # Using Ruby's built-in thread-local storage is faster
60
- unless array = get_threadlocal_array(me)
86
+ unless (array = get_threadlocal_array(me))
61
87
  array = set_threadlocal_array([], me)
62
88
  LOCK.synchronize { ARRAYS[array.object_id] = array }
63
- ObjectSpace.define_finalizer(me, self.class.thread_finalizer(array))
89
+ ObjectSpace.define_finalizer(me, self.class.thread_finalizer(array.object_id))
64
90
  end
65
91
  array[@index] = (value.nil? ? NULL : value)
66
92
  value
@@ -69,6 +95,7 @@ module Concurrent
69
95
  protected
70
96
 
71
97
  # @!visibility private
98
+ # noinspection RubyClassVariableUsageInspection
72
99
  def allocate_storage
73
100
  @index = LOCK.synchronize do
74
101
  FREE.pop || begin
@@ -77,37 +104,19 @@ module Concurrent
77
104
  result
78
105
  end
79
106
  end
80
- ObjectSpace.define_finalizer(self, self.class.threadlocal_finalizer(@index))
107
+ ObjectSpace.define_finalizer(self, self.class.thread_local_finalizer(@index))
81
108
  end
82
109
 
83
110
  # @!visibility private
84
- def self.threadlocal_finalizer(index)
85
- proc do
86
- Thread.new do # avoid error: can't be called from trap context
87
- LOCK.synchronize do
88
- FREE.push(index)
89
- # The cost of GC'ing a TLV is linear in the number of threads using TLVs
90
- # But that is natural! More threads means more storage is used per TLV
91
- # So naturally more CPU time is required to free more storage
92
- ARRAYS.each_value do |array|
93
- array[index] = nil
94
- end
95
- end
96
- end
97
- end
111
+ def self.thread_local_finalizer(index)
112
+ # avoid error: can't be called from trap context
113
+ proc { QUEUE.push [:thread_local_finalizer, index] }
98
114
  end
99
115
 
100
116
  # @!visibility private
101
- def self.thread_finalizer(array)
102
- proc do
103
- Thread.new do # avoid error: can't be called from trap context
104
- LOCK.synchronize do
105
- # The thread which used this thread-local array is now gone
106
- # So don't hold onto a reference to the array (thus blocking GC)
107
- ARRAYS.delete(array.object_id)
108
- end
109
- end
110
- end
117
+ def self.thread_finalizer(id)
118
+ # avoid error: can't be called from trap context
119
+ proc { QUEUE.push [:thread_finalizer, id] }
111
120
  end
112
121
 
113
122
  private
@@ -136,21 +145,22 @@ module Concurrent
136
145
  # This exists only for use in testing
137
146
  # @!visibility private
138
147
  def value_for(thread)
139
- if array = get_threadlocal_array(thread)
148
+ if (array = get_threadlocal_array(thread))
140
149
  value = array[@index]
141
150
  if value.nil?
142
- default_for(thread)
151
+ get_default
143
152
  elsif value.equal?(NULL)
144
153
  nil
145
154
  else
146
155
  value
147
156
  end
148
157
  else
149
- default_for(thread)
158
+ get_default
150
159
  end
151
160
  end
152
161
 
153
- def default_for(thread)
162
+ # @!visibility private
163
+ def get_default
154
164
  if @default_block
155
165
  raise "Cannot use default_for with default block"
156
166
  else