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
@@ -1,161 +0,0 @@
|
|
1
|
-
require 'thread'
|
2
|
-
require 'concurrent/atomic/abstract_thread_local_var'
|
3
|
-
|
4
|
-
module Concurrent
|
5
|
-
|
6
|
-
# @!visibility private
|
7
|
-
# @!macro internal_implementation_note
|
8
|
-
class RubyThreadLocalVar < AbstractThreadLocalVar
|
9
|
-
|
10
|
-
# Each thread has a (lazily initialized) array of thread-local variable values
|
11
|
-
# Each time a new thread-local var is created, we allocate an "index" for it
|
12
|
-
# For example, if the allocated index is 1, that means slot #1 in EVERY
|
13
|
-
# thread's thread-local array will be used for the value of that TLV
|
14
|
-
#
|
15
|
-
# The good thing about using a per-THREAD structure to hold values, rather
|
16
|
-
# than a per-TLV structure, is that no synchronization is needed when
|
17
|
-
# reading and writing those values (since the structure is only ever
|
18
|
-
# accessed by a single thread)
|
19
|
-
#
|
20
|
-
# Of course, when a TLV is GC'd, 1) we need to recover its index for use
|
21
|
-
# by other new TLVs (otherwise the thread-local arrays could get bigger
|
22
|
-
# and bigger with time), and 2) we need to null out all the references
|
23
|
-
# held in the now-unused slots (both to avoid blocking GC of those objects,
|
24
|
-
# and also to prevent "stale" values from being passed on to a new TLV
|
25
|
-
# when the index is reused)
|
26
|
-
# Because we need to null out freed slots, we need to keep references to
|
27
|
-
# ALL the thread-local arrays -- ARRAYS is for that
|
28
|
-
# But when a Thread is GC'd, we need to drop the reference to its thread-local
|
29
|
-
# array, so we don't leak memory
|
30
|
-
|
31
|
-
# @!visibility private
|
32
|
-
FREE = []
|
33
|
-
LOCK = Mutex.new
|
34
|
-
ARRAYS = {} # used as a hash set
|
35
|
-
@@next = 0
|
36
|
-
private_constant :FREE, :LOCK, :ARRAYS
|
37
|
-
|
38
|
-
# @!macro thread_local_var_method_get
|
39
|
-
def value
|
40
|
-
if array = get_threadlocal_array
|
41
|
-
value = array[@index]
|
42
|
-
if value.nil?
|
43
|
-
default
|
44
|
-
elsif value.equal?(NULL)
|
45
|
-
nil
|
46
|
-
else
|
47
|
-
value
|
48
|
-
end
|
49
|
-
else
|
50
|
-
default
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
# @!macro thread_local_var_method_set
|
55
|
-
def value=(value)
|
56
|
-
me = Thread.current
|
57
|
-
# We could keep the thread-local arrays in a hash, keyed by Thread
|
58
|
-
# But why? That would require locking
|
59
|
-
# Using Ruby's built-in thread-local storage is faster
|
60
|
-
unless array = get_threadlocal_array(me)
|
61
|
-
array = set_threadlocal_array([], me)
|
62
|
-
LOCK.synchronize { ARRAYS[array.object_id] = array }
|
63
|
-
ObjectSpace.define_finalizer(me, self.class.thread_finalizer(array))
|
64
|
-
end
|
65
|
-
array[@index] = (value.nil? ? NULL : value)
|
66
|
-
value
|
67
|
-
end
|
68
|
-
|
69
|
-
protected
|
70
|
-
|
71
|
-
# @!visibility private
|
72
|
-
def allocate_storage
|
73
|
-
@index = LOCK.synchronize do
|
74
|
-
FREE.pop || begin
|
75
|
-
result = @@next
|
76
|
-
@@next += 1
|
77
|
-
result
|
78
|
-
end
|
79
|
-
end
|
80
|
-
ObjectSpace.define_finalizer(self, self.class.threadlocal_finalizer(@index))
|
81
|
-
end
|
82
|
-
|
83
|
-
# @!visibility private
|
84
|
-
def self.threadlocal_finalizer(index)
|
85
|
-
proc do
|
86
|
-
Thread.new do # avoid error: can't be called from trap context
|
87
|
-
LOCK.synchronize do
|
88
|
-
FREE.push(index)
|
89
|
-
# The cost of GC'ing a TLV is linear in the number of threads using TLVs
|
90
|
-
# But that is natural! More threads means more storage is used per TLV
|
91
|
-
# So naturally more CPU time is required to free more storage
|
92
|
-
ARRAYS.each_value do |array|
|
93
|
-
array[index] = nil
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
# @!visibility private
|
101
|
-
def self.thread_finalizer(array)
|
102
|
-
proc do
|
103
|
-
Thread.new do # avoid error: can't be called from trap context
|
104
|
-
LOCK.synchronize do
|
105
|
-
# The thread which used this thread-local array is now gone
|
106
|
-
# So don't hold onto a reference to the array (thus blocking GC)
|
107
|
-
ARRAYS.delete(array.object_id)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
private
|
114
|
-
|
115
|
-
if Thread.instance_methods.include?(:thread_variable_get)
|
116
|
-
|
117
|
-
def get_threadlocal_array(thread = Thread.current)
|
118
|
-
thread.thread_variable_get(:__threadlocal_array__)
|
119
|
-
end
|
120
|
-
|
121
|
-
def set_threadlocal_array(array, thread = Thread.current)
|
122
|
-
thread.thread_variable_set(:__threadlocal_array__, array)
|
123
|
-
end
|
124
|
-
|
125
|
-
else
|
126
|
-
|
127
|
-
def get_threadlocal_array(thread = Thread.current)
|
128
|
-
thread[:__threadlocal_array__]
|
129
|
-
end
|
130
|
-
|
131
|
-
def set_threadlocal_array(array, thread = Thread.current)
|
132
|
-
thread[:__threadlocal_array__] = array
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
# This exists only for use in testing
|
137
|
-
# @!visibility private
|
138
|
-
def value_for(thread)
|
139
|
-
if array = get_threadlocal_array(thread)
|
140
|
-
value = array[@index]
|
141
|
-
if value.nil?
|
142
|
-
default_for(thread)
|
143
|
-
elsif value.equal?(NULL)
|
144
|
-
nil
|
145
|
-
else
|
146
|
-
value
|
147
|
-
end
|
148
|
-
else
|
149
|
-
default_for(thread)
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
def default_for(thread)
|
154
|
-
if @default_block
|
155
|
-
raise "Cannot use default_for with default block"
|
156
|
-
else
|
157
|
-
@default
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
@@ -1,104 +0,0 @@
|
|
1
|
-
require 'concurrent/atomic/ruby_thread_local_var'
|
2
|
-
require 'concurrent/atomic/java_thread_local_var'
|
3
|
-
require 'concurrent/utility/engine'
|
4
|
-
|
5
|
-
module Concurrent
|
6
|
-
|
7
|
-
###################################################################
|
8
|
-
|
9
|
-
# @!macro thread_local_var_method_initialize
|
10
|
-
#
|
11
|
-
# Creates a thread local variable.
|
12
|
-
#
|
13
|
-
# @param [Object] default the default value when otherwise unset
|
14
|
-
# @param [Proc] default_block Optional block that gets called to obtain the
|
15
|
-
# default value for each thread
|
16
|
-
|
17
|
-
# @!macro thread_local_var_method_get
|
18
|
-
#
|
19
|
-
# Returns the value in the current thread's copy of this thread-local variable.
|
20
|
-
#
|
21
|
-
# @return [Object] the current value
|
22
|
-
|
23
|
-
# @!macro thread_local_var_method_set
|
24
|
-
#
|
25
|
-
# Sets the current thread's copy of this thread-local variable to the specified value.
|
26
|
-
#
|
27
|
-
# @param [Object] value the value to set
|
28
|
-
# @return [Object] the new value
|
29
|
-
|
30
|
-
# @!macro thread_local_var_method_bind
|
31
|
-
#
|
32
|
-
# Bind the given value to thread local storage during
|
33
|
-
# execution of the given block.
|
34
|
-
#
|
35
|
-
# @param [Object] value the value to bind
|
36
|
-
# @yield the operation to be performed with the bound variable
|
37
|
-
# @return [Object] the value
|
38
|
-
|
39
|
-
|
40
|
-
###################################################################
|
41
|
-
|
42
|
-
# @!macro thread_local_var_public_api
|
43
|
-
#
|
44
|
-
# @!method initialize(default = nil, &default_block)
|
45
|
-
# @!macro thread_local_var_method_initialize
|
46
|
-
#
|
47
|
-
# @!method value
|
48
|
-
# @!macro thread_local_var_method_get
|
49
|
-
#
|
50
|
-
# @!method value=(value)
|
51
|
-
# @!macro thread_local_var_method_set
|
52
|
-
#
|
53
|
-
# @!method bind(value, &block)
|
54
|
-
# @!macro thread_local_var_method_bind
|
55
|
-
|
56
|
-
###################################################################
|
57
|
-
|
58
|
-
# @!visibility private
|
59
|
-
# @!macro internal_implementation_note
|
60
|
-
ThreadLocalVarImplementation = case
|
61
|
-
when Concurrent.on_jruby?
|
62
|
-
JavaThreadLocalVar
|
63
|
-
else
|
64
|
-
RubyThreadLocalVar
|
65
|
-
end
|
66
|
-
private_constant :ThreadLocalVarImplementation
|
67
|
-
|
68
|
-
# @!macro thread_local_var
|
69
|
-
#
|
70
|
-
# A `ThreadLocalVar` is a variable where the value is different for each thread.
|
71
|
-
# Each variable may have a default value, but when you modify the variable only
|
72
|
-
# the current thread will ever see that change.
|
73
|
-
#
|
74
|
-
# @!macro thread_safe_variable_comparison
|
75
|
-
#
|
76
|
-
# @example
|
77
|
-
# v = ThreadLocalVar.new(14)
|
78
|
-
# v.value #=> 14
|
79
|
-
# v.value = 2
|
80
|
-
# v.value #=> 2
|
81
|
-
#
|
82
|
-
# @example
|
83
|
-
# v = ThreadLocalVar.new(14)
|
84
|
-
#
|
85
|
-
# t1 = Thread.new do
|
86
|
-
# v.value #=> 14
|
87
|
-
# v.value = 1
|
88
|
-
# v.value #=> 1
|
89
|
-
# end
|
90
|
-
#
|
91
|
-
# t2 = Thread.new do
|
92
|
-
# v.value #=> 14
|
93
|
-
# v.value = 2
|
94
|
-
# v.value #=> 2
|
95
|
-
# end
|
96
|
-
#
|
97
|
-
# v.value #=> 14
|
98
|
-
#
|
99
|
-
# @see https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html Java ThreadLocal
|
100
|
-
#
|
101
|
-
# @!macro thread_local_var_public_api
|
102
|
-
class ThreadLocalVar < ThreadLocalVarImplementation
|
103
|
-
end
|
104
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'logger'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
module Concern
|
5
|
-
|
6
|
-
# Include where logging is needed
|
7
|
-
#
|
8
|
-
# @!visibility private
|
9
|
-
module Logging
|
10
|
-
include Logger::Severity
|
11
|
-
|
12
|
-
# Logs through {Concurrent.global_logger}, it can be overridden by setting @logger
|
13
|
-
# @param [Integer] level one of Logger::Severity constants
|
14
|
-
# @param [String] progname e.g. a path of an Actor
|
15
|
-
# @param [String, nil] message when nil block is used to generate the message
|
16
|
-
# @yieldreturn [String] a message
|
17
|
-
def log(level, progname, message = nil, &block)
|
18
|
-
#NOTE: Cannot require 'concurrent/configuration' above due to circular references.
|
19
|
-
# Assume that the gem has been initialized if we've gotten this far.
|
20
|
-
logger = if defined?(@logger) && @logger
|
21
|
-
@logger
|
22
|
-
else
|
23
|
-
Concurrent.global_logger
|
24
|
-
end
|
25
|
-
logger.call level, progname, message, &block
|
26
|
-
rescue => error
|
27
|
-
$stderr.puts "`Concurrent.configuration.logger` failed to log #{[level, progname, message, block]}\n" +
|
28
|
-
"#{error.message} (#{error.class})\n#{error.backtrace.join "\n"}"
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
Binary file
|
@@ -1,184 +0,0 @@
|
|
1
|
-
require 'thread'
|
2
|
-
require 'concurrent/delay'
|
3
|
-
require 'concurrent/errors'
|
4
|
-
require 'concurrent/atomic/atomic_reference'
|
5
|
-
require 'concurrent/concern/logging'
|
6
|
-
require 'concurrent/executor/immediate_executor'
|
7
|
-
require 'concurrent/executor/cached_thread_pool'
|
8
|
-
require 'concurrent/utility/at_exit'
|
9
|
-
require 'concurrent/utility/processor_counter'
|
10
|
-
|
11
|
-
module Concurrent
|
12
|
-
extend Concern::Logging
|
13
|
-
|
14
|
-
autoload :Options, 'concurrent/options'
|
15
|
-
autoload :TimerSet, 'concurrent/executor/timer_set'
|
16
|
-
autoload :ThreadPoolExecutor, 'concurrent/executor/thread_pool_executor'
|
17
|
-
|
18
|
-
# @return [Logger] Logger with provided level and output.
|
19
|
-
def self.create_simple_logger(level = Logger::FATAL, output = $stderr)
|
20
|
-
# TODO (pitr-ch 24-Dec-2016): figure out why it had to be replaced, stdlogger was deadlocking
|
21
|
-
lambda do |severity, progname, message = nil, &block|
|
22
|
-
return false if severity < level
|
23
|
-
|
24
|
-
message = block ? block.call : message
|
25
|
-
formatted_message = case message
|
26
|
-
when String
|
27
|
-
message
|
28
|
-
when Exception
|
29
|
-
format "%s (%s)\n%s",
|
30
|
-
message.message, message.class, (message.backtrace || []).join("\n")
|
31
|
-
else
|
32
|
-
message.inspect
|
33
|
-
end
|
34
|
-
|
35
|
-
output.print format "[%s] %5s -- %s: %s\n",
|
36
|
-
Time.now.strftime('%Y-%m-%d %H:%M:%S.%L'),
|
37
|
-
Logger::SEV_LABEL[severity],
|
38
|
-
progname,
|
39
|
-
formatted_message
|
40
|
-
true
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# Use logger created by #create_simple_logger to log concurrent-ruby messages.
|
45
|
-
def self.use_simple_logger(level = Logger::FATAL, output = $stderr)
|
46
|
-
Concurrent.global_logger = create_simple_logger level, output
|
47
|
-
end
|
48
|
-
|
49
|
-
# @return [Logger] Logger with provided level and output.
|
50
|
-
# @deprecated
|
51
|
-
def self.create_stdlib_logger(level = Logger::FATAL, output = $stderr)
|
52
|
-
logger = Logger.new(output)
|
53
|
-
logger.level = level
|
54
|
-
logger.formatter = lambda do |severity, datetime, progname, msg|
|
55
|
-
formatted_message = case msg
|
56
|
-
when String
|
57
|
-
msg
|
58
|
-
when Exception
|
59
|
-
format "%s (%s)\n%s",
|
60
|
-
msg.message, msg.class, (msg.backtrace || []).join("\n")
|
61
|
-
else
|
62
|
-
msg.inspect
|
63
|
-
end
|
64
|
-
format "[%s] %5s -- %s: %s\n",
|
65
|
-
datetime.strftime('%Y-%m-%d %H:%M:%S.%L'),
|
66
|
-
severity,
|
67
|
-
progname,
|
68
|
-
formatted_message
|
69
|
-
end
|
70
|
-
|
71
|
-
lambda do |loglevel, progname, message = nil, &block|
|
72
|
-
logger.add loglevel, message, progname, &block
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# Use logger created by #create_stdlib_logger to log concurrent-ruby messages.
|
77
|
-
# @deprecated
|
78
|
-
def self.use_stdlib_logger(level = Logger::FATAL, output = $stderr)
|
79
|
-
Concurrent.global_logger = create_stdlib_logger level, output
|
80
|
-
end
|
81
|
-
|
82
|
-
# TODO (pitr-ch 27-Dec-2016): remove deadlocking stdlib_logger methods
|
83
|
-
|
84
|
-
# Suppresses all output when used for logging.
|
85
|
-
NULL_LOGGER = lambda { |level, progname, message = nil, &block| }
|
86
|
-
|
87
|
-
# @!visibility private
|
88
|
-
GLOBAL_LOGGER = AtomicReference.new(create_simple_logger(Logger::WARN))
|
89
|
-
private_constant :GLOBAL_LOGGER
|
90
|
-
|
91
|
-
def self.global_logger
|
92
|
-
GLOBAL_LOGGER.value
|
93
|
-
end
|
94
|
-
|
95
|
-
def self.global_logger=(value)
|
96
|
-
GLOBAL_LOGGER.value = value
|
97
|
-
end
|
98
|
-
|
99
|
-
# @!visibility private
|
100
|
-
GLOBAL_FAST_EXECUTOR = Delay.new { Concurrent.new_fast_executor(auto_terminate: true) }
|
101
|
-
private_constant :GLOBAL_FAST_EXECUTOR
|
102
|
-
|
103
|
-
# @!visibility private
|
104
|
-
GLOBAL_IO_EXECUTOR = Delay.new { Concurrent.new_io_executor(auto_terminate: true) }
|
105
|
-
private_constant :GLOBAL_IO_EXECUTOR
|
106
|
-
|
107
|
-
# @!visibility private
|
108
|
-
GLOBAL_TIMER_SET = Delay.new { TimerSet.new(auto_terminate: true) }
|
109
|
-
private_constant :GLOBAL_TIMER_SET
|
110
|
-
|
111
|
-
# @!visibility private
|
112
|
-
GLOBAL_IMMEDIATE_EXECUTOR = ImmediateExecutor.new
|
113
|
-
private_constant :GLOBAL_IMMEDIATE_EXECUTOR
|
114
|
-
|
115
|
-
# Disables AtExit handlers including pool auto-termination handlers.
|
116
|
-
# When disabled it will be the application programmer's responsibility
|
117
|
-
# to ensure that the handlers are shutdown properly prior to application
|
118
|
-
# exit by calling {AtExit.run} method.
|
119
|
-
#
|
120
|
-
# @note this option should be needed only because of `at_exit` ordering
|
121
|
-
# issues which may arise when running some of the testing frameworks.
|
122
|
-
# E.g. Minitest's test-suite runs itself in `at_exit` callback which
|
123
|
-
# executes after the pools are already terminated. Then auto termination
|
124
|
-
# needs to be disabled and called manually after test-suite ends.
|
125
|
-
# @note This method should *never* be called
|
126
|
-
# from within a gem. It should *only* be used from within the main
|
127
|
-
# application and even then it should be used only when necessary.
|
128
|
-
# @see AtExit
|
129
|
-
def self.disable_at_exit_handlers!
|
130
|
-
AtExit.enabled = false
|
131
|
-
end
|
132
|
-
|
133
|
-
# Global thread pool optimized for short, fast *operations*.
|
134
|
-
#
|
135
|
-
# @return [ThreadPoolExecutor] the thread pool
|
136
|
-
def self.global_fast_executor
|
137
|
-
GLOBAL_FAST_EXECUTOR.value
|
138
|
-
end
|
139
|
-
|
140
|
-
# Global thread pool optimized for long, blocking (IO) *tasks*.
|
141
|
-
#
|
142
|
-
# @return [ThreadPoolExecutor] the thread pool
|
143
|
-
def self.global_io_executor
|
144
|
-
GLOBAL_IO_EXECUTOR.value
|
145
|
-
end
|
146
|
-
|
147
|
-
def self.global_immediate_executor
|
148
|
-
GLOBAL_IMMEDIATE_EXECUTOR
|
149
|
-
end
|
150
|
-
|
151
|
-
# Global thread pool user for global *timers*.
|
152
|
-
#
|
153
|
-
# @return [Concurrent::TimerSet] the thread pool
|
154
|
-
def self.global_timer_set
|
155
|
-
GLOBAL_TIMER_SET.value
|
156
|
-
end
|
157
|
-
|
158
|
-
# General access point to global executors.
|
159
|
-
# @param [Symbol, Executor] executor_identifier symbols:
|
160
|
-
# - :fast - {Concurrent.global_fast_executor}
|
161
|
-
# - :io - {Concurrent.global_io_executor}
|
162
|
-
# - :immediate - {Concurrent.global_immediate_executor}
|
163
|
-
# @return [Executor]
|
164
|
-
def self.executor(executor_identifier)
|
165
|
-
Options.executor(executor_identifier)
|
166
|
-
end
|
167
|
-
|
168
|
-
def self.new_fast_executor(opts = {})
|
169
|
-
FixedThreadPool.new(
|
170
|
-
[2, Concurrent.processor_count].max,
|
171
|
-
auto_terminate: opts.fetch(:auto_terminate, true),
|
172
|
-
idletime: 60, # 1 minute
|
173
|
-
max_queue: 0, # unlimited
|
174
|
-
fallback_policy: :abort # shouldn't matter -- 0 max queue
|
175
|
-
)
|
176
|
-
end
|
177
|
-
|
178
|
-
def self.new_io_executor(opts = {})
|
179
|
-
CachedThreadPool.new(
|
180
|
-
auto_terminate: opts.fetch(:auto_terminate, true),
|
181
|
-
fallback_policy: :abort # shouldn't matter -- 0 max queue
|
182
|
-
)
|
183
|
-
end
|
184
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
module Concurrent
|
2
|
-
module Synchronization
|
3
|
-
|
4
|
-
if Concurrent.on_jruby? && Concurrent.java_extensions_loaded?
|
5
|
-
|
6
|
-
# @!visibility private
|
7
|
-
module JRubyAttrVolatile
|
8
|
-
def self.included(base)
|
9
|
-
base.extend(ClassMethods)
|
10
|
-
end
|
11
|
-
|
12
|
-
module ClassMethods
|
13
|
-
def attr_volatile(*names)
|
14
|
-
names.each do |name|
|
15
|
-
|
16
|
-
ivar = :"@volatile_#{name}"
|
17
|
-
|
18
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
19
|
-
def #{name}
|
20
|
-
instance_variable_get_volatile(:#{ivar})
|
21
|
-
end
|
22
|
-
|
23
|
-
def #{name}=(value)
|
24
|
-
instance_variable_set_volatile(:#{ivar}, value)
|
25
|
-
end
|
26
|
-
RUBY
|
27
|
-
|
28
|
-
end
|
29
|
-
names.map { |n| [n, :"#{n}="] }.flatten
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# @!visibility private
|
35
|
-
# @!macro internal_implementation_note
|
36
|
-
class JRubyObject < AbstractObject
|
37
|
-
include JRubyAttrVolatile
|
38
|
-
|
39
|
-
def initialize
|
40
|
-
# nothing to do
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
module Concurrent
|
2
|
-
module Synchronization
|
3
|
-
|
4
|
-
# @!visibility private
|
5
|
-
module MriAttrVolatile
|
6
|
-
def self.included(base)
|
7
|
-
base.extend(ClassMethods)
|
8
|
-
end
|
9
|
-
|
10
|
-
module ClassMethods
|
11
|
-
def attr_volatile(*names)
|
12
|
-
names.each do |name|
|
13
|
-
ivar = :"@volatile_#{name}"
|
14
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
15
|
-
def #{name}
|
16
|
-
#{ivar}
|
17
|
-
end
|
18
|
-
|
19
|
-
def #{name}=(value)
|
20
|
-
#{ivar} = value
|
21
|
-
end
|
22
|
-
RUBY
|
23
|
-
end
|
24
|
-
names.map { |n| [n, :"#{n}="] }.flatten
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def full_memory_barrier
|
29
|
-
# relying on undocumented behavior of CRuby, GVL acquire has lock which ensures visibility of ivars
|
30
|
-
# https://github.com/ruby/ruby/blob/ruby_2_2/thread_pthread.c#L204-L211
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# @!visibility private
|
35
|
-
# @!macro internal_implementation_note
|
36
|
-
class MriObject < AbstractObject
|
37
|
-
include MriAttrVolatile
|
38
|
-
|
39
|
-
def initialize
|
40
|
-
# nothing to do
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,65 +0,0 @@
|
|
1
|
-
module Concurrent
|
2
|
-
module Synchronization
|
3
|
-
|
4
|
-
# @!visibility private
|
5
|
-
# @!macro internal_implementation_note
|
6
|
-
class RbxLockableObject < AbstractLockableObject
|
7
|
-
safe_initialization!
|
8
|
-
|
9
|
-
def initialize(*defaults)
|
10
|
-
super(*defaults)
|
11
|
-
@__Waiters__ = []
|
12
|
-
@__owner__ = nil
|
13
|
-
end
|
14
|
-
|
15
|
-
protected
|
16
|
-
|
17
|
-
def synchronize(&block)
|
18
|
-
if @__owner__ == Thread.current
|
19
|
-
yield
|
20
|
-
else
|
21
|
-
result = nil
|
22
|
-
Rubinius.synchronize(self) do
|
23
|
-
begin
|
24
|
-
@__owner__ = Thread.current
|
25
|
-
result = yield
|
26
|
-
ensure
|
27
|
-
@__owner__ = nil
|
28
|
-
end
|
29
|
-
end
|
30
|
-
result
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def ns_wait(timeout = nil)
|
35
|
-
wchan = Rubinius::Channel.new
|
36
|
-
|
37
|
-
begin
|
38
|
-
@__Waiters__.push wchan
|
39
|
-
Rubinius.unlock(self)
|
40
|
-
signaled = wchan.receive_timeout timeout
|
41
|
-
ensure
|
42
|
-
Rubinius.lock(self)
|
43
|
-
|
44
|
-
if !signaled && !@__Waiters__.delete(wchan)
|
45
|
-
# we timed out, but got signaled afterwards,
|
46
|
-
# so pass that signal on to the next waiter
|
47
|
-
@__Waiters__.shift << true unless @__Waiters__.empty?
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
self
|
52
|
-
end
|
53
|
-
|
54
|
-
def ns_signal
|
55
|
-
@__Waiters__.shift << true unless @__Waiters__.empty?
|
56
|
-
self
|
57
|
-
end
|
58
|
-
|
59
|
-
def ns_broadcast
|
60
|
-
@__Waiters__.shift << true until @__Waiters__.empty?
|
61
|
-
self
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
module Concurrent
|
2
|
-
module Synchronization
|
3
|
-
|
4
|
-
# @!visibility private
|
5
|
-
module RbxAttrVolatile
|
6
|
-
def self.included(base)
|
7
|
-
base.extend(ClassMethods)
|
8
|
-
end
|
9
|
-
|
10
|
-
module ClassMethods
|
11
|
-
|
12
|
-
def attr_volatile(*names)
|
13
|
-
names.each do |name|
|
14
|
-
ivar = :"@volatile_#{name}"
|
15
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
16
|
-
def #{name}
|
17
|
-
Rubinius.memory_barrier
|
18
|
-
#{ivar}
|
19
|
-
end
|
20
|
-
|
21
|
-
def #{name}=(value)
|
22
|
-
#{ivar} = value
|
23
|
-
Rubinius.memory_barrier
|
24
|
-
end
|
25
|
-
RUBY
|
26
|
-
end
|
27
|
-
names.map { |n| [n, :"#{n}="] }.flatten
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
def full_memory_barrier
|
33
|
-
# Rubinius instance variables are not volatile so we need to insert barrier
|
34
|
-
# TODO (pitr 26-Nov-2015): check comments like ^
|
35
|
-
Rubinius.memory_barrier
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
# @!visibility private
|
40
|
-
# @!macro internal_implementation_note
|
41
|
-
class RbxObject < AbstractObject
|
42
|
-
include RbxAttrVolatile
|
43
|
-
|
44
|
-
def initialize
|
45
|
-
# nothing to do
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|