concurrent-ruby 0.8.0 → 0.9.0.pre2

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 (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -2
  3. data/README.md +103 -54
  4. data/lib/concurrent.rb +34 -14
  5. data/lib/concurrent/async.rb +164 -50
  6. data/lib/concurrent/atom.rb +171 -0
  7. data/lib/concurrent/atomic/atomic_boolean.rb +57 -107
  8. data/lib/concurrent/atomic/atomic_fixnum.rb +73 -101
  9. data/lib/concurrent/atomic/atomic_reference.rb +49 -0
  10. data/lib/concurrent/atomic/condition.rb +23 -12
  11. data/lib/concurrent/atomic/count_down_latch.rb +23 -21
  12. data/lib/concurrent/atomic/cyclic_barrier.rb +47 -47
  13. data/lib/concurrent/atomic/event.rb +33 -42
  14. data/lib/concurrent/atomic/read_write_lock.rb +252 -0
  15. data/lib/concurrent/atomic/semaphore.rb +64 -89
  16. data/lib/concurrent/atomic/thread_local_var.rb +130 -58
  17. data/lib/concurrent/atomic/thread_local_var/weak_key_map.rb +236 -0
  18. data/lib/concurrent/atomic_reference/direct_update.rb +3 -0
  19. data/lib/concurrent/atomic_reference/jruby.rb +6 -3
  20. data/lib/concurrent/atomic_reference/mutex_atomic.rb +10 -32
  21. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +3 -0
  22. data/lib/concurrent/atomic_reference/rbx.rb +4 -1
  23. data/lib/concurrent/atomic_reference/ruby.rb +6 -3
  24. data/lib/concurrent/atomics.rb +74 -4
  25. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +115 -0
  26. data/lib/concurrent/collection/copy_on_write_observer_set.rb +119 -0
  27. data/lib/concurrent/collection/priority_queue.rb +300 -245
  28. data/lib/concurrent/concern/deprecation.rb +27 -0
  29. data/lib/concurrent/concern/dereferenceable.rb +88 -0
  30. data/lib/concurrent/concern/logging.rb +25 -0
  31. data/lib/concurrent/concern/obligation.rb +228 -0
  32. data/lib/concurrent/concern/observable.rb +85 -0
  33. data/lib/concurrent/configuration.rb +226 -112
  34. data/lib/concurrent/dataflow.rb +2 -3
  35. data/lib/concurrent/delay.rb +141 -50
  36. data/lib/concurrent/edge.rb +30 -0
  37. data/lib/concurrent/errors.rb +10 -0
  38. data/lib/concurrent/exchanger.rb +25 -1
  39. data/lib/concurrent/executor/cached_thread_pool.rb +46 -33
  40. data/lib/concurrent/executor/executor.rb +46 -299
  41. data/lib/concurrent/executor/executor_service.rb +521 -0
  42. data/lib/concurrent/executor/fixed_thread_pool.rb +206 -26
  43. data/lib/concurrent/executor/immediate_executor.rb +9 -9
  44. data/lib/concurrent/executor/indirect_immediate_executor.rb +4 -3
  45. data/lib/concurrent/executor/java_cached_thread_pool.rb +18 -16
  46. data/lib/concurrent/executor/java_fixed_thread_pool.rb +11 -18
  47. data/lib/concurrent/executor/java_single_thread_executor.rb +17 -16
  48. data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
  49. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +9 -18
  50. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +10 -21
  51. data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
  52. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
  53. data/lib/concurrent/executor/safe_task_executor.rb +5 -4
  54. data/lib/concurrent/executor/serialized_execution.rb +22 -18
  55. data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
  56. data/lib/concurrent/executor/single_thread_executor.rb +32 -21
  57. data/lib/concurrent/executor/thread_pool_executor.rb +72 -60
  58. data/lib/concurrent/executor/timer_set.rb +96 -84
  59. data/lib/concurrent/executors.rb +1 -1
  60. data/lib/concurrent/future.rb +70 -38
  61. data/lib/concurrent/immutable_struct.rb +89 -0
  62. data/lib/concurrent/ivar.rb +152 -60
  63. data/lib/concurrent/lazy_register.rb +40 -20
  64. data/lib/concurrent/maybe.rb +226 -0
  65. data/lib/concurrent/mutable_struct.rb +227 -0
  66. data/lib/concurrent/mvar.rb +44 -43
  67. data/lib/concurrent/promise.rb +208 -134
  68. data/lib/concurrent/scheduled_task.rb +339 -43
  69. data/lib/concurrent/settable_struct.rb +127 -0
  70. data/lib/concurrent/synchronization.rb +17 -0
  71. data/lib/concurrent/synchronization/abstract_object.rb +163 -0
  72. data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
  73. data/lib/concurrent/synchronization/condition.rb +53 -0
  74. data/lib/concurrent/synchronization/java_object.rb +35 -0
  75. data/lib/concurrent/synchronization/lock.rb +32 -0
  76. data/lib/concurrent/synchronization/monitor_object.rb +24 -0
  77. data/lib/concurrent/synchronization/mutex_object.rb +43 -0
  78. data/lib/concurrent/synchronization/object.rb +78 -0
  79. data/lib/concurrent/synchronization/rbx_object.rb +75 -0
  80. data/lib/concurrent/timer_task.rb +87 -100
  81. data/lib/concurrent/tvar.rb +42 -38
  82. data/lib/concurrent/utilities.rb +3 -1
  83. data/lib/concurrent/utility/at_exit.rb +97 -0
  84. data/lib/concurrent/utility/engine.rb +40 -0
  85. data/lib/concurrent/utility/monotonic_time.rb +59 -0
  86. data/lib/concurrent/utility/native_extension_loader.rb +56 -0
  87. data/lib/concurrent/utility/processor_counter.rb +156 -0
  88. data/lib/concurrent/utility/timeout.rb +18 -14
  89. data/lib/concurrent/utility/timer.rb +11 -6
  90. data/lib/concurrent/version.rb +2 -1
  91. data/lib/concurrent_ruby.rb +1 -0
  92. metadata +47 -83
  93. data/lib/concurrent/actor.rb +0 -103
  94. data/lib/concurrent/actor/behaviour.rb +0 -70
  95. data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
  96. data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
  97. data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
  98. data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
  99. data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
  100. data/lib/concurrent/actor/behaviour/linking.rb +0 -45
  101. data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
  102. data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
  103. data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
  104. data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
  105. data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
  106. data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
  107. data/lib/concurrent/actor/behaviour/termination.rb +0 -54
  108. data/lib/concurrent/actor/context.rb +0 -154
  109. data/lib/concurrent/actor/core.rb +0 -217
  110. data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
  111. data/lib/concurrent/actor/envelope.rb +0 -41
  112. data/lib/concurrent/actor/errors.rb +0 -27
  113. data/lib/concurrent/actor/internal_delegations.rb +0 -49
  114. data/lib/concurrent/actor/public_delegations.rb +0 -40
  115. data/lib/concurrent/actor/reference.rb +0 -81
  116. data/lib/concurrent/actor/root.rb +0 -37
  117. data/lib/concurrent/actor/type_check.rb +0 -48
  118. data/lib/concurrent/actor/utils.rb +0 -10
  119. data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
  120. data/lib/concurrent/actor/utils/balancer.rb +0 -42
  121. data/lib/concurrent/actor/utils/broadcast.rb +0 -52
  122. data/lib/concurrent/actor/utils/pool.rb +0 -59
  123. data/lib/concurrent/actress.rb +0 -3
  124. data/lib/concurrent/agent.rb +0 -209
  125. data/lib/concurrent/atomic.rb +0 -92
  126. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
  127. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
  128. data/lib/concurrent/atomic/synchronization.rb +0 -51
  129. data/lib/concurrent/channel/buffered_channel.rb +0 -85
  130. data/lib/concurrent/channel/channel.rb +0 -41
  131. data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
  132. data/lib/concurrent/channel/waitable_list.rb +0 -40
  133. data/lib/concurrent/channels.rb +0 -5
  134. data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
  135. data/lib/concurrent/collection/ring_buffer.rb +0 -59
  136. data/lib/concurrent/collections.rb +0 -3
  137. data/lib/concurrent/dereferenceable.rb +0 -108
  138. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
  139. data/lib/concurrent/logging.rb +0 -20
  140. data/lib/concurrent/obligation.rb +0 -171
  141. data/lib/concurrent/observable.rb +0 -73
  142. data/lib/concurrent/options_parser.rb +0 -52
  143. data/lib/concurrent/utility/processor_count.rb +0 -152
  144. data/lib/extension_helper.rb +0 -37
@@ -0,0 +1,171 @@
1
+ require 'concurrent/concern/dereferenceable'
2
+ require 'concurrent/atomic/atomic_reference'
3
+ require 'concurrent/synchronization/object'
4
+
5
+ module Concurrent
6
+
7
+ # Atoms provide a way to manage shared, synchronous, independent state.
8
+ #
9
+ # An atom is initialized with an initial value and an optional validation
10
+ # proc. At any time the value of the atom can be synchronously and safely
11
+ # changed. If a validator is given at construction then any new value
12
+ # will be checked against the validator and will be rejected if the
13
+ # validator returns false or raises an exception.
14
+ #
15
+ # There are two ways to change the value of an atom: {#compare_and_set} and
16
+ # {#swap}. The former will set the new value if and only if it validates and
17
+ # the current value matches the new value. The latter will atomically set the
18
+ # new value to the result of running the given block if and only if that
19
+ # value validates.
20
+ #
21
+ # @!macro [attach] copy_options
22
+ # ## Copy Options
23
+ #
24
+ # Object references in Ruby are mutable. This can lead to serious
25
+ # problems when the {#value} of an object is a mutable reference. Which
26
+ # is always the case unless the value is a `Fixnum`, `Symbol`, or similar
27
+ # "primative" data type. Each instance can be configured with a few
28
+ # options that can help protect the program from potentially dangerous
29
+ # operations. Each of these options can be optionally set when the oject
30
+ # instance is created:
31
+ #
32
+ # * `:dup_on_deref` When true the object will call the `#dup` method on
33
+ # the `value` object every time the `#value` methid is called
34
+ # (default: false)
35
+ # * `:freeze_on_deref` When true the object will call the `#freeze`
36
+ # method on the `value` object every time the `#value` method is called
37
+ # (default: false)
38
+ # * `:copy_on_deref` When given a `Proc` object the `Proc` will be run
39
+ # every time the `#value` method is called. The `Proc` will be given
40
+ # the current `value` as its only argument and the result returned by
41
+ # the block will be the return value of the `#value` call. When `nil`
42
+ # this option will be ignored (default: nil)
43
+ #
44
+ # When multiple deref options are set the order of operations is strictly defined.
45
+ # The order of deref operations is:
46
+ # * `:copy_on_deref`
47
+ # * `:dup_on_deref`
48
+ # * `:freeze_on_deref`
49
+ #
50
+ # Because of this ordering there is no need to `#freeze` an object created by a
51
+ # provided `:copy_on_deref` block. Simply set `:freeze_on_deref` to `true`.
52
+ # Setting both `:dup_on_deref` to `true` and `:freeze_on_deref` to `true` is
53
+ # as close to the behavior of a "pure" functional language (like Erlang, Clojure,
54
+ # or Haskell) as we are likely to get in Ruby.
55
+ #
56
+ # @see http://clojure.org/atoms Clojure Atoms
57
+ class Atom < Synchronization::Object
58
+ include Concern::Dereferenceable
59
+
60
+ # Create a new atom with the given initial value.
61
+ #
62
+ # @param [Object] value The initial value
63
+ # @param [Hash] opts The options used to configure the atom
64
+ # @option opts [Proc] :validator (nil) Optional proc used to validate new
65
+ # values. It must accept one and only one argument which will be the
66
+ # intended new value. The validator will return true if the new value
67
+ # is acceptable else return false (preferrably) or raise an exception.
68
+ #
69
+ # @!macro [attach] deref_options
70
+ # @option opts [Boolean] :dup_on_deref (false) Call `#dup` before
71
+ # returning the data from {#value}
72
+ # @option opts [Boolean] :freeze_on_deref (false) Call `#freeze` before
73
+ # returning the data from {#value}
74
+ # @option opts [Proc] :copy_on_deref (nil) When calling the {#value}
75
+ # method, call the given proc passing the internal value as the sole
76
+ # argument then return the new value returned from the proc.
77
+ #
78
+ # @raise [ArgumentError] if the validator is not a `Proc` (when given)
79
+ def initialize(value, opts = {})
80
+ super()
81
+
82
+ @validator = opts.fetch(:validator, ->(v){ true })
83
+ raise ArgumentError.new('validator must be a proc') unless @validator.is_a? Proc
84
+
85
+ @value = Concurrent::AtomicReference.new(value)
86
+ ns_set_deref_options(opts)
87
+ ensure_ivar_visibility!
88
+ end
89
+
90
+ # The current value of the atom.
91
+ #
92
+ # @return [Object] The current value.
93
+ def value
94
+ apply_deref_options(@value.value)
95
+ end
96
+ alias_method :deref, :value
97
+
98
+ # Atomically swaps the value of atom using the given block. The current
99
+ # value will be passed to the block, as will any arguments passed as
100
+ # arguments to the function. The new value will be validated against the
101
+ # (optional) validator proc given at construction. If validation fails the
102
+ # value will not be changed.
103
+ #
104
+ # Internally, {#swap} reads the current value, applies the block to it, and
105
+ # attempts to compare-and-set it in. Since another thread may have changed
106
+ # the value in the intervening time, it may have to retry, and does so in a
107
+ # spin loop. The net effect is that the value will always be the result of
108
+ # the application of the supplied block to a current value, atomically.
109
+ # However, because the block might be called multiple times, it must be free
110
+ # of side effects.
111
+ #
112
+ # @note The given block may be called multiple times, and thus should be free
113
+ # of side effects.
114
+ #
115
+ # @param [Object] args Zero or more arguments passed to the block.
116
+ #
117
+ # @yield [value, args] Calculates a new value for the atom based on the
118
+ # current value and any supplied agruments.
119
+ # @yieldparam value [Object] The current value of the atom.
120
+ # @yieldparam args [Object] All arguments passed to the function, in order.
121
+ # @yieldreturn [Object] The intended new value of the atom.
122
+ #
123
+ # @return [Object] The final value of the atom after all operations and
124
+ # validations are complete.
125
+ #
126
+ # @raise [ArgumentError] When no block is given.
127
+ def swap(*args)
128
+ raise ArgumentError.new('no block given') unless block_given?
129
+
130
+ begin
131
+ loop do
132
+ old_value = @value.value
133
+ new_value = yield(old_value, *args)
134
+ return old_value unless @validator.call(new_value)
135
+ return new_value if compare_and_set!(old_value, new_value)
136
+ end
137
+ rescue
138
+ return @value.value
139
+ end
140
+ end
141
+
142
+ # @!macro [attach] atom_compare_and_set
143
+ # Atomically sets the value of atom to the new value if and only if the
144
+ # current value of the atom is identical to the old value and the new
145
+ # value successfully validates against the (optional) validator given
146
+ # at construction.
147
+ #
148
+ # @param [Object] old_value The expected current value.
149
+ # @param [Object] new_value The intended new value.
150
+ #
151
+ # @return [Boolean] True if the value is changed else false.
152
+ def compare_and_set(old_value, new_value)
153
+ compare_and_set!(old_value, new_value)
154
+ rescue
155
+ false
156
+ end
157
+
158
+ private
159
+
160
+ # @!macro atom_compare_and_set
161
+ # @raise [Exception] if the validator proc raises an exception
162
+ # @!visibility private
163
+ def compare_and_set!(old_value, new_value)
164
+ if @validator.call(new_value) # may raise exception
165
+ @value.compare_and_set(old_value, new_value)
166
+ else
167
+ false
168
+ end
169
+ end
170
+ end
171
+ end
@@ -1,4 +1,5 @@
1
- require_relative '../../extension_helper'
1
+ require 'concurrent/utility/native_extension_loader'
2
+ require 'concurrent/synchronization'
2
3
 
3
4
  module Concurrent
4
5
 
@@ -21,7 +22,11 @@ module Concurrent
21
22
  # 3.340000 0.010000 3.350000 ( 0.855000)
22
23
  #
23
24
  # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicBoolean.html java.util.concurrent.atomic.AtomicBoolean
24
- class MutexAtomicBoolean
25
+ #
26
+ # @!visibility private
27
+ #
28
+ # @!macro internal_implementation_note
29
+ class MutexAtomicBoolean < Synchronization::Object
25
30
 
26
31
  # @!macro [attach] atomic_boolean_method_initialize
27
32
  #
@@ -29,8 +34,8 @@ module Concurrent
29
34
  #
30
35
  # @param [Boolean] initial the initial value
31
36
  def initialize(initial = false)
32
- @value = !!initial
33
- @mutex = Mutex.new
37
+ super()
38
+ synchronize { ns_initialize(initial) }
34
39
  end
35
40
 
36
41
  # @!macro [attach] atomic_boolean_method_value_get
@@ -39,10 +44,7 @@ module Concurrent
39
44
  #
40
45
  # @return [Boolean] the current value
41
46
  def value
42
- @mutex.lock
43
- @value
44
- ensure
45
- @mutex.unlock
47
+ synchronize { @value }
46
48
  end
47
49
 
48
50
  # @!macro [attach] atomic_boolean_method_value_set
@@ -53,11 +55,7 @@ module Concurrent
53
55
  #
54
56
  # @return [Boolean] the current value
55
57
  def value=(value)
56
- @mutex.lock
57
- @value = !!value
58
- @value
59
- ensure
60
- @mutex.unlock
58
+ synchronize { @value = !!value }
61
59
  end
62
60
 
63
61
  # @!macro [attach] atomic_boolean_method_true_question
@@ -66,22 +64,16 @@ module Concurrent
66
64
  #
67
65
  # @return [Boolean] true if the current value is `true`, else false
68
66
  def true?
69
- @mutex.lock
70
- @value
71
- ensure
72
- @mutex.unlock
67
+ synchronize { @value }
73
68
  end
74
69
 
75
- # @!macro atomic_boolean_method_false_question
70
+ # @!macro [attach] atomic_boolean_method_false_question
76
71
  #
77
72
  # Is the current value `false`
78
73
  #
79
74
  # @return [Boolean] true if the current value is `false`, else false
80
75
  def false?
81
- @mutex.lock
82
- !@value
83
- ensure
84
- @mutex.unlock
76
+ synchronize { !@value }
85
77
  end
86
78
 
87
79
  # @!macro [attach] atomic_boolean_method_make_true
@@ -90,12 +82,7 @@ module Concurrent
90
82
  #
91
83
  # @return [Boolean] true is value has changed, otherwise false
92
84
  def make_true
93
- @mutex.lock
94
- old = @value
95
- @value = true
96
- !old
97
- ensure
98
- @mutex.unlock
85
+ synchronize { ns_make_value(true) }
99
86
  end
100
87
 
101
88
  # @!macro [attach] atomic_boolean_method_make_false
@@ -104,98 +91,61 @@ module Concurrent
104
91
  #
105
92
  # @return [Boolean] true is value has changed, otherwise false
106
93
  def make_false
107
- @mutex.lock
108
- old = @value
109
- @value = false
110
- old
111
- ensure
112
- @mutex.unlock
94
+ synchronize { ns_make_value(false) }
113
95
  end
114
- end
115
96
 
116
- if RUBY_PLATFORM == 'java'
117
-
118
- # @!macro atomic_boolean
119
- class JavaAtomicBoolean
120
-
121
- # @!macro atomic_boolean_method_initialize
122
- #
123
- def initialize(initial = false)
124
- @atomic = java.util.concurrent.atomic.AtomicBoolean.new(!!initial)
125
- end
126
-
127
- # @!macro atomic_boolean_method_value_get
128
- #
129
- def value
130
- @atomic.get
131
- end
132
-
133
- # @!macro atomic_boolean_method_value_set
134
- #
135
- def value=(value)
136
- @atomic.set(!!value)
137
- end
138
-
139
- # @!macro atomic_boolean_method_true_question
140
- def true?
141
- @atomic.get
142
- end
143
-
144
- # @!macro atomic_boolean_method_false_question
145
- def false?
146
- !@atomic.get
147
- end
148
-
149
- # @!macro atomic_boolean_method_make_true
150
- def make_true
151
- @atomic.compareAndSet(false, true)
152
- end
153
-
154
- # @!macro atomic_boolean_method_make_false
155
- def make_false
156
- @atomic.compareAndSet(true, false)
157
- end
158
- end
97
+ protected
159
98
 
160
- # @!macro atomic_boolean
161
- class AtomicBoolean < JavaAtomicBoolean
99
+ # @!visibility private
100
+ def ns_initialize(initial)
101
+ @value = !!initial
162
102
  end
163
103
 
164
- elsif defined?(CAtomicBoolean)
165
-
166
- # @!macro atomic_boolean
167
- class CAtomicBoolean
168
-
169
- # @!method initialize
170
- # @!macro atomic_boolean_method_initialize
104
+ # @!visibility private
105
+ def ns_make_value(value)
106
+ old = @value
107
+ @value = value
108
+ old != @value
109
+ end
110
+ end
171
111
 
172
- # @!method value
173
- # @!macro atomic_boolean_method_value_get
112
+ # @!visibility private
113
+ # @!macro internal_implementation_note
114
+ AtomicBooleanImplementation = case
115
+ when Concurrent.on_jruby?
116
+ JavaAtomicBoolean
117
+ when defined?(CAtomicBoolean)
118
+ CAtomicBoolean
119
+ else
120
+ MutexAtomicBoolean
121
+ end
122
+ private_constant :AtomicBooleanImplementation
123
+
124
+ # @!macro atomic_boolean
125
+ #
126
+ # @see Concurrent::MutexAtomicBoolean
127
+ class AtomicBoolean < AtomicBooleanImplementation
174
128
 
175
- # @!method value=
176
- # @!macro atomic_boolean_method_value_set
129
+ # @!method initialize(initial = false)
130
+ # @!macro atomic_boolean_method_initialize
177
131
 
178
- # @!method true?
179
- # @!macro atomic_boolean_method_true_question
132
+ # @!method value
133
+ # @!macro atomic_boolean_method_value_get
180
134
 
181
- # @!method false?
182
- # @!macro atomic_boolean_method_false_question
135
+ # @!method value=(value)
136
+ # @!macro atomic_boolean_method_value_set
183
137
 
184
- # @!method make_true
185
- # @!macro atomic_boolean_method_make_true
138
+ # @!method true?
139
+ # @!macro atomic_boolean_method_true_question
186
140
 
187
- # @!method make_false
188
- # @!macro atomic_boolean_method_make_false
189
- end
141
+ # @!method false?
142
+ # @!macro atomic_boolean_method_false_question
190
143
 
191
- # @!macro atomic_boolean
192
- class AtomicBoolean < CAtomicBoolean
193
- end
144
+ # @!method make_true
145
+ # @!macro atomic_boolean_method_make_true
194
146
 
195
- else
147
+ # @!method make_false
148
+ # @!macro atomic_boolean_method_make_false
196
149
 
197
- # @!macro atomic_boolean
198
- class AtomicBoolean < MutexAtomicBoolean
199
- end
200
150
  end
201
151
  end
@@ -1,4 +1,5 @@
1
- require_relative '../../extension_helper'
1
+ require 'concurrent/utility/native_extension_loader'
2
+ require 'concurrent/synchronization'
2
3
 
3
4
  module Concurrent
4
5
 
@@ -21,7 +22,10 @@ module Concurrent
21
22
  # 4.520000 0.030000 4.550000 ( 1.187000)
22
23
  #
23
24
  # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicLong.html java.util.concurrent.atomic.AtomicLong
24
- class MutexAtomicFixnum
25
+ #
26
+ # @!visibility private
27
+ # @!macro internal_implementation_note
28
+ class MutexAtomicFixnum < Synchronization::Object
25
29
 
26
30
  # http://stackoverflow.com/questions/535721/ruby-max-integer
27
31
  MIN_VALUE = -(2**(0.size * 8 - 2))
@@ -31,12 +35,11 @@ module Concurrent
31
35
  #
32
36
  # Creates a new `AtomicFixnum` with the given initial value.
33
37
  #
34
- # @param [Fixnum] init the initial value
38
+ # @param [Fixnum] initial the initial value
35
39
  # @raise [ArgumentError] if the initial value is not a `Fixnum`
36
- def initialize(init = 0)
37
- raise ArgumentError.new('initial value must be a Fixnum') unless init.is_a?(Fixnum)
38
- @value = init
39
- @mutex = Mutex.new
40
+ def initialize(initial = 0)
41
+ super()
42
+ synchronize { ns_initialize(initial) }
40
43
  end
41
44
 
42
45
  # @!macro [attach] atomic_fixnum_method_value_get
@@ -45,10 +48,7 @@ module Concurrent
45
48
  #
46
49
  # @return [Fixnum] the current value
47
50
  def value
48
- @mutex.lock
49
- @value
50
- ensure
51
- @mutex.unlock
51
+ synchronize { @value }
52
52
  end
53
53
 
54
54
  # @!macro [attach] atomic_fixnum_method_value_set
@@ -61,11 +61,7 @@ module Concurrent
61
61
  #
62
62
  # @raise [ArgumentError] if the new value is not a `Fixnum`
63
63
  def value=(value)
64
- raise ArgumentError.new('value must be a Fixnum') unless value.is_a?(Fixnum)
65
- @mutex.lock
66
- @value = value
67
- ensure
68
- @mutex.unlock
64
+ synchronize { ns_set(value) }
69
65
  end
70
66
 
71
67
  # @!macro [attach] atomic_fixnum_method_increment
@@ -74,10 +70,7 @@ module Concurrent
74
70
  #
75
71
  # @return [Fixnum] the current value after incrementation
76
72
  def increment
77
- @mutex.lock
78
- @value += 1
79
- ensure
80
- @mutex.unlock
73
+ synchronize { ns_set(@value + 1) }
81
74
  end
82
75
 
83
76
  alias_method :up, :increment
@@ -88,115 +81,94 @@ module Concurrent
88
81
  #
89
82
  # @return [Fixnum] the current value after decrementation
90
83
  def decrement
91
- @mutex.lock
92
- @value -= 1
93
- ensure
94
- @mutex.unlock
84
+ synchronize { ns_set(@value -1) }
95
85
  end
96
86
 
97
87
  alias_method :down, :decrement
98
88
 
99
89
  # @!macro [attach] atomic_fixnum_method_compare_and_set
100
- #
90
+ #
101
91
  # Atomically sets the value to the given updated value if the current
102
92
  # value == the expected value.
103
93
  #
104
94
  # @param [Fixnum] expect the expected value
105
95
  # @param [Fixnum] update the new value
106
96
  #
107
- # @return [Boolean] true if the value was updated else false
97
+ # @return [Fixnum] true if the value was updated else false
108
98
  def compare_and_set(expect, update)
109
- @mutex.lock
110
- if @value == expect
111
- @value = update
112
- true
113
- else
114
- false
99
+ synchronize do
100
+ if @value == expect
101
+ @value = update
102
+ true
103
+ else
104
+ false
105
+ end
115
106
  end
116
- ensure
117
- @mutex.unlock
118
107
  end
119
- end
120
-
121
- if RUBY_PLATFORM == 'java'
122
-
123
- # @!macro atomic_fixnum
124
- class JavaAtomicFixnum
125
108
 
126
- MIN_VALUE = Java::JavaLang::Long::MIN_VALUE
127
- MAX_VALUE = Java::JavaLang::Long::MAX_VALUE
109
+ protected
128
110
 
129
- # @!macro atomic_fixnum_method_initialize
130
- def initialize(init = 0)
131
- raise ArgumentError.new('initial value must be a Fixnum') unless init.is_a?(Fixnum)
132
- @atomic = java.util.concurrent.atomic.AtomicLong.new(init)
133
- end
134
-
135
- # @!macro atomic_fixnum_method_value_get
136
- def value
137
- @atomic.get
138
- end
139
-
140
- # @!macro atomic_fixnum_method_value_set
141
- def value=(value)
142
- raise ArgumentError.new('value must be a Fixnum') unless value.is_a?(Fixnum)
143
- @atomic.set(value)
144
- end
145
-
146
- # @!macro atomic_fixnum_method_increment
147
- def increment
148
- @atomic.increment_and_get
149
- end
150
- alias_method :up, :increment
111
+ # @!visibility private
112
+ def ns_initialize(initial)
113
+ ns_set(initial)
114
+ end
151
115
 
152
- # @!macro atomic_fixnum_method_decrement
153
- def decrement
154
- @atomic.decrement_and_get
155
- end
156
- alias_method :down, :decrement
116
+ private
157
117
 
158
- # @!macro atomic_fixnum_method_compare_and_set
159
- def compare_and_set(expect, update)
160
- @atomic.compare_and_set(expect, update)
161
- end
118
+ # @!visibility private
119
+ def ns_set(value)
120
+ range_check!(value)
121
+ @value = value
162
122
  end
163
123
 
164
- # @!macro atomic_fixnum
165
- class AtomicFixnum < JavaAtomicFixnum
124
+ # @!visibility private
125
+ def range_check!(value)
126
+ if !value.is_a?(Fixnum)
127
+ raise ArgumentError.new('value value must be a Fixnum')
128
+ elsif value > MAX_VALUE
129
+ raise RangeError.new("#{value} is greater than the maximum value of #{MAX_VALUE}")
130
+ elsif value < MIN_VALUE
131
+ raise RangeError.new("#{value} is less than the maximum value of #{MIN_VALUE}")
132
+ else
133
+ value
134
+ end
166
135
  end
136
+ end
167
137
 
168
- elsif defined?(CAtomicFixnum)
169
-
170
- # @!macro atomic_fixnum
171
- class CAtomicFixnum
138
+ # @!visibility private
139
+ # @!macro internal_implementation_note
140
+ AtomicFixnumImplementation = case
141
+ when Concurrent.on_jruby?
142
+ JavaAtomicFixnum
143
+ when defined?(CAtomicFixnum)
144
+ CAtomicFixnum
145
+ else
146
+ MutexAtomicFixnum
147
+ end
148
+ private_constant :AtomicFixnumImplementation
149
+
150
+ # @!macro atomic_fixnum
151
+ #
152
+ # @see Concurrent::MutexAtomicFixnum
153
+ class AtomicFixnum < AtomicFixnumImplementation
172
154
 
173
- # @!method initialize
174
- # @!macro atomic_fixnum_method_initialize
155
+ # @!method initialize(initial = 0)
156
+ # @!macro atomic_fixnum_method_initialize
175
157
 
176
- # @!method value
177
- # @!macro atomic_fixnum_method_value_get
158
+ # @!method value
159
+ # @!macro atomic_fixnum_method_value_get
178
160
 
179
- # @!method value=
180
- # @!macro atomic_fixnum_method_value_set
161
+ # @!method value=(value)
162
+ # @!macro atomic_fixnum_method_value_set
181
163
 
182
- # @!method increment
183
- # @!macro atomic_fixnum_method_increment
164
+ # @!method increment
165
+ # @!macro atomic_fixnum_method_increment
184
166
 
185
- # @!method decrement
186
- # @!macro atomic_fixnum_method_decrement
167
+ # @!method decrement
168
+ # @!macro atomic_fixnum_method_decrement
187
169
 
188
- # @!method compare_and_set
189
- # @!macro atomic_fixnum_method_compare_and_set
190
- end
170
+ # @!method compare_and_set(expect, update)
171
+ # @!macro atomic_fixnum_method_compare_and_set
191
172
 
192
- # @!macro atomic_fixnum
193
- class AtomicFixnum < CAtomicFixnum
194
- end
195
-
196
- else
197
-
198
- # @!macro atomic_fixnum
199
- class AtomicFixnum < MutexAtomicFixnum
200
- end
201
173
  end
202
174
  end