concurrent-ruby 1.1.8 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -0
  3. data/Gemfile +2 -8
  4. data/README.md +49 -28
  5. data/Rakefile +66 -81
  6. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +0 -0
  7. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +52 -22
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +10 -25
  9. data/lib/concurrent-ruby/concurrent/agent.rb +2 -1
  10. data/lib/concurrent-ruby/concurrent/array.rb +0 -10
  11. data/lib/concurrent-ruby/concurrent/async.rb +1 -0
  12. data/lib/concurrent-ruby/concurrent/atom.rb +1 -1
  13. data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +5 -4
  14. data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +5 -4
  15. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +3 -0
  16. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +82 -151
  17. data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +1 -1
  18. data/lib/concurrent-ruby/concurrent/atomic/event.rb +3 -3
  19. data/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb +109 -0
  20. data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +1 -0
  21. data/lib/concurrent-ruby/concurrent/atomic/locals.rb +189 -0
  22. data/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb +28 -0
  23. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +11 -5
  24. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +11 -5
  25. data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +1 -1
  26. data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +19 -3
  27. data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +2 -1
  28. data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +9 -9
  29. data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +32 -14
  30. data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +96 -89
  31. data/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb +37 -0
  32. data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +15 -4
  33. data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +1 -1
  34. data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +1 -1
  35. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +2 -0
  36. data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +2 -2
  37. data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +16 -8
  38. data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
  39. data/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +11 -1
  40. data/lib/concurrent-ruby/concurrent/concern/logging.rb +86 -2
  41. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  42. data/lib/concurrent-ruby/concurrent/configuration.rb +4 -87
  43. data/lib/concurrent-ruby/concurrent/delay.rb +2 -2
  44. data/lib/concurrent-ruby/concurrent/errors.rb +5 -0
  45. data/lib/concurrent-ruby/concurrent/exchanger.rb +1 -0
  46. data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +17 -14
  47. data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +13 -3
  48. data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +3 -3
  49. data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +4 -0
  50. data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +10 -4
  51. data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +26 -37
  52. data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +6 -6
  53. data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +1 -1
  54. data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +4 -1
  55. data/lib/concurrent-ruby/concurrent/hash.rb +0 -9
  56. data/lib/concurrent-ruby/concurrent/immutable_struct.rb +1 -1
  57. data/lib/concurrent-ruby/concurrent/ivar.rb +2 -1
  58. data/lib/concurrent-ruby/concurrent/map.rb +43 -30
  59. data/lib/concurrent-ruby/concurrent/maybe.rb +1 -1
  60. data/lib/concurrent-ruby/concurrent/mutable_struct.rb +1 -1
  61. data/lib/concurrent-ruby/concurrent/mvar.rb +1 -1
  62. data/lib/concurrent-ruby/concurrent/promise.rb +2 -1
  63. data/lib/concurrent-ruby/concurrent/promises.rb +7 -6
  64. data/lib/concurrent-ruby/concurrent/re_include.rb +2 -0
  65. data/lib/concurrent-ruby/concurrent/scheduled_task.rb +30 -17
  66. data/lib/concurrent-ruby/concurrent/set.rb +12 -14
  67. data/lib/concurrent-ruby/concurrent/settable_struct.rb +2 -2
  68. data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +5 -1
  69. data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +1 -3
  70. data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +2 -0
  71. data/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb +29 -0
  72. data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +3 -1
  73. data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +2 -0
  74. data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +6 -5
  75. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +18 -5
  76. data/lib/concurrent-ruby/concurrent/synchronization/object.rb +12 -44
  77. data/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb +36 -0
  78. data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +77 -12
  79. data/lib/concurrent-ruby/concurrent/synchronization.rb +1 -18
  80. data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +36 -39
  81. data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +2 -39
  82. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +16 -27
  83. data/lib/concurrent-ruby/concurrent/timer_task.rb +11 -33
  84. data/lib/concurrent-ruby/concurrent/tuple.rb +1 -5
  85. data/lib/concurrent-ruby/concurrent/tvar.rb +22 -61
  86. data/lib/concurrent-ruby/concurrent/utility/engine.rb +5 -16
  87. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +7 -46
  88. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +8 -10
  89. data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +1 -0
  90. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +36 -89
  91. data/lib/concurrent-ruby/concurrent/version.rb +1 -1
  92. data/lib/concurrent-ruby/concurrent-ruby.rb +5 -1
  93. metadata +11 -12
  94. data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +0 -66
  95. data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +0 -37
  96. data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +0 -181
  97. data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +0 -45
  98. data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +0 -44
  99. data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +0 -65
  100. data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +0 -49
  101. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +0 -47
@@ -55,12 +55,6 @@ public class SynchronizationLibrary implements Library {
55
55
  }
56
56
  }
57
57
 
58
- private static final ObjectAllocator JRUBY_OBJECT_ALLOCATOR = new ObjectAllocator() {
59
- public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
60
- return new JRubyObject(runtime, klazz);
61
- }
62
- };
63
-
64
58
  private static final ObjectAllocator OBJECT_ALLOCATOR = new ObjectAllocator() {
65
59
  public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
66
60
  return new Object(runtime, klazz);
@@ -87,10 +81,7 @@ public class SynchronizationLibrary implements Library {
87
81
  RubyModule jrubyAttrVolatileModule = synchronizationModule.defineModuleUnder("JRubyAttrVolatile");
88
82
  jrubyAttrVolatileModule.defineAnnotatedMethods(JRubyAttrVolatile.class);
89
83
 
90
- defineClass(runtime, synchronizationModule, "AbstractObject", "JRubyObject",
91
- JRubyObject.class, JRUBY_OBJECT_ALLOCATOR);
92
-
93
- defineClass(runtime, synchronizationModule, "JRubyObject", "Object",
84
+ defineClass(runtime, synchronizationModule, "AbstractObject", "Object",
94
85
  Object.class, OBJECT_ALLOCATOR);
95
86
 
96
87
  defineClass(runtime, synchronizationModule, "Object", "AbstractLockableObject",
@@ -143,8 +134,8 @@ public class SynchronizationLibrary implements Library {
143
134
  // attempt to avoid code elimination.
144
135
  private static volatile int volatileField;
145
136
 
146
- @JRubyMethod(name = "full_memory_barrier", visibility = Visibility.PUBLIC)
147
- public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject self) {
137
+ @JRubyMethod(name = "full_memory_barrier", visibility = Visibility.PUBLIC, module = true)
138
+ public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject module) {
148
139
  // Prevent reordering of ivar writes with publication of this instance
149
140
  if (!FULL_FENCE) {
150
141
  // Assuming that following volatile read and write is not eliminated it simulates fullFence.
@@ -158,9 +149,10 @@ public class SynchronizationLibrary implements Library {
158
149
  return context.nil;
159
150
  }
160
151
 
161
- @JRubyMethod(name = "instance_variable_get_volatile", visibility = Visibility.PUBLIC)
152
+ @JRubyMethod(name = "instance_variable_get_volatile", visibility = Visibility.PUBLIC, module = true)
162
153
  public static IRubyObject instanceVariableGetVolatile(
163
154
  ThreadContext context,
155
+ IRubyObject module,
164
156
  IRubyObject self,
165
157
  IRubyObject name) {
166
158
  // Ensure we ses latest value with loadFence
@@ -174,9 +166,10 @@ public class SynchronizationLibrary implements Library {
174
166
  }
175
167
  }
176
168
 
177
- @JRubyMethod(name = "instance_variable_set_volatile", visibility = Visibility.PUBLIC)
169
+ @JRubyMethod(name = "instance_variable_set_volatile", visibility = Visibility.PUBLIC, module = true)
178
170
  public static IRubyObject InstanceVariableSetVolatile(
179
171
  ThreadContext context,
172
+ IRubyObject module,
180
173
  IRubyObject self,
181
174
  IRubyObject name,
182
175
  IRubyObject value) {
@@ -195,16 +188,8 @@ public class SynchronizationLibrary implements Library {
195
188
  }
196
189
  }
197
190
 
198
- @JRubyClass(name = "JRubyObject", parent = "AbstractObject")
199
- public static class JRubyObject extends RubyObject {
200
-
201
- public JRubyObject(Ruby runtime, RubyClass metaClass) {
202
- super(runtime, metaClass);
203
- }
204
- }
205
-
206
- @JRubyClass(name = "Object", parent = "JRubyObject")
207
- public static class Object extends JRubyObject {
191
+ @JRubyClass(name = "Object", parent = "AbstractObject")
192
+ public static class Object extends RubyObject {
208
193
 
209
194
  public Object(Ruby runtime, RubyClass metaClass) {
210
195
  super(runtime, metaClass);
@@ -220,7 +205,7 @@ public class SynchronizationLibrary implements Library {
220
205
  }
221
206
 
222
207
  @JRubyClass(name = "JRubyLockableObject", parent = "AbstractLockableObject")
223
- public static class JRubyLockableObject extends JRubyObject {
208
+ public static class JRubyLockableObject extends AbstractLockableObject {
224
209
 
225
210
  public JRubyLockableObject(Ruby runtime, RubyClass metaClass) {
226
211
  super(runtime, metaClass);
@@ -1,9 +1,10 @@
1
1
  require 'concurrent/configuration'
2
2
  require 'concurrent/atomic/atomic_reference'
3
+ require 'concurrent/atomic/count_down_latch'
3
4
  require 'concurrent/atomic/thread_local_var'
4
5
  require 'concurrent/collection/copy_on_write_observer_set'
5
6
  require 'concurrent/concern/observable'
6
- require 'concurrent/synchronization'
7
+ require 'concurrent/synchronization/lockable_object'
7
8
 
8
9
  module Concurrent
9
10
 
@@ -34,16 +34,6 @@ module Concurrent
34
34
  end
35
35
  JRubyArray
36
36
 
37
- when Concurrent.on_rbx?
38
- require 'monitor'
39
- require 'concurrent/thread_safe/util/data_structures'
40
-
41
- class RbxArray < ::Array
42
- end
43
-
44
- ThreadSafe::Util.make_synchronized_on_rbx RbxArray
45
- RbxArray
46
-
47
37
  when Concurrent.on_truffleruby?
48
38
  require 'concurrent/thread_safe/util/data_structures'
49
39
 
@@ -272,6 +272,7 @@ module Concurrent
272
272
  obj.send(:init_synchronization)
273
273
  obj
274
274
  end
275
+ ruby2_keywords :new if respond_to?(:ruby2_keywords, true)
275
276
  end
276
277
  private_constant :ClassMethods
277
278
 
@@ -1,7 +1,7 @@
1
1
  require 'concurrent/atomic/atomic_reference'
2
2
  require 'concurrent/collection/copy_on_notify_observer_set'
3
3
  require 'concurrent/concern/observable'
4
- require 'concurrent/synchronization'
4
+ require 'concurrent/synchronization/object'
5
5
 
6
6
  # @!macro thread_safe_variable_comparison
7
7
  #
@@ -1,5 +1,6 @@
1
+ require 'concurrent/utility/native_extension_loader' # load native parts first
2
+
1
3
  require 'concurrent/atomic/mutex_atomic_boolean'
2
- require 'concurrent/synchronization'
3
4
 
4
5
  module Concurrent
5
6
 
@@ -79,10 +80,10 @@ module Concurrent
79
80
  # @!visibility private
80
81
  # @!macro internal_implementation_note
81
82
  AtomicBooleanImplementation = case
82
- when defined?(JavaAtomicBoolean)
83
- JavaAtomicBoolean
84
- when defined?(CAtomicBoolean)
83
+ when Concurrent.on_cruby? && Concurrent.c_extensions_loaded?
85
84
  CAtomicBoolean
85
+ when Concurrent.on_jruby?
86
+ JavaAtomicBoolean
86
87
  else
87
88
  MutexAtomicBoolean
88
89
  end
@@ -1,5 +1,6 @@
1
+ require 'concurrent/utility/native_extension_loader' # load native parts first
2
+
1
3
  require 'concurrent/atomic/mutex_atomic_fixnum'
2
- require 'concurrent/synchronization'
3
4
 
4
5
  module Concurrent
5
6
 
@@ -96,10 +97,10 @@ module Concurrent
96
97
  # @!visibility private
97
98
  # @!macro internal_implementation_note
98
99
  AtomicFixnumImplementation = case
99
- when defined?(JavaAtomicFixnum)
100
- JavaAtomicFixnum
101
- when defined?(CAtomicFixnum)
100
+ when Concurrent.on_cruby? && Concurrent.c_extensions_loaded?
102
101
  CAtomicFixnum
102
+ when Concurrent.on_jruby?
103
+ JavaAtomicFixnum
103
104
  else
104
105
  MutexAtomicFixnum
105
106
  end
@@ -1,3 +1,6 @@
1
+ require 'concurrent/errors'
2
+ require 'concurrent/synchronization/object'
3
+
1
4
  module Concurrent
2
5
  # An atomic reference which maintains an object reference along with a mark bit
3
6
  # that can be updated atomically.
@@ -1,6 +1,8 @@
1
- require 'concurrent/synchronization'
2
- require 'concurrent/utility/engine'
1
+ require 'concurrent/utility/native_extension_loader' # load native parts first
2
+
3
+ require 'concurrent/atomic_reference/atomic_direct_update'
3
4
  require 'concurrent/atomic_reference/numeric_cas_wrapper'
5
+ require 'concurrent/atomic_reference/mutex_atomic'
4
6
 
5
7
  # Shim for TruffleRuby::AtomicReference
6
8
  if Concurrent.on_truffleruby? && !defined?(TruffleRuby::AtomicReference)
@@ -12,138 +14,6 @@ end
12
14
 
13
15
  module Concurrent
14
16
 
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
17
  # @!macro internal_implementation_note
148
18
  AtomicReferenceImplementation = case
149
19
  when Concurrent.on_cruby? && Concurrent.c_extensions_loaded?
@@ -170,28 +40,89 @@ module Concurrent
170
40
  alias_method :compare_and_swap, :compare_and_set
171
41
  alias_method :swap, :get_and_set
172
42
  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
43
+ TruffleRubyAtomicReference
189
44
  else
190
45
  MutexAtomicReference
191
46
  end
192
47
  private_constant :AtomicReferenceImplementation
193
48
 
194
- # @!macro atomic_reference
49
+ # An object reference that may be updated atomically. All read and write
50
+ # operations have java volatile semantic.
51
+ #
52
+ # @!macro thread_safe_variable_comparison
53
+ #
54
+ # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html
55
+ # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html
56
+ #
57
+ # @!method initialize(value = nil)
58
+ # @!macro atomic_reference_method_initialize
59
+ # @param [Object] value The initial value.
60
+ #
61
+ # @!method get
62
+ # @!macro atomic_reference_method_get
63
+ # Gets the current value.
64
+ # @return [Object] the current value
65
+ #
66
+ # @!method set(new_value)
67
+ # @!macro atomic_reference_method_set
68
+ # Sets to the given value.
69
+ # @param [Object] new_value the new value
70
+ # @return [Object] the new value
71
+ #
72
+ # @!method get_and_set(new_value)
73
+ # @!macro atomic_reference_method_get_and_set
74
+ # Atomically sets to the given value and returns the old value.
75
+ # @param [Object] new_value the new value
76
+ # @return [Object] the old value
77
+ #
78
+ # @!method compare_and_set(old_value, new_value)
79
+ # @!macro atomic_reference_method_compare_and_set
80
+ #
81
+ # Atomically sets the value to the given updated value if
82
+ # the current value == the expected value.
83
+ #
84
+ # @param [Object] old_value the expected value
85
+ # @param [Object] new_value the new value
86
+ #
87
+ # @return [Boolean] `true` if successful. A `false` return indicates
88
+ # that the actual value was not equal to the expected value.
89
+ #
90
+ # @!method update
91
+ # Pass the current value to the given block, replacing it
92
+ # with the block's result. May retry if the value changes
93
+ # during the block's execution.
94
+ #
95
+ # @yield [Object] Calculate a new value for the atomic reference using
96
+ # given (old) value
97
+ # @yieldparam [Object] old_value the starting value of the atomic reference
98
+ # @return [Object] the new value
99
+ #
100
+ # @!method try_update
101
+ # Pass the current value to the given block, replacing it
102
+ # with the block's result. Return nil if the update fails.
103
+ #
104
+ # @yield [Object] Calculate a new value for the atomic reference using
105
+ # given (old) value
106
+ # @yieldparam [Object] old_value the starting value of the atomic reference
107
+ # @note This method was altered to avoid raising an exception by default.
108
+ # Instead, this method now returns `nil` in case of failure. For more info,
109
+ # please see: https://github.com/ruby-concurrency/concurrent-ruby/pull/336
110
+ # @return [Object] the new value, or nil if update failed
111
+ #
112
+ # @!method try_update!
113
+ # Pass the current value to the given block, replacing it
114
+ # with the block's result. Raise an exception if the update
115
+ # fails.
116
+ #
117
+ # @yield [Object] Calculate a new value for the atomic reference using
118
+ # given (old) value
119
+ # @yieldparam [Object] old_value the starting value of the atomic reference
120
+ # @note This behavior mimics the behavior of the original
121
+ # `AtomicReference#try_update` API. The reason this was changed was to
122
+ # avoid raising exceptions (which are inherently slow) by default. For more
123
+ # info: https://github.com/ruby-concurrency/concurrent-ruby/pull/336
124
+ # @return [Object] the new value
125
+ # @raise [Concurrent::ConcurrentUpdateError] if the update fails
195
126
  class AtomicReference < AtomicReferenceImplementation
196
127
 
197
128
  # @return [String] Short string representation.
@@ -1,4 +1,4 @@
1
- require 'concurrent/synchronization'
1
+ require 'concurrent/synchronization/lockable_object'
2
2
  require 'concurrent/utility/native_integer'
3
3
 
4
4
  module Concurrent
@@ -1,5 +1,5 @@
1
1
  require 'thread'
2
- require 'concurrent/synchronization'
2
+ require 'concurrent/synchronization/lockable_object'
3
3
 
4
4
  module Concurrent
5
5
 
@@ -19,7 +19,7 @@ module Concurrent
19
19
  # t1 = Thread.new do
20
20
  # puts "t1 is waiting"
21
21
  # event.wait(1)
22
- # puts "event ocurred"
22
+ # puts "event occurred"
23
23
  # end
24
24
  #
25
25
  # t2 = Thread.new do
@@ -30,8 +30,8 @@ module Concurrent
30
30
  # [t1, t2].each(&:join)
31
31
  #
32
32
  # # prints:
33
- # # t2 calling set
34
33
  # # t1 is waiting
34
+ # # t2 calling set
35
35
  # # event occurred
36
36
  class Event < Synchronization::LockableObject
37
37
 
@@ -0,0 +1,109 @@
1
+ require 'concurrent/constants'
2
+ require_relative 'locals'
3
+
4
+ module Concurrent
5
+
6
+ # A `FiberLocalVar` is a variable where the value is different for each fiber.
7
+ # Each variable may have a default value, but when you modify the variable only
8
+ # the current fiber will ever see that change.
9
+ #
10
+ # This is similar to Ruby's built-in fiber-local variables (`Thread.current[:name]`),
11
+ # but with these major advantages:
12
+ # * `FiberLocalVar` has its own identity, it doesn't need a Symbol.
13
+ # * Each Ruby's built-in fiber-local variable leaks some memory forever (it's a Symbol held forever on the fiber),
14
+ # so it's only OK to create a small amount of them.
15
+ # `FiberLocalVar` has no such issue and it is fine to create many of them.
16
+ # * Ruby's built-in fiber-local variables leak forever the value set on each fiber (unless set to nil explicitly).
17
+ # `FiberLocalVar` automatically removes the mapping for each fiber once the `FiberLocalVar` instance is GC'd.
18
+ #
19
+ # @example
20
+ # v = FiberLocalVar.new(14)
21
+ # v.value #=> 14
22
+ # v.value = 2
23
+ # v.value #=> 2
24
+ #
25
+ # @example
26
+ # v = FiberLocalVar.new(14)
27
+ #
28
+ # Fiber.new do
29
+ # v.value #=> 14
30
+ # v.value = 1
31
+ # v.value #=> 1
32
+ # end.resume
33
+ #
34
+ # Fiber.new do
35
+ # v.value #=> 14
36
+ # v.value = 2
37
+ # v.value #=> 2
38
+ # end.resume
39
+ #
40
+ # v.value #=> 14
41
+ class FiberLocalVar
42
+ LOCALS = FiberLocals.new
43
+
44
+ # Creates a fiber local variable.
45
+ #
46
+ # @param [Object] default the default value when otherwise unset
47
+ # @param [Proc] default_block Optional block that gets called to obtain the
48
+ # default value for each fiber
49
+ def initialize(default = nil, &default_block)
50
+ if default && block_given?
51
+ raise ArgumentError, "Cannot use both value and block as default value"
52
+ end
53
+
54
+ if block_given?
55
+ @default_block = default_block
56
+ @default = nil
57
+ else
58
+ @default_block = nil
59
+ @default = default
60
+ end
61
+
62
+ @index = LOCALS.next_index(self)
63
+ end
64
+
65
+ # Returns the value in the current fiber's copy of this fiber-local variable.
66
+ #
67
+ # @return [Object] the current value
68
+ def value
69
+ LOCALS.fetch(@index) { default }
70
+ end
71
+
72
+ # Sets the current fiber's copy of this fiber-local variable to the specified value.
73
+ #
74
+ # @param [Object] value the value to set
75
+ # @return [Object] the new value
76
+ def value=(value)
77
+ LOCALS.set(@index, value)
78
+ end
79
+
80
+ # Bind the given value to fiber local storage during
81
+ # execution of the given block.
82
+ #
83
+ # @param [Object] value the value to bind
84
+ # @yield the operation to be performed with the bound variable
85
+ # @return [Object] the value
86
+ def bind(value)
87
+ if block_given?
88
+ old_value = self.value
89
+ self.value = value
90
+ begin
91
+ yield
92
+ ensure
93
+ self.value = old_value
94
+ end
95
+ end
96
+ end
97
+
98
+ protected
99
+
100
+ # @!visibility private
101
+ def default
102
+ if @default_block
103
+ self.value = @default_block.call
104
+ else
105
+ @default
106
+ end
107
+ end
108
+ end
109
+ end
@@ -1,4 +1,5 @@
1
1
  if Concurrent.on_jruby?
2
+ require 'concurrent/utility/native_extension_loader'
2
3
 
3
4
  module Concurrent
4
5