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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +84 -1
- data/Gemfile +5 -10
- data/{LICENSE.md → LICENSE.txt} +18 -20
- data/README.md +55 -31
- data/Rakefile +84 -92
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +0 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +52 -22
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +10 -25
- data/lib/{concurrent → concurrent-ruby/concurrent}/agent.rb +2 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/array.rb +6 -16
- data/lib/{concurrent → concurrent-ruby/concurrent}/async.rb +10 -20
- data/lib/{concurrent → concurrent-ruby/concurrent}/atom.rb +2 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_boolean.rb +7 -6
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_fixnum.rb +5 -4
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_markable_reference.rb +3 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +135 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/cyclic_barrier.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/event.rb +3 -3
- data/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb +109 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_count_down_latch.rb +1 -0
- data/lib/concurrent-ruby/concurrent/atomic/locals.rb +189 -0
- data/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb +28 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_boolean.rb +11 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_fixnum.rb +11 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_count_down_latch.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_semaphore.rb +19 -3
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/read_write_lock.rb +2 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/reentrant_read_write_lock.rb +9 -9
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/semaphore.rb +32 -14
- data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +111 -0
- data/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb +37 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/mutex_atomic.rb +15 -4
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_notify_observer_set.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_write_observer_set.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/lock_free_stack.rb +2 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/mri_map_backend.rb +3 -3
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/non_concurrent_map_backend.rb +16 -8
- data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb +11 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/dereferenceable.rb +2 -2
- data/lib/concurrent-ruby/concurrent/concern/logging.rb +116 -0
- data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent-ruby/concurrent/configuration.rb +105 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/delay.rb +2 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/errors.rb +5 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/exchanger.rb +1 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/abstract_executor_service.rb +34 -37
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/cached_thread_pool.rb +4 -4
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/executor_service.rb +2 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/fixed_thread_pool.rb +29 -15
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_executor_service.rb +21 -9
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_single_thread_executor.rb +4 -3
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_thread_pool_executor.rb +19 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_executor_service.rb +10 -6
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_single_thread_executor.rb +0 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_thread_pool_executor.rb +46 -42
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/safe_task_executor.rb +6 -6
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/simple_executor_service.rb +5 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/single_thread_executor.rb +1 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/thread_pool_executor.rb +2 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/timer_set.rb +0 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/hash.rb +1 -10
- data/lib/{concurrent → concurrent-ruby/concurrent}/immutable_struct.rb +10 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/ivar.rb +2 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/map.rb +44 -31
- data/lib/{concurrent → concurrent-ruby/concurrent}/maybe.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/mutable_struct.rb +13 -3
- data/lib/{concurrent → concurrent-ruby/concurrent}/mvar.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/promise.rb +2 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/promises.rb +7 -6
- data/lib/{concurrent → concurrent-ruby/concurrent}/re_include.rb +2 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/scheduled_task.rb +30 -17
- data/lib/{concurrent → concurrent-ruby/concurrent}/set.rb +17 -19
- data/lib/{concurrent → concurrent-ruby/concurrent}/settable_struct.rb +13 -3
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_lockable_object.rb +5 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_object.rb +1 -3
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_struct.rb +11 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/condition.rb +2 -0
- data/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb +29 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_lockable_object.rb +3 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lock.rb +2 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lockable_object.rb +8 -7
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mutex_lockable_object.rb +18 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/object.rb +12 -44
- data/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb +36 -0
- data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +101 -0
- data/lib/concurrent-ruby/concurrent/synchronization.rb +13 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +47 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/cheap_lockable.rb +2 -39
- data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +52 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/striped64.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/timer_task.rb +11 -34
- data/lib/{concurrent → concurrent-ruby/concurrent}/tuple.rb +1 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/tvar.rb +21 -57
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/engine.rb +5 -16
- data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +19 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_extension_loader.rb +8 -10
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_integer.rb +1 -0
- data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +110 -0
- data/lib/concurrent-ruby/concurrent/version.rb +3 -0
- data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
- metadata +127 -129
- data/lib/concurrent/atomic/abstract_thread_local_var.rb +0 -66
- data/lib/concurrent/atomic/atomic_reference.rb +0 -204
- data/lib/concurrent/atomic/java_thread_local_var.rb +0 -37
- data/lib/concurrent/atomic/ruby_thread_local_var.rb +0 -161
- data/lib/concurrent/atomic/thread_local_var.rb +0 -104
- data/lib/concurrent/concern/logging.rb +0 -32
- data/lib/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent/configuration.rb +0 -184
- data/lib/concurrent/synchronization/jruby_object.rb +0 -45
- data/lib/concurrent/synchronization/mri_object.rb +0 -44
- data/lib/concurrent/synchronization/rbx_lockable_object.rb +0 -65
- data/lib/concurrent/synchronization/rbx_object.rb +0 -49
- data/lib/concurrent/synchronization/truffleruby_object.rb +0 -47
- data/lib/concurrent/synchronization/volatile.rb +0 -36
- data/lib/concurrent/synchronization.rb +0 -30
- data/lib/concurrent/thread_safe/synchronized_delegator.rb +0 -50
- data/lib/concurrent/thread_safe/util/data_structures.rb +0 -63
- data/lib/concurrent/utility/at_exit.rb +0 -97
- data/lib/concurrent/utility/monotonic_time.rb +0 -58
- data/lib/concurrent/utility/processor_counter.rb +0 -158
- data/lib/concurrent/version.rb +0 -3
- data/lib/concurrent-ruby.rb +0 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/count_down_latch.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/numeric_cas_wrapper.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomics.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/java_non_concurrent_priority_queue.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/atomic_reference_map_backend.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/synchronized_map_backend.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/non_concurrent_priority_queue.rb +1 -1
- /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/deprecation.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/obligation.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/observable.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/constants.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/dataflow.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/immediate_executor.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/indirect_immediate_executor.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serial_executor_service.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution_delegator.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/executors.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/future.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/options.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/adder.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/power_of_two_tuple.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/volatile.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/xor_shift_random.rb +0 -0
- /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util.rb +0 -0
- /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
|
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.
|
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).
|
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`
|
70
|
-
# task = Concurrent::TimerTask.new(execution_interval: 5
|
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
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =
|
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
|
-
|
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
|
-
@
|
174
|
-
@write_log = {}
|
163
|
+
@open_tvars = {}
|
175
164
|
end
|
176
165
|
|
177
166
|
def read(tvar)
|
178
|
-
|
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
|
-
|
172
|
+
entry = open(tvar)
|
173
|
+
entry.modified = true
|
174
|
+
entry.value = value
|
175
|
+
end
|
190
176
|
|
191
|
-
|
192
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
219
|
-
|
220
|
-
|
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
|
-
|
203
|
+
unlock
|
240
204
|
end
|
241
205
|
|
242
206
|
def unlock
|
243
|
-
@
|
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
|
-
|
8
|
+
RUBY_ENGINE == 'ruby'
|
16
9
|
end
|
17
10
|
|
18
|
-
def
|
19
|
-
|
11
|
+
def on_jruby?
|
12
|
+
RUBY_ENGINE == 'jruby'
|
20
13
|
end
|
21
14
|
|
22
15
|
def on_truffleruby?
|
23
|
-
|
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
|
@@ -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
|