concurrent-ruby 1.1.5 → 1.2.2

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 (151) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +84 -1
  3. data/Gemfile +5 -10
  4. data/{LICENSE.md → LICENSE.txt} +18 -20
  5. data/README.md +55 -31
  6. data/Rakefile +84 -92
  7. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +0 -0
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +52 -22
  9. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +10 -25
  10. data/lib/{concurrent → concurrent-ruby/concurrent}/agent.rb +2 -1
  11. data/lib/{concurrent → concurrent-ruby/concurrent}/array.rb +6 -16
  12. data/lib/{concurrent → concurrent-ruby/concurrent}/async.rb +10 -20
  13. data/lib/{concurrent → concurrent-ruby/concurrent}/atom.rb +2 -2
  14. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_boolean.rb +7 -6
  15. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_fixnum.rb +5 -4
  16. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_markable_reference.rb +3 -0
  17. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +135 -0
  18. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/cyclic_barrier.rb +1 -1
  19. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/event.rb +3 -3
  20. data/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb +109 -0
  21. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_count_down_latch.rb +1 -0
  22. data/lib/concurrent-ruby/concurrent/atomic/locals.rb +189 -0
  23. data/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb +28 -0
  24. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_boolean.rb +11 -5
  25. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_fixnum.rb +11 -5
  26. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_count_down_latch.rb +1 -1
  27. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_semaphore.rb +19 -3
  28. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/read_write_lock.rb +2 -1
  29. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/reentrant_read_write_lock.rb +9 -9
  30. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/semaphore.rb +32 -14
  31. data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +111 -0
  32. data/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb +37 -0
  33. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/mutex_atomic.rb +15 -4
  34. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_notify_observer_set.rb +1 -1
  35. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_write_observer_set.rb +1 -1
  36. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/lock_free_stack.rb +2 -0
  37. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/mri_map_backend.rb +3 -3
  38. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/non_concurrent_map_backend.rb +16 -8
  39. data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
  40. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb +11 -1
  41. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/dereferenceable.rb +2 -2
  42. data/lib/concurrent-ruby/concurrent/concern/logging.rb +116 -0
  43. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  44. data/lib/concurrent-ruby/concurrent/configuration.rb +105 -0
  45. data/lib/{concurrent → concurrent-ruby/concurrent}/delay.rb +2 -2
  46. data/lib/{concurrent → concurrent-ruby/concurrent}/errors.rb +5 -0
  47. data/lib/{concurrent → concurrent-ruby/concurrent}/exchanger.rb +1 -0
  48. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/abstract_executor_service.rb +34 -37
  49. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/cached_thread_pool.rb +4 -4
  50. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/executor_service.rb +2 -2
  51. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/fixed_thread_pool.rb +29 -15
  52. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_executor_service.rb +21 -9
  53. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_single_thread_executor.rb +4 -3
  54. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_thread_pool_executor.rb +19 -2
  55. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_executor_service.rb +10 -6
  56. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_single_thread_executor.rb +0 -1
  57. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_thread_pool_executor.rb +46 -42
  58. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/safe_task_executor.rb +6 -6
  59. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution.rb +1 -1
  60. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/simple_executor_service.rb +5 -2
  61. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/single_thread_executor.rb +1 -0
  62. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/thread_pool_executor.rb +2 -1
  63. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/timer_set.rb +0 -1
  64. data/lib/{concurrent → concurrent-ruby/concurrent}/hash.rb +1 -10
  65. data/lib/{concurrent → concurrent-ruby/concurrent}/immutable_struct.rb +10 -2
  66. data/lib/{concurrent → concurrent-ruby/concurrent}/ivar.rb +2 -1
  67. data/lib/{concurrent → concurrent-ruby/concurrent}/map.rb +44 -31
  68. data/lib/{concurrent → concurrent-ruby/concurrent}/maybe.rb +1 -1
  69. data/lib/{concurrent → concurrent-ruby/concurrent}/mutable_struct.rb +13 -3
  70. data/lib/{concurrent → concurrent-ruby/concurrent}/mvar.rb +1 -1
  71. data/lib/{concurrent → concurrent-ruby/concurrent}/promise.rb +2 -1
  72. data/lib/{concurrent → concurrent-ruby/concurrent}/promises.rb +7 -6
  73. data/lib/{concurrent → concurrent-ruby/concurrent}/re_include.rb +2 -0
  74. data/lib/{concurrent → concurrent-ruby/concurrent}/scheduled_task.rb +30 -17
  75. data/lib/{concurrent → concurrent-ruby/concurrent}/set.rb +17 -19
  76. data/lib/{concurrent → concurrent-ruby/concurrent}/settable_struct.rb +13 -3
  77. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_lockable_object.rb +5 -1
  78. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_object.rb +1 -3
  79. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_struct.rb +11 -0
  80. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/condition.rb +2 -0
  81. data/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb +29 -0
  82. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_lockable_object.rb +3 -1
  83. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lock.rb +2 -0
  84. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lockable_object.rb +8 -7
  85. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mutex_lockable_object.rb +18 -5
  86. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/object.rb +12 -44
  87. data/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb +36 -0
  88. data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +101 -0
  89. data/lib/concurrent-ruby/concurrent/synchronization.rb +13 -0
  90. data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +47 -0
  91. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/cheap_lockable.rb +2 -39
  92. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +52 -0
  93. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/striped64.rb +1 -1
  94. data/lib/{concurrent → concurrent-ruby/concurrent}/timer_task.rb +11 -34
  95. data/lib/{concurrent → concurrent-ruby/concurrent}/tuple.rb +1 -5
  96. data/lib/{concurrent → concurrent-ruby/concurrent}/tvar.rb +21 -57
  97. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/engine.rb +5 -16
  98. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +19 -0
  99. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_extension_loader.rb +8 -10
  100. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_integer.rb +1 -0
  101. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +110 -0
  102. data/lib/concurrent-ruby/concurrent/version.rb +3 -0
  103. data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
  104. metadata +127 -129
  105. data/lib/concurrent/atomic/abstract_thread_local_var.rb +0 -66
  106. data/lib/concurrent/atomic/atomic_reference.rb +0 -204
  107. data/lib/concurrent/atomic/java_thread_local_var.rb +0 -37
  108. data/lib/concurrent/atomic/ruby_thread_local_var.rb +0 -161
  109. data/lib/concurrent/atomic/thread_local_var.rb +0 -104
  110. data/lib/concurrent/concern/logging.rb +0 -32
  111. data/lib/concurrent/concurrent_ruby.jar +0 -0
  112. data/lib/concurrent/configuration.rb +0 -184
  113. data/lib/concurrent/synchronization/jruby_object.rb +0 -45
  114. data/lib/concurrent/synchronization/mri_object.rb +0 -44
  115. data/lib/concurrent/synchronization/rbx_lockable_object.rb +0 -65
  116. data/lib/concurrent/synchronization/rbx_object.rb +0 -49
  117. data/lib/concurrent/synchronization/truffleruby_object.rb +0 -47
  118. data/lib/concurrent/synchronization/volatile.rb +0 -36
  119. data/lib/concurrent/synchronization.rb +0 -30
  120. data/lib/concurrent/thread_safe/synchronized_delegator.rb +0 -50
  121. data/lib/concurrent/thread_safe/util/data_structures.rb +0 -63
  122. data/lib/concurrent/utility/at_exit.rb +0 -97
  123. data/lib/concurrent/utility/monotonic_time.rb +0 -58
  124. data/lib/concurrent/utility/processor_counter.rb +0 -158
  125. data/lib/concurrent/version.rb +0 -3
  126. data/lib/concurrent-ruby.rb +0 -1
  127. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/count_down_latch.rb +1 -1
  128. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/numeric_cas_wrapper.rb +0 -0
  129. data/lib/{concurrent → concurrent-ruby/concurrent}/atomics.rb +0 -0
  130. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/java_non_concurrent_priority_queue.rb +0 -0
  131. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/atomic_reference_map_backend.rb +0 -0
  132. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/synchronized_map_backend.rb +0 -0
  133. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/non_concurrent_priority_queue.rb +1 -1
  134. /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/deprecation.rb +0 -0
  135. /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/obligation.rb +0 -0
  136. /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/observable.rb +0 -0
  137. /data/lib/{concurrent → concurrent-ruby/concurrent}/constants.rb +0 -0
  138. /data/lib/{concurrent → concurrent-ruby/concurrent}/dataflow.rb +0 -0
  139. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/immediate_executor.rb +0 -0
  140. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/indirect_immediate_executor.rb +0 -0
  141. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serial_executor_service.rb +0 -0
  142. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution_delegator.rb +0 -0
  143. /data/lib/{concurrent → concurrent-ruby/concurrent}/executors.rb +0 -0
  144. /data/lib/{concurrent → concurrent-ruby/concurrent}/future.rb +0 -0
  145. /data/lib/{concurrent → concurrent-ruby/concurrent}/options.rb +0 -0
  146. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/adder.rb +0 -0
  147. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/power_of_two_tuple.rb +0 -0
  148. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/volatile.rb +0 -0
  149. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/xor_shift_random.rb +0 -0
  150. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util.rb +0 -0
  151. /data/lib/{concurrent.rb → concurrent-ruby/concurrent.rb} +0 -0
@@ -0,0 +1,52 @@
1
+ require 'concurrent/thread_safe/util'
2
+ require 'concurrent/utility/engine'
3
+
4
+ # Shim for TruffleRuby.synchronized
5
+ if Concurrent.on_truffleruby? && !TruffleRuby.respond_to?(:synchronized)
6
+ module TruffleRuby
7
+ def self.synchronized(object, &block)
8
+ Truffle::System.synchronized(object, &block)
9
+ end
10
+ end
11
+ end
12
+
13
+ module Concurrent
14
+ module ThreadSafe
15
+ module Util
16
+ def self.make_synchronized_on_cruby(klass)
17
+ klass.class_eval do
18
+ def initialize(*args, &block)
19
+ @_monitor = Monitor.new
20
+ super
21
+ end
22
+
23
+ def initialize_copy(other)
24
+ # make sure a copy is not sharing a monitor with the original object!
25
+ @_monitor = Monitor.new
26
+ super
27
+ end
28
+ end
29
+
30
+ klass.superclass.instance_methods(false).each do |method|
31
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
32
+ def #{method}(*args)
33
+ monitor = @_monitor
34
+ monitor or raise("BUG: Internal monitor was not properly initialized. Please report this to the concurrent-ruby developers.")
35
+ monitor.synchronize { super }
36
+ end
37
+ RUBY
38
+ end
39
+ end
40
+
41
+ def self.make_synchronized_on_truffleruby(klass)
42
+ klass.superclass.instance_methods(false).each do |method|
43
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
44
+ def #{method}(*args, &block)
45
+ TruffleRuby.synchronized(self) { super(*args, &block) }
46
+ end
47
+ RUBY
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -97,7 +97,7 @@ module Concurrent
97
97
  # TODO: this only adds padding after the :value slot, need to find a way to add padding before the slot
98
98
  # TODO (pitr-ch 28-Jul-2018): the padding instance vars may not be created
99
99
  # hide from yardoc in a method
100
- attr_reader *(12.times.collect{ |i| "padding_#{i}".to_sym })
100
+ attr_reader :padding_0, :padding_1, :padding_2, :padding_3, :padding_4, :padding_5, :padding_6, :padding_7, :padding_8, :padding_9, :padding_10, :padding_11
101
101
  end
102
102
  padding
103
103
  end
@@ -25,9 +25,7 @@ module Concurrent
25
25
  # Should the task experience an unrecoverable crash only the task thread will
26
26
  # crash. This makes the `TimerTask` very fault tolerant. Additionally, the
27
27
  # `TimerTask` thread can respond to the success or failure of the task,
28
- # performing logging or ancillary operations. `TimerTask` can also be
29
- # configured with a timeout value allowing it to kill a task that runs too
30
- # long.
28
+ # performing logging or ancillary operations.
31
29
  #
32
30
  # One other advantage of `TimerTask` is that it forces the business logic to
33
31
  # be completely decoupled from the concurrency logic. The business logic can
@@ -48,9 +46,7 @@ module Concurrent
48
46
  # {http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html
49
47
  # Observable} module. On execution the `TimerTask` will notify the observers
50
48
  # with three arguments: time of execution, the result of the block (or nil on
51
- # failure), and any raised exceptions (or nil on success). If the timeout
52
- # interval is exceeded the observer will receive a `Concurrent::TimeoutError`
53
- # object as the third argument.
49
+ # failure), and any raised exceptions (or nil on success).
54
50
  #
55
51
  # @!macro copy_options
56
52
  #
@@ -59,20 +55,18 @@ module Concurrent
59
55
  # task.execute
60
56
  #
61
57
  # task.execution_interval #=> 60 (default)
62
- # task.timeout_interval #=> 30 (default)
63
58
  #
64
59
  # # wait 60 seconds...
65
60
  # #=> 'Boom!'
66
61
  #
67
62
  # task.shutdown #=> true
68
63
  #
69
- # @example Configuring `:execution_interval` and `:timeout_interval`
70
- # task = Concurrent::TimerTask.new(execution_interval: 5, timeout_interval: 5) do
64
+ # @example Configuring `:execution_interval`
65
+ # task = Concurrent::TimerTask.new(execution_interval: 5) do
71
66
  # puts 'Boom!'
72
67
  # end
73
68
  #
74
69
  # task.execution_interval #=> 5
75
- # task.timeout_interval #=> 5
76
70
  #
77
71
  # @example Immediate execution with `:run_now`
78
72
  # task = Concurrent::TimerTask.new(run_now: true){ puts 'Boom!' }
@@ -115,15 +109,13 @@ module Concurrent
115
109
  # def update(time, result, ex)
116
110
  # if result
117
111
  # print "(#{time}) Execution successfully returned #{result}\n"
118
- # elsif ex.is_a?(Concurrent::TimeoutError)
119
- # print "(#{time}) Execution timed out\n"
120
112
  # else
121
113
  # print "(#{time}) Execution failed with error #{ex}\n"
122
114
  # end
123
115
  # end
124
116
  # end
125
117
  #
126
- # task = Concurrent::TimerTask.new(execution_interval: 1, timeout_interval: 1){ 42 }
118
+ # task = Concurrent::TimerTask.new(execution_interval: 1){ 42 }
127
119
  # task.add_observer(TaskObserver.new)
128
120
  # task.execute
129
121
  # sleep 4
@@ -133,7 +125,7 @@ module Concurrent
133
125
  # #=> (2013-10-13 19:09:00 -0400) Execution successfully returned 42
134
126
  # task.shutdown
135
127
  #
136
- # task = Concurrent::TimerTask.new(execution_interval: 1, timeout_interval: 1){ sleep }
128
+ # task = Concurrent::TimerTask.new(execution_interval: 1){ sleep }
137
129
  # task.add_observer(TaskObserver.new)
138
130
  # task.execute
139
131
  #
@@ -169,8 +161,6 @@ module Concurrent
169
161
  # @param [Hash] opts the options defining task execution.
170
162
  # @option opts [Integer] :execution_interval number of seconds between
171
163
  # task executions (default: EXECUTION_INTERVAL)
172
- # @option opts [Integer] :timeout_interval number of seconds a task can
173
- # run before it is considered to have failed (default: TIMEOUT_INTERVAL)
174
164
  # @option opts [Boolean] :run_now Whether to run the task immediately
175
165
  # upon instantiation or to wait until the first # execution_interval
176
166
  # has passed (default: false)
@@ -256,18 +246,14 @@ module Concurrent
256
246
  # @return [Fixnum] Number of seconds the task can run before it is
257
247
  # considered to have failed.
258
248
  def timeout_interval
259
- synchronize { @timeout_interval }
249
+ warn 'TimerTask timeouts are now ignored as these were not able to be implemented correctly'
260
250
  end
261
251
 
262
252
  # @!attribute [rw] timeout_interval
263
253
  # @return [Fixnum] Number of seconds the task can run before it is
264
254
  # considered to have failed.
265
255
  def timeout_interval=(value)
266
- if (value = value.to_f) <= 0.0
267
- raise ArgumentError.new('must be greater than zero')
268
- else
269
- synchronize { @timeout_interval = value }
270
- end
256
+ warn 'TimerTask timeouts are now ignored as these were not able to be implemented correctly'
271
257
  end
272
258
 
273
259
  private :post, :<<
@@ -278,7 +264,9 @@ module Concurrent
278
264
  set_deref_options(opts)
279
265
 
280
266
  self.execution_interval = opts[:execution] || opts[:execution_interval] || EXECUTION_INTERVAL
281
- self.timeout_interval = opts[:timeout] || opts[:timeout_interval] || TIMEOUT_INTERVAL
267
+ if opts[:timeout] || opts[:timeout_interval]
268
+ warn 'TimeTask timeouts are now ignored as these were not able to be implemented correctly'
269
+ end
282
270
  @run_now = opts[:now] || opts[:run_now]
283
271
  @executor = Concurrent::SafeTaskExecutor.new(task)
284
272
  @running = Concurrent::AtomicBoolean.new(false)
@@ -308,7 +296,6 @@ module Concurrent
308
296
  # @!visibility private
309
297
  def execute_task(completion)
310
298
  return nil unless @running.true?
311
- ScheduledTask.execute(timeout_interval, args: [completion], &method(:timeout_task))
312
299
  _success, value, reason = @executor.execute(self)
313
300
  if completion.try?
314
301
  self.value = value
@@ -320,15 +307,5 @@ module Concurrent
320
307
  end
321
308
  nil
322
309
  end
323
-
324
- # @!visibility private
325
- def timeout_task(completion)
326
- return unless @running.true?
327
- if completion.try?
328
- self.value = value
329
- schedule_next_task
330
- observers.notify_observers(Time.now, nil, Concurrent::TimeoutError.new)
331
- end
332
- end
333
310
  end
334
311
  end
@@ -23,16 +23,12 @@ module Concurrent
23
23
  # The (fixed) size of the tuple.
24
24
  attr_reader :size
25
25
 
26
- # @!visibility private
27
- Tuple = defined?(Rubinius::Tuple) ? Rubinius::Tuple : ::Array
28
- private_constant :Tuple
29
-
30
26
  # Create a new tuple of the given size.
31
27
  #
32
28
  # @param [Integer] size the number of elements in the tuple
33
29
  def initialize(size)
34
30
  @size = size
35
- @tuple = tuple = Tuple.new(size)
31
+ @tuple = tuple = ::Array.new(size)
36
32
  i = 0
37
33
  while i < size
38
34
  tuple[i] = Concurrent::AtomicReference.new
@@ -1,5 +1,5 @@
1
1
  require 'set'
2
- require 'concurrent/synchronization'
2
+ require 'concurrent/synchronization/object'
3
3
 
4
4
  module Concurrent
5
5
 
@@ -15,7 +15,6 @@ module Concurrent
15
15
  # Create a new `TVar` with an initial value.
16
16
  def initialize(value)
17
17
  @value = value
18
- @version = 0
19
18
  @lock = Mutex.new
20
19
  end
21
20
 
@@ -43,16 +42,6 @@ module Concurrent
43
42
  @value = value
44
43
  end
45
44
 
46
- # @!visibility private
47
- def unsafe_version # :nodoc:
48
- @version
49
- end
50
-
51
- # @!visibility private
52
- def unsafe_increment_version # :nodoc:
53
- @version += 1
54
- end
55
-
56
45
  # @!visibility private
57
46
  def unsafe_lock # :nodoc:
58
47
  @lock
@@ -160,54 +149,44 @@ module Concurrent
160
149
 
161
150
  private
162
151
 
152
+ # @!visibility private
163
153
  class Transaction
164
154
 
165
155
  ABORTED = ::Object.new
166
156
 
167
- ReadLogEntry = Struct.new(:tvar, :version)
157
+ OpenEntry = Struct.new(:value, :modified)
168
158
 
169
159
  AbortError = Class.new(StandardError)
170
160
  LeaveError = Class.new(StandardError)
171
161
 
172
162
  def initialize
173
- @read_log = []
174
- @write_log = {}
163
+ @open_tvars = {}
175
164
  end
176
165
 
177
166
  def read(tvar)
178
- Concurrent::abort_transaction unless valid?
179
-
180
- if @write_log.has_key? tvar
181
- @write_log[tvar]
182
- else
183
- @read_log.push(ReadLogEntry.new(tvar, tvar.unsafe_version))
184
- tvar.unsafe_value
185
- end
167
+ entry = open(tvar)
168
+ entry.value
186
169
  end
187
170
 
188
171
  def write(tvar, value)
189
- # Have we already written to this TVar?
172
+ entry = open(tvar)
173
+ entry.modified = true
174
+ entry.value = value
175
+ end
190
176
 
191
- unless @write_log.has_key? tvar
192
- # Try to lock the TVar
177
+ def open(tvar)
178
+ entry = @open_tvars[tvar]
193
179
 
180
+ unless entry
194
181
  unless tvar.unsafe_lock.try_lock
195
- # Someone else is writing to this TVar - abort
196
182
  Concurrent::abort_transaction
197
183
  end
198
184
 
199
- # If we previously wrote to it, check the version hasn't changed
200
-
201
- @read_log.each do |log_entry|
202
- if log_entry.tvar == tvar and tvar.unsafe_version > log_entry.version
203
- Concurrent::abort_transaction
204
- end
205
- end
185
+ entry = OpenEntry.new(tvar.unsafe_value, false)
186
+ @open_tvars[tvar] = entry
206
187
  end
207
188
 
208
- # Record the value written
209
-
210
- @write_log[tvar] = value
189
+ entry
211
190
  end
212
191
 
213
192
  def abort
@@ -215,32 +194,17 @@ module Concurrent
215
194
  end
216
195
 
217
196
  def commit
218
- return false unless valid?
219
-
220
- @write_log.each_pair do |tvar, value|
221
- tvar.unsafe_value = value
222
- tvar.unsafe_increment_version
223
- end
224
-
225
- unlock
226
-
227
- true
228
- end
229
-
230
- def valid?
231
- @read_log.each do |log_entry|
232
- unless @write_log.has_key? log_entry.tvar
233
- if log_entry.tvar.unsafe_version > log_entry.version
234
- return false
235
- end
197
+ @open_tvars.each do |tvar, entry|
198
+ if entry.modified
199
+ tvar.unsafe_value = entry.value
236
200
  end
237
201
  end
238
202
 
239
- true
203
+ unlock
240
204
  end
241
205
 
242
206
  def unlock
243
- @write_log.each_key do |tvar|
207
+ @open_tvars.each_key do |tvar|
244
208
  tvar.unsafe_lock.unlock
245
209
  end
246
210
  end
@@ -1,26 +1,19 @@
1
1
  module Concurrent
2
+ # @!visibility private
2
3
  module Utility
3
4
 
4
5
  # @!visibility private
5
6
  module EngineDetector
6
- def on_jruby?
7
- ruby_engine == 'jruby'
8
- end
9
-
10
- def on_jruby_9000?
11
- on_jruby? && ruby_version(JRUBY_VERSION, :>=, 9, 0, 0)
12
- end
13
-
14
7
  def on_cruby?
15
- ruby_engine == 'ruby'
8
+ RUBY_ENGINE == 'ruby'
16
9
  end
17
10
 
18
- def on_rbx?
19
- ruby_engine == 'rbx'
11
+ def on_jruby?
12
+ RUBY_ENGINE == 'jruby'
20
13
  end
21
14
 
22
15
  def on_truffleruby?
23
- ruby_engine == 'truffleruby'
16
+ RUBY_ENGINE == 'truffleruby'
24
17
  end
25
18
 
26
19
  def on_windows?
@@ -35,10 +28,6 @@ module Concurrent
35
28
  !(RbConfig::CONFIG['host_os'] =~ /linux/).nil?
36
29
  end
37
30
 
38
- def ruby_engine
39
- defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
40
- end
41
-
42
31
  def ruby_version(version = RUBY_VERSION, comparison, major, minor, patch)
43
32
  result = (version.split('.').map(&:to_i) <=> [major, minor, patch])
44
33
  comparisons = { :== => [0],
@@ -0,0 +1,19 @@
1
+ module Concurrent
2
+
3
+ # @!macro monotonic_get_time
4
+ #
5
+ # Returns the current time as tracked by the application monotonic clock.
6
+ #
7
+ # @param [Symbol] unit the time unit to be returned, can be either
8
+ # :float_second, :float_millisecond, :float_microsecond, :second,
9
+ # :millisecond, :microsecond, or :nanosecond default to :float_second.
10
+ #
11
+ # @return [Float] The current monotonic time since some unspecified
12
+ # starting point
13
+ #
14
+ # @!macro monotonic_clock_warning
15
+ def monotonic_time(unit = :float_second)
16
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, unit)
17
+ end
18
+ module_function :monotonic_time
19
+ end
@@ -1,9 +1,10 @@
1
1
  require 'concurrent/utility/engine'
2
+ # Synchronization::AbstractObject must be defined before loading the extension
3
+ require 'concurrent/synchronization/abstract_object'
2
4
 
3
5
  module Concurrent
4
-
6
+ # @!visibility private
5
7
  module Utility
6
-
7
8
  # @!visibility private
8
9
  module NativeExtensionLoader
9
10
 
@@ -15,15 +16,7 @@ module Concurrent
15
16
  defined?(@c_extensions_loaded) && @c_extensions_loaded
16
17
  end
17
18
 
18
- def java_extensions_loaded?
19
- defined?(@java_extensions_loaded) && @java_extensions_loaded
20
- end
21
-
22
19
  def load_native_extensions
23
- unless defined? Synchronization::AbstractObject
24
- raise 'native_extension_loader loaded before Synchronization::AbstractObject'
25
- end
26
-
27
20
  if Concurrent.on_cruby? && !c_extensions_loaded?
28
21
  ['concurrent/concurrent_ruby_ext',
29
22
  "concurrent/#{RUBY_VERSION[0..2]}/concurrent_ruby_ext"
@@ -54,6 +47,10 @@ module Concurrent
54
47
  @c_extensions_loaded = true
55
48
  end
56
49
 
50
+ def java_extensions_loaded?
51
+ defined?(@java_extensions_loaded) && @java_extensions_loaded
52
+ end
53
+
57
54
  def set_java_extensions_loaded
58
55
  @java_extensions_loaded = true
59
56
  end
@@ -77,3 +74,4 @@ module Concurrent
77
74
  extend Utility::NativeExtensionLoader
78
75
  end
79
76
 
77
+ Concurrent.load_native_extensions
@@ -1,4 +1,5 @@
1
1
  module Concurrent
2
+ # @!visibility private
2
3
  module Utility
3
4
  # @private
4
5
  module NativeInteger
@@ -0,0 +1,110 @@
1
+ require 'etc'
2
+ require 'rbconfig'
3
+ require 'concurrent/delay'
4
+
5
+ module Concurrent
6
+ # @!visibility private
7
+ module Utility
8
+
9
+ # @!visibility private
10
+ class ProcessorCounter
11
+ def initialize
12
+ @processor_count = Delay.new { compute_processor_count }
13
+ @physical_processor_count = Delay.new { compute_physical_processor_count }
14
+ end
15
+
16
+ def processor_count
17
+ @processor_count.value
18
+ end
19
+
20
+ def physical_processor_count
21
+ @physical_processor_count.value
22
+ end
23
+
24
+ private
25
+
26
+ def compute_processor_count
27
+ if Concurrent.on_jruby?
28
+ java.lang.Runtime.getRuntime.availableProcessors
29
+ else
30
+ Etc.nprocessors
31
+ end
32
+ end
33
+
34
+ def compute_physical_processor_count
35
+ ppc = case RbConfig::CONFIG["target_os"]
36
+ when /darwin\d\d/
37
+ IO.popen("/usr/sbin/sysctl -n hw.physicalcpu", &:read).to_i
38
+ when /linux/
39
+ cores = {} # unique physical ID / core ID combinations
40
+ phy = 0
41
+ IO.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln|
42
+ if ln.start_with?("physical")
43
+ phy = ln[/\d+/]
44
+ elsif ln.start_with?("core")
45
+ cid = phy + ":" + ln[/\d+/]
46
+ cores[cid] = true if not cores[cid]
47
+ end
48
+ end
49
+ cores.count
50
+ when /mswin|mingw/
51
+ require 'win32ole'
52
+ result_set = WIN32OLE.connect("winmgmts://").ExecQuery(
53
+ "select NumberOfCores from Win32_Processor")
54
+ result_set.to_enum.collect(&:NumberOfCores).reduce(:+)
55
+ else
56
+ processor_count
57
+ end
58
+ # fall back to logical count if physical info is invalid
59
+ ppc > 0 ? ppc : processor_count
60
+ rescue
61
+ return 1
62
+ end
63
+ end
64
+ end
65
+
66
+ # create the default ProcessorCounter on load
67
+ @processor_counter = Utility::ProcessorCounter.new
68
+ singleton_class.send :attr_reader, :processor_counter
69
+
70
+ # Number of processors seen by the OS and used for process scheduling. For
71
+ # performance reasons the calculated value will be memoized on the first
72
+ # call.
73
+ #
74
+ # When running under JRuby the Java runtime call
75
+ # `java.lang.Runtime.getRuntime.availableProcessors` will be used. According
76
+ # to the Java documentation this "value may change during a particular
77
+ # invocation of the virtual machine... [applications] should therefore
78
+ # occasionally poll this property." Subsequently the result will NOT be
79
+ # memoized under JRuby.
80
+ #
81
+ # Otherwise Ruby's Etc.nprocessors will be used.
82
+ #
83
+ # @return [Integer] number of processors seen by the OS or Java runtime
84
+ #
85
+ # @see http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#availableProcessors()
86
+ def self.processor_count
87
+ processor_counter.processor_count
88
+ end
89
+
90
+ # Number of physical processor cores on the current system. For performance
91
+ # reasons the calculated value will be memoized on the first call.
92
+ #
93
+ # On Windows the Win32 API will be queried for the `NumberOfCores from
94
+ # Win32_Processor`. This will return the total number "of cores for the
95
+ # current instance of the processor." On Unix-like operating systems either
96
+ # the `hwprefs` or `sysctl` utility will be called in a subshell and the
97
+ # returned value will be used. In the rare case where none of these methods
98
+ # work or an exception is raised the function will simply return 1.
99
+ #
100
+ # @return [Integer] number physical processor cores on the current system
101
+ #
102
+ # @see https://github.com/grosser/parallel/blob/4fc8b89d08c7091fe0419ca8fba1ec3ce5a8d185/lib/parallel.rb
103
+ #
104
+ # @see http://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx
105
+ # @see http://www.unix.com/man-page/osx/1/HWPREFS/
106
+ # @see http://linux.die.net/man/8/sysctl
107
+ def self.physical_processor_count
108
+ processor_counter.physical_processor_count
109
+ end
110
+ end
@@ -0,0 +1,3 @@
1
+ module Concurrent
2
+ VERSION = '1.2.2'
3
+ end
@@ -0,0 +1,5 @@
1
+ # This file is here so that there is a file with the same name as the gem that
2
+ # can be required by Bundler.require. Applications should normally
3
+ # require 'concurrent'.
4
+
5
+ require_relative "concurrent"