concurrent-ruby 1.1.8 → 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 +45 -0
- data/Gemfile +2 -8
- data/README.md +49 -28
- data/Rakefile +66 -81
- 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-ruby/concurrent/agent.rb +2 -1
- data/lib/concurrent-ruby/concurrent/array.rb +0 -10
- data/lib/concurrent-ruby/concurrent/async.rb +1 -0
- data/lib/concurrent-ruby/concurrent/atom.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +5 -4
- data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +5 -4
- data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +3 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +82 -151
- data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/event.rb +3 -3
- data/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb +109 -0
- data/lib/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-ruby/concurrent/atomic/mutex_atomic_boolean.rb +11 -5
- data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +11 -5
- data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +19 -3
- data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +2 -1
- data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +9 -9
- data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +32 -14
- data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +96 -89
- data/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb +37 -0
- data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +15 -4
- data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +1 -1
- data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +1 -1
- data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +2 -0
- data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +2 -2
- data/lib/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-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +11 -1
- data/lib/concurrent-ruby/concurrent/concern/logging.rb +86 -2
- data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent-ruby/concurrent/configuration.rb +4 -87
- data/lib/concurrent-ruby/concurrent/delay.rb +2 -2
- data/lib/concurrent-ruby/concurrent/errors.rb +5 -0
- data/lib/concurrent-ruby/concurrent/exchanger.rb +1 -0
- data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +17 -14
- data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +13 -3
- data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +3 -3
- data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +4 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +10 -4
- data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +26 -37
- data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +6 -6
- data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +1 -1
- data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +4 -1
- data/lib/concurrent-ruby/concurrent/hash.rb +0 -9
- data/lib/concurrent-ruby/concurrent/immutable_struct.rb +1 -1
- data/lib/concurrent-ruby/concurrent/ivar.rb +2 -1
- data/lib/concurrent-ruby/concurrent/map.rb +43 -30
- data/lib/concurrent-ruby/concurrent/maybe.rb +1 -1
- data/lib/concurrent-ruby/concurrent/mutable_struct.rb +1 -1
- data/lib/concurrent-ruby/concurrent/mvar.rb +1 -1
- data/lib/concurrent-ruby/concurrent/promise.rb +2 -1
- data/lib/concurrent-ruby/concurrent/promises.rb +7 -6
- data/lib/concurrent-ruby/concurrent/re_include.rb +2 -0
- data/lib/concurrent-ruby/concurrent/scheduled_task.rb +30 -17
- data/lib/concurrent-ruby/concurrent/set.rb +12 -14
- data/lib/concurrent-ruby/concurrent/settable_struct.rb +2 -2
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +5 -1
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +1 -3
- data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +2 -0
- data/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb +29 -0
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +3 -1
- data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +2 -0
- data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +6 -5
- data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +18 -5
- data/lib/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 +77 -12
- data/lib/concurrent-ruby/concurrent/synchronization.rb +1 -18
- data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +36 -39
- data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +2 -39
- data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +16 -27
- data/lib/concurrent-ruby/concurrent/timer_task.rb +11 -33
- data/lib/concurrent-ruby/concurrent/tuple.rb +1 -5
- data/lib/concurrent-ruby/concurrent/tvar.rb +22 -61
- data/lib/concurrent-ruby/concurrent/utility/engine.rb +5 -16
- data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +7 -46
- data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +8 -10
- data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +1 -0
- data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +36 -89
- data/lib/concurrent-ruby/concurrent/version.rb +1 -1
- data/lib/concurrent-ruby/concurrent-ruby.rb +5 -1
- metadata +11 -12
- data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +0 -66
- data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +0 -37
- data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +0 -181
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +0 -45
- data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +0 -44
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +0 -65
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +0 -49
- data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +0 -47
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: concurrent-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jerry D'Antonio
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2023-02-24 00:00:00.000000000 Z
|
14
14
|
dependencies: []
|
15
15
|
description: |
|
16
16
|
Modern concurrency tools including agents, futures, promises, thread pools, actors, supervisors, and more.
|
@@ -49,7 +49,6 @@ files:
|
|
49
49
|
- lib/concurrent-ruby/concurrent/array.rb
|
50
50
|
- lib/concurrent-ruby/concurrent/async.rb
|
51
51
|
- lib/concurrent-ruby/concurrent/atom.rb
|
52
|
-
- lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb
|
53
52
|
- lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb
|
54
53
|
- lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb
|
55
54
|
- lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb
|
@@ -57,17 +56,19 @@ files:
|
|
57
56
|
- lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb
|
58
57
|
- lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb
|
59
58
|
- lib/concurrent-ruby/concurrent/atomic/event.rb
|
59
|
+
- lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb
|
60
60
|
- lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb
|
61
|
-
- lib/concurrent-ruby/concurrent/atomic/
|
61
|
+
- lib/concurrent-ruby/concurrent/atomic/locals.rb
|
62
|
+
- lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb
|
62
63
|
- lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb
|
63
64
|
- lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb
|
64
65
|
- lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb
|
65
66
|
- lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb
|
66
67
|
- lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb
|
67
68
|
- lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb
|
68
|
-
- lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb
|
69
69
|
- lib/concurrent-ruby/concurrent/atomic/semaphore.rb
|
70
70
|
- lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb
|
71
|
+
- lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb
|
71
72
|
- lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb
|
72
73
|
- lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb
|
73
74
|
- lib/concurrent-ruby/concurrent/atomics.rb
|
@@ -79,6 +80,7 @@ files:
|
|
79
80
|
- lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb
|
80
81
|
- lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb
|
81
82
|
- lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb
|
83
|
+
- lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb
|
82
84
|
- lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb
|
83
85
|
- lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb
|
84
86
|
- lib/concurrent-ruby/concurrent/concern/deprecation.rb
|
@@ -134,16 +136,13 @@ files:
|
|
134
136
|
- lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb
|
135
137
|
- lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb
|
136
138
|
- lib/concurrent-ruby/concurrent/synchronization/condition.rb
|
139
|
+
- lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb
|
137
140
|
- lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb
|
138
|
-
- lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb
|
139
141
|
- lib/concurrent-ruby/concurrent/synchronization/lock.rb
|
140
142
|
- lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb
|
141
|
-
- lib/concurrent-ruby/concurrent/synchronization/mri_object.rb
|
142
143
|
- lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb
|
143
144
|
- lib/concurrent-ruby/concurrent/synchronization/object.rb
|
144
|
-
- lib/concurrent-ruby/concurrent/synchronization/
|
145
|
-
- lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb
|
146
|
-
- lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb
|
145
|
+
- lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb
|
147
146
|
- lib/concurrent-ruby/concurrent/synchronization/volatile.rb
|
148
147
|
- lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb
|
149
148
|
- lib/concurrent-ruby/concurrent/thread_safe/util.rb
|
@@ -177,14 +176,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
177
176
|
requirements:
|
178
177
|
- - ">="
|
179
178
|
- !ruby/object:Gem::Version
|
180
|
-
version:
|
179
|
+
version: '2.3'
|
181
180
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
181
|
requirements:
|
183
182
|
- - ">="
|
184
183
|
- !ruby/object:Gem::Version
|
185
184
|
version: '0'
|
186
185
|
requirements: []
|
187
|
-
rubygems_version: 3.
|
186
|
+
rubygems_version: 3.3.26
|
188
187
|
signing_key:
|
189
188
|
specification_version: 4
|
190
189
|
summary: Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell,
|
@@ -1,66 +0,0 @@
|
|
1
|
-
require 'concurrent/constants'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
# @!macro thread_local_var
|
6
|
-
# @!macro internal_implementation_note
|
7
|
-
# @!visibility private
|
8
|
-
class AbstractThreadLocalVar
|
9
|
-
|
10
|
-
# @!macro thread_local_var_method_initialize
|
11
|
-
def initialize(default = nil, &default_block)
|
12
|
-
if default && block_given?
|
13
|
-
raise ArgumentError, "Cannot use both value and block as default value"
|
14
|
-
end
|
15
|
-
|
16
|
-
if block_given?
|
17
|
-
@default_block = default_block
|
18
|
-
@default = nil
|
19
|
-
else
|
20
|
-
@default_block = nil
|
21
|
-
@default = default
|
22
|
-
end
|
23
|
-
|
24
|
-
allocate_storage
|
25
|
-
end
|
26
|
-
|
27
|
-
# @!macro thread_local_var_method_get
|
28
|
-
def value
|
29
|
-
raise NotImplementedError
|
30
|
-
end
|
31
|
-
|
32
|
-
# @!macro thread_local_var_method_set
|
33
|
-
def value=(value)
|
34
|
-
raise NotImplementedError
|
35
|
-
end
|
36
|
-
|
37
|
-
# @!macro thread_local_var_method_bind
|
38
|
-
def bind(value, &block)
|
39
|
-
if block_given?
|
40
|
-
old_value = self.value
|
41
|
-
begin
|
42
|
-
self.value = value
|
43
|
-
yield
|
44
|
-
ensure
|
45
|
-
self.value = old_value
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
protected
|
51
|
-
|
52
|
-
# @!visibility private
|
53
|
-
def allocate_storage
|
54
|
-
raise NotImplementedError
|
55
|
-
end
|
56
|
-
|
57
|
-
# @!visibility private
|
58
|
-
def default
|
59
|
-
if @default_block
|
60
|
-
self.value = @default_block.call
|
61
|
-
else
|
62
|
-
@default
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'concurrent/atomic/abstract_thread_local_var'
|
2
|
-
|
3
|
-
if Concurrent.on_jruby?
|
4
|
-
|
5
|
-
module Concurrent
|
6
|
-
|
7
|
-
# @!visibility private
|
8
|
-
# @!macro internal_implementation_note
|
9
|
-
class JavaThreadLocalVar < AbstractThreadLocalVar
|
10
|
-
|
11
|
-
# @!macro thread_local_var_method_get
|
12
|
-
def value
|
13
|
-
value = @var.get
|
14
|
-
|
15
|
-
if value.nil?
|
16
|
-
default
|
17
|
-
elsif value == NULL
|
18
|
-
nil
|
19
|
-
else
|
20
|
-
value
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
# @!macro thread_local_var_method_set
|
25
|
-
def value=(value)
|
26
|
-
@var.set(value)
|
27
|
-
end
|
28
|
-
|
29
|
-
protected
|
30
|
-
|
31
|
-
# @!visibility private
|
32
|
-
def allocate_storage
|
33
|
-
@var = java.lang.ThreadLocal.new
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,181 +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
|
-
FREE = []
|
32
|
-
LOCK = Mutex.new
|
33
|
-
THREAD_LOCAL_ARRAYS = {} # used as a hash set
|
34
|
-
|
35
|
-
# synchronize when not on MRI
|
36
|
-
# on MRI using lock in finalizer leads to "can't be called from trap context" error
|
37
|
-
# so the code is carefully written to be tread-safe on MRI relying on GIL
|
38
|
-
|
39
|
-
if Concurrent.on_cruby?
|
40
|
-
# @!visibility private
|
41
|
-
def self.semi_sync(&block)
|
42
|
-
block.call
|
43
|
-
end
|
44
|
-
else
|
45
|
-
# @!visibility private
|
46
|
-
def self.semi_sync(&block)
|
47
|
-
LOCK.synchronize(&block)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
private_constant :FREE, :LOCK, :THREAD_LOCAL_ARRAYS
|
52
|
-
|
53
|
-
# @!macro thread_local_var_method_get
|
54
|
-
def value
|
55
|
-
if (array = get_threadlocal_array)
|
56
|
-
value = array[@index]
|
57
|
-
if value.nil?
|
58
|
-
default
|
59
|
-
elsif value.equal?(NULL)
|
60
|
-
nil
|
61
|
-
else
|
62
|
-
value
|
63
|
-
end
|
64
|
-
else
|
65
|
-
default
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# @!macro thread_local_var_method_set
|
70
|
-
def value=(value)
|
71
|
-
me = Thread.current
|
72
|
-
# We could keep the thread-local arrays in a hash, keyed by Thread
|
73
|
-
# But why? That would require locking
|
74
|
-
# Using Ruby's built-in thread-local storage is faster
|
75
|
-
unless (array = get_threadlocal_array(me))
|
76
|
-
array = set_threadlocal_array([], me)
|
77
|
-
self.class.semi_sync { THREAD_LOCAL_ARRAYS[array.object_id] = array }
|
78
|
-
ObjectSpace.define_finalizer(me, self.class.thread_finalizer(array.object_id))
|
79
|
-
end
|
80
|
-
array[@index] = (value.nil? ? NULL : value)
|
81
|
-
value
|
82
|
-
end
|
83
|
-
|
84
|
-
protected
|
85
|
-
|
86
|
-
# @!visibility private
|
87
|
-
def allocate_storage
|
88
|
-
@index = FREE.pop || next_index
|
89
|
-
|
90
|
-
ObjectSpace.define_finalizer(self, self.class.thread_local_finalizer(@index))
|
91
|
-
end
|
92
|
-
|
93
|
-
# @!visibility private
|
94
|
-
def self.thread_local_finalizer(index)
|
95
|
-
proc do
|
96
|
-
semi_sync do
|
97
|
-
# The cost of GC'ing a TLV is linear in the number of threads using TLVs
|
98
|
-
# But that is natural! More threads means more storage is used per TLV
|
99
|
-
# So naturally more CPU time is required to free more storage
|
100
|
-
#
|
101
|
-
# DO NOT use each_value which might conflict with new pair assignment
|
102
|
-
# into the hash in #value= method
|
103
|
-
THREAD_LOCAL_ARRAYS.values.each { |array| array[index] = nil }
|
104
|
-
# free index has to be published after the arrays are cleared
|
105
|
-
FREE.push(index)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
# @!visibility private
|
111
|
-
def self.thread_finalizer(id)
|
112
|
-
proc do
|
113
|
-
semi_sync do
|
114
|
-
# The thread which used this thread-local array is now gone
|
115
|
-
# So don't hold onto a reference to the array (thus blocking GC)
|
116
|
-
THREAD_LOCAL_ARRAYS.delete(id)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
private
|
122
|
-
|
123
|
-
# noinspection RubyClassVariableUsageInspection
|
124
|
-
@@next = 0
|
125
|
-
# noinspection RubyClassVariableUsageInspection
|
126
|
-
def next_index
|
127
|
-
LOCK.synchronize do
|
128
|
-
result = @@next
|
129
|
-
@@next += 1
|
130
|
-
result
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
if Thread.instance_methods.include?(:thread_variable_get)
|
135
|
-
|
136
|
-
def get_threadlocal_array(thread = Thread.current)
|
137
|
-
thread.thread_variable_get(:__threadlocal_array__)
|
138
|
-
end
|
139
|
-
|
140
|
-
def set_threadlocal_array(array, thread = Thread.current)
|
141
|
-
thread.thread_variable_set(:__threadlocal_array__, array)
|
142
|
-
end
|
143
|
-
|
144
|
-
else
|
145
|
-
|
146
|
-
def get_threadlocal_array(thread = Thread.current)
|
147
|
-
thread[:__threadlocal_array__]
|
148
|
-
end
|
149
|
-
|
150
|
-
def set_threadlocal_array(array, thread = Thread.current)
|
151
|
-
thread[:__threadlocal_array__] = array
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
# This exists only for use in testing
|
156
|
-
# @!visibility private
|
157
|
-
def value_for(thread)
|
158
|
-
if (array = get_threadlocal_array(thread))
|
159
|
-
value = array[@index]
|
160
|
-
if value.nil?
|
161
|
-
get_default
|
162
|
-
elsif value.equal?(NULL)
|
163
|
-
nil
|
164
|
-
else
|
165
|
-
value
|
166
|
-
end
|
167
|
-
else
|
168
|
-
get_default
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
# @!visibility private
|
173
|
-
def get_default
|
174
|
-
if @default_block
|
175
|
-
raise "Cannot use default_for with default block"
|
176
|
-
else
|
177
|
-
@default
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
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
|
@@ -1,47 +0,0 @@
|
|
1
|
-
module Concurrent
|
2
|
-
module Synchronization
|
3
|
-
|
4
|
-
# @!visibility private
|
5
|
-
module TruffleRubyAttrVolatile
|
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
|
-
|
15
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
16
|
-
def #{name}
|
17
|
-
full_memory_barrier
|
18
|
-
#{ivar}
|
19
|
-
end
|
20
|
-
|
21
|
-
def #{name}=(value)
|
22
|
-
#{ivar} = value
|
23
|
-
full_memory_barrier
|
24
|
-
end
|
25
|
-
RUBY
|
26
|
-
end
|
27
|
-
|
28
|
-
names.map { |n| [n, :"#{n}="] }.flatten
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def full_memory_barrier
|
33
|
-
TruffleRuby.full_memory_barrier
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
# @!visibility private
|
38
|
-
# @!macro internal_implementation_note
|
39
|
-
class TruffleRubyObject < AbstractObject
|
40
|
-
include TruffleRubyAttrVolatile
|
41
|
-
|
42
|
-
def initialize
|
43
|
-
# nothing to do
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|