concurrent-ruby 1.0.5 → 1.1.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +42 -0
- data/Gemfile +39 -0
- data/{LICENSE.txt → LICENSE.md} +2 -0
- data/README.md +203 -105
- data/Rakefile +278 -0
- data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +159 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +304 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
- data/lib/concurrent-ruby.rb +1 -0
- data/lib/concurrent.rb +24 -20
- data/lib/concurrent/agent.rb +7 -7
- data/lib/concurrent/array.rb +59 -32
- data/lib/concurrent/async.rb +4 -4
- data/lib/concurrent/atom.rb +9 -9
- data/lib/concurrent/atomic/atomic_boolean.rb +24 -20
- data/lib/concurrent/atomic/atomic_fixnum.rb +27 -23
- data/lib/concurrent/atomic/atomic_markable_reference.rb +164 -0
- data/lib/concurrent/atomic/atomic_reference.rb +176 -33
- data/lib/concurrent/atomic/count_down_latch.rb +6 -6
- data/lib/concurrent/atomic/cyclic_barrier.rb +1 -1
- data/lib/concurrent/atomic/event.rb +1 -1
- data/lib/concurrent/atomic/java_count_down_latch.rb +6 -5
- data/lib/concurrent/atomic/mutex_count_down_latch.rb +1 -0
- data/lib/concurrent/atomic/read_write_lock.rb +2 -1
- data/lib/concurrent/atomic/reentrant_read_write_lock.rb +3 -1
- data/lib/concurrent/atomic/semaphore.rb +8 -8
- data/lib/concurrent/atomic/thread_local_var.rb +7 -7
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +3 -8
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +1 -1
- data/lib/concurrent/atomics.rb +0 -43
- data/lib/concurrent/collection/lock_free_stack.rb +127 -0
- data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +3 -3
- data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +1 -2
- data/lib/concurrent/collection/non_concurrent_priority_queue.rb +29 -29
- data/lib/concurrent/concern/dereferenceable.rb +1 -1
- data/lib/concurrent/concern/logging.rb +6 -1
- data/lib/concurrent/concern/observable.rb +7 -7
- data/lib/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent/configuration.rb +1 -6
- data/lib/concurrent/constants.rb +1 -1
- data/lib/concurrent/dataflow.rb +2 -1
- data/lib/concurrent/delay.rb +9 -7
- data/lib/concurrent/exchanger.rb +13 -21
- data/lib/concurrent/executor/abstract_executor_service.rb +2 -2
- data/lib/concurrent/executor/cached_thread_pool.rb +1 -1
- data/lib/concurrent/executor/executor_service.rb +15 -15
- data/lib/concurrent/executor/fixed_thread_pool.rb +18 -18
- data/lib/concurrent/executor/java_thread_pool_executor.rb +10 -7
- data/lib/concurrent/executor/single_thread_executor.rb +2 -2
- data/lib/concurrent/executor/thread_pool_executor.rb +6 -6
- data/lib/concurrent/executor/timer_set.rb +1 -1
- data/lib/concurrent/future.rb +4 -1
- data/lib/concurrent/hash.rb +53 -30
- data/lib/concurrent/ivar.rb +5 -6
- data/lib/concurrent/map.rb +20 -25
- data/lib/concurrent/maybe.rb +1 -1
- data/lib/concurrent/mutable_struct.rb +15 -14
- data/lib/concurrent/mvar.rb +2 -2
- data/lib/concurrent/promise.rb +53 -21
- data/lib/concurrent/promises.rb +1938 -0
- data/lib/concurrent/re_include.rb +58 -0
- data/lib/concurrent/set.rb +66 -0
- data/lib/concurrent/settable_struct.rb +1 -0
- data/lib/concurrent/synchronization.rb +4 -5
- data/lib/concurrent/synchronization/abstract_lockable_object.rb +5 -5
- data/lib/concurrent/synchronization/abstract_struct.rb +6 -4
- data/lib/concurrent/synchronization/lockable_object.rb +6 -6
- data/lib/concurrent/synchronization/{mri_lockable_object.rb → mutex_lockable_object.rb} +19 -14
- data/lib/concurrent/synchronization/object.rb +8 -4
- data/lib/concurrent/synchronization/truffleruby_object.rb +46 -0
- data/lib/concurrent/synchronization/volatile.rb +11 -9
- data/lib/concurrent/thread_safe/util/data_structures.rb +55 -0
- data/lib/concurrent/thread_safe/util/striped64.rb +9 -4
- data/lib/concurrent/timer_task.rb +5 -2
- data/lib/concurrent/tuple.rb +1 -1
- data/lib/concurrent/tvar.rb +2 -2
- data/lib/concurrent/utility/at_exit.rb +1 -1
- data/lib/concurrent/utility/engine.rb +2 -2
- data/lib/concurrent/utility/monotonic_time.rb +3 -3
- data/lib/concurrent/utility/native_extension_loader.rb +31 -33
- data/lib/concurrent/utility/processor_counter.rb +0 -2
- data/lib/concurrent/version.rb +2 -2
- metadata +35 -21
- data/lib/concurrent/atomic_reference/concurrent_update_error.rb +0 -8
- data/lib/concurrent/atomic_reference/direct_update.rb +0 -81
- data/lib/concurrent/atomic_reference/jruby+truffle.rb +0 -2
- data/lib/concurrent/atomic_reference/jruby.rb +0 -16
- data/lib/concurrent/atomic_reference/rbx.rb +0 -22
- data/lib/concurrent/atomic_reference/ruby.rb +0 -32
- data/lib/concurrent/edge.rb +0 -26
- data/lib/concurrent/lazy_register.rb +0 -81
- data/lib/concurrent/synchronization/truffle_lockable_object.rb +0 -9
- data/lib/concurrent/synchronization/truffle_object.rb +0 -31
- data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +0 -30
@@ -0,0 +1,58 @@
|
|
1
|
+
module Concurrent
|
2
|
+
|
3
|
+
# Methods form module A included to a module B, which is already included into class C,
|
4
|
+
# will not be visible in the C class. If this module is extended to B then A's methods
|
5
|
+
# are correctly made visible to C.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# module A
|
9
|
+
# def a
|
10
|
+
# :a
|
11
|
+
# end
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# module B1
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# class C1
|
18
|
+
# include B1
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# module B2
|
22
|
+
# extend Concurrent::ReInclude
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# class C2
|
26
|
+
# include B2
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# B1.send :include, A
|
30
|
+
# B2.send :include, A
|
31
|
+
#
|
32
|
+
# C1.new.respond_to? :a # => false
|
33
|
+
# C2.new.respond_to? :a # => true
|
34
|
+
module ReInclude
|
35
|
+
# @!visibility private
|
36
|
+
def included(base)
|
37
|
+
(@re_include_to_bases ||= []) << [:include, base]
|
38
|
+
super(base)
|
39
|
+
end
|
40
|
+
|
41
|
+
# @!visibility private
|
42
|
+
def extended(base)
|
43
|
+
(@re_include_to_bases ||= []) << [:extend, base]
|
44
|
+
super(base)
|
45
|
+
end
|
46
|
+
|
47
|
+
# @!visibility private
|
48
|
+
def include(*modules)
|
49
|
+
result = super(*modules)
|
50
|
+
modules.reverse.each do |module_being_included|
|
51
|
+
(@re_include_to_bases ||= []).each do |method, mod|
|
52
|
+
mod.send method, module_being_included
|
53
|
+
end
|
54
|
+
end
|
55
|
+
result
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'concurrent/utility/engine'
|
2
|
+
require 'concurrent/thread_safe/util'
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module Concurrent
|
6
|
+
|
7
|
+
# @!macro concurrent_set
|
8
|
+
#
|
9
|
+
# A thread-safe subclass of Set. This version locks against the object
|
10
|
+
# itself for every method call, ensuring only one thread can be reading
|
11
|
+
# or writing at a time. This includes iteration methods like `#each`.
|
12
|
+
#
|
13
|
+
# @note `a += b` is **not** a **thread-safe** operation on
|
14
|
+
# `Concurrent::Set`. It reads Set `a`, then it creates new `Concurrent::Set`
|
15
|
+
# which is union of `a` and `b`, then it writes the union to `a`.
|
16
|
+
# The read and write are independent operations they do not form a single atomic
|
17
|
+
# operation therefore when two `+=` operations are executed concurrently updates
|
18
|
+
# may be lost. Use `#merge` instead.
|
19
|
+
#
|
20
|
+
# @see http://ruby-doc.org/stdlib-2.4.0/libdoc/set/rdoc/Set.html Ruby standard library `Set`
|
21
|
+
|
22
|
+
|
23
|
+
# @!macro internal_implementation_note
|
24
|
+
SetImplementation = case
|
25
|
+
when Concurrent.on_cruby?
|
26
|
+
# Because MRI never runs code in parallel, the existing
|
27
|
+
# non-thread-safe structures should usually work fine.
|
28
|
+
::Set
|
29
|
+
|
30
|
+
when Concurrent.on_jruby?
|
31
|
+
require 'jruby/synchronized'
|
32
|
+
|
33
|
+
class JRubySet < ::Set
|
34
|
+
include JRuby::Synchronized
|
35
|
+
end
|
36
|
+
JRubySet
|
37
|
+
|
38
|
+
when Concurrent.on_rbx?
|
39
|
+
require 'monitor'
|
40
|
+
require 'concurrent/thread_safe/util/data_structures'
|
41
|
+
|
42
|
+
class RbxSet < ::Set
|
43
|
+
end
|
44
|
+
ThreadSafe::Util.make_synchronized_on_rbx Concurrent::Set
|
45
|
+
RbxSet
|
46
|
+
|
47
|
+
when Concurrent.on_truffleruby?
|
48
|
+
require 'concurrent/thread_safe/util/data_structures'
|
49
|
+
|
50
|
+
class TruffleRubySet < ::Set
|
51
|
+
end
|
52
|
+
|
53
|
+
ThreadSafe::Util.make_synchronized_on_truffleruby Concurrent::Set
|
54
|
+
TruffleRubySet
|
55
|
+
|
56
|
+
else
|
57
|
+
warn 'Possibly unsupported Ruby implementation'
|
58
|
+
::Set
|
59
|
+
end
|
60
|
+
private_constant :SetImplementation
|
61
|
+
|
62
|
+
# @!macro concurrent_set
|
63
|
+
class Set < SetImplementation
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
@@ -107,6 +107,7 @@ module Concurrent
|
|
107
107
|
synchronize do
|
108
108
|
clazz = Synchronization::AbstractStruct.define_struct_class(SettableStruct, Synchronization::LockableObject, name, members, &block)
|
109
109
|
members.each_with_index do |member, index|
|
110
|
+
clazz.send :remove_method, member if clazz.instance_methods.include? member
|
110
111
|
clazz.send(:define_method, member) do
|
111
112
|
synchronize { @values[index] }
|
112
113
|
end
|
@@ -7,15 +7,14 @@ Concurrent.load_native_extensions
|
|
7
7
|
require 'concurrent/synchronization/mri_object'
|
8
8
|
require 'concurrent/synchronization/jruby_object'
|
9
9
|
require 'concurrent/synchronization/rbx_object'
|
10
|
-
require 'concurrent/synchronization/
|
10
|
+
require 'concurrent/synchronization/truffleruby_object'
|
11
11
|
require 'concurrent/synchronization/object'
|
12
12
|
require 'concurrent/synchronization/volatile'
|
13
13
|
|
14
14
|
require 'concurrent/synchronization/abstract_lockable_object'
|
15
|
-
require 'concurrent/synchronization/
|
15
|
+
require 'concurrent/synchronization/mutex_lockable_object'
|
16
16
|
require 'concurrent/synchronization/jruby_lockable_object'
|
17
17
|
require 'concurrent/synchronization/rbx_lockable_object'
|
18
|
-
require 'concurrent/synchronization/truffle_lockable_object'
|
19
18
|
|
20
19
|
require 'concurrent/synchronization/lockable_object'
|
21
20
|
|
@@ -23,8 +22,8 @@ require 'concurrent/synchronization/condition'
|
|
23
22
|
require 'concurrent/synchronization/lock'
|
24
23
|
|
25
24
|
module Concurrent
|
26
|
-
# {include:file:
|
27
|
-
# {include:file:
|
25
|
+
# {include:file:docs-source/synchronization.md}
|
26
|
+
# {include:file:docs-source/synchronization-notes.md}
|
28
27
|
module Synchronization
|
29
28
|
end
|
30
29
|
end
|
@@ -6,7 +6,7 @@ module Concurrent
|
|
6
6
|
|
7
7
|
protected
|
8
8
|
|
9
|
-
# @!macro
|
9
|
+
# @!macro synchronization_object_method_synchronize
|
10
10
|
#
|
11
11
|
# @yield runs the block synchronized against this object,
|
12
12
|
# equivalent of java's `synchronize(this) {}`
|
@@ -15,7 +15,7 @@ module Concurrent
|
|
15
15
|
raise NotImplementedError
|
16
16
|
end
|
17
17
|
|
18
|
-
# @!macro
|
18
|
+
# @!macro synchronization_object_method_ns_wait_until
|
19
19
|
#
|
20
20
|
# Wait until condition is met or timeout passes,
|
21
21
|
# protects against spurious wake-ups.
|
@@ -45,7 +45,7 @@ module Concurrent
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
# @!macro
|
48
|
+
# @!macro synchronization_object_method_ns_wait
|
49
49
|
#
|
50
50
|
# Wait until another thread calls #signal or #broadcast,
|
51
51
|
# spurious wake-ups can happen.
|
@@ -63,7 +63,7 @@ module Concurrent
|
|
63
63
|
raise NotImplementedError
|
64
64
|
end
|
65
65
|
|
66
|
-
# @!macro
|
66
|
+
# @!macro synchronization_object_method_ns_signal
|
67
67
|
#
|
68
68
|
# Signal one waiting thread.
|
69
69
|
# @return [self]
|
@@ -78,7 +78,7 @@ module Concurrent
|
|
78
78
|
raise NotImplementedError
|
79
79
|
end
|
80
80
|
|
81
|
-
# @!macro
|
81
|
+
# @!macro synchronization_object_method_ns_broadcast
|
82
82
|
#
|
83
83
|
# Broadcast to all waiting threads.
|
84
84
|
# @return [self]
|
@@ -11,7 +11,7 @@ module Concurrent
|
|
11
11
|
ns_initialize(*values)
|
12
12
|
end
|
13
13
|
|
14
|
-
# @!macro
|
14
|
+
# @!macro struct_length
|
15
15
|
#
|
16
16
|
# Returns the number of struct members.
|
17
17
|
#
|
@@ -21,7 +21,7 @@ module Concurrent
|
|
21
21
|
end
|
22
22
|
alias_method :size, :length
|
23
23
|
|
24
|
-
# @!macro
|
24
|
+
# @!macro struct_members
|
25
25
|
#
|
26
26
|
# Returns the struct members as an array of symbols.
|
27
27
|
#
|
@@ -117,7 +117,7 @@ module Concurrent
|
|
117
117
|
|
118
118
|
# @!visibility private
|
119
119
|
def pr_underscore(clazz)
|
120
|
-
word = clazz.to_s
|
120
|
+
word = clazz.to_s.dup # dup string to workaround JRuby 9.2.0.0 bug https://github.com/jruby/jruby/issues/5229
|
121
121
|
word.gsub!(/::/, '/')
|
122
122
|
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
123
123
|
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
@@ -138,13 +138,15 @@ module Concurrent
|
|
138
138
|
end
|
139
139
|
unless name.nil?
|
140
140
|
begin
|
141
|
+
parent.send :remove_const, name if parent.const_defined? name
|
141
142
|
parent.const_set(name, clazz)
|
142
|
-
|
143
|
+
clazz
|
143
144
|
rescue NameError
|
144
145
|
raise NameError.new("identifier #{name} needs to be constant")
|
145
146
|
end
|
146
147
|
end
|
147
148
|
members.each_with_index do |member, index|
|
149
|
+
clazz.send :remove_method, member if clazz.instance_methods.include? member
|
148
150
|
clazz.send(:define_method, member) do
|
149
151
|
@values[index]
|
150
152
|
end
|
@@ -5,18 +5,18 @@ module Concurrent
|
|
5
5
|
# @!macro internal_implementation_note
|
6
6
|
LockableObjectImplementation = case
|
7
7
|
when Concurrent.on_cruby? && Concurrent.ruby_version(:<=, 1, 9, 3)
|
8
|
-
|
8
|
+
MonitorLockableObject
|
9
9
|
when Concurrent.on_cruby? && Concurrent.ruby_version(:>, 1, 9, 3)
|
10
|
-
|
10
|
+
MutexLockableObject
|
11
11
|
when Concurrent.on_jruby?
|
12
12
|
JRubyLockableObject
|
13
13
|
when Concurrent.on_rbx?
|
14
14
|
RbxLockableObject
|
15
|
-
when Concurrent.
|
16
|
-
|
15
|
+
when Concurrent.on_truffleruby?
|
16
|
+
MutexLockableObject
|
17
17
|
else
|
18
18
|
warn 'Possibly unsupported Ruby implementation'
|
19
|
-
|
19
|
+
MonitorLockableObject
|
20
20
|
end
|
21
21
|
private_constant :LockableObjectImplementation
|
22
22
|
|
@@ -31,7 +31,7 @@ module Concurrent
|
|
31
31
|
# `Thread#sleep` and `Thread#wakeup` will work as expected but mixing `Synchronization::Object#wait` and
|
32
32
|
# `Thread#wakeup` will not work on all platforms.
|
33
33
|
#
|
34
|
-
# @see
|
34
|
+
# @see Event implementation as an example of this class use
|
35
35
|
#
|
36
36
|
# @example simple
|
37
37
|
# class AnClass < Synchronization::Object
|
@@ -1,18 +1,19 @@
|
|
1
1
|
module Concurrent
|
2
|
+
# noinspection RubyInstanceVariableNamingConvention
|
2
3
|
module Synchronization
|
3
4
|
|
4
5
|
# @!visibility private
|
5
6
|
# @!macro internal_implementation_note
|
6
|
-
|
7
|
+
module ConditionSignalling
|
7
8
|
protected
|
8
9
|
|
9
10
|
def ns_signal
|
10
|
-
@
|
11
|
+
@__Condition__.signal
|
11
12
|
self
|
12
13
|
end
|
13
14
|
|
14
15
|
def ns_broadcast
|
15
|
-
@
|
16
|
+
@__Condition__.broadcast
|
16
17
|
self
|
17
18
|
end
|
18
19
|
end
|
@@ -20,50 +21,54 @@ module Concurrent
|
|
20
21
|
|
21
22
|
# @!visibility private
|
22
23
|
# @!macro internal_implementation_note
|
23
|
-
class
|
24
|
+
class MutexLockableObject < AbstractLockableObject
|
25
|
+
include ConditionSignalling
|
26
|
+
|
24
27
|
safe_initialization!
|
25
28
|
|
26
29
|
def initialize(*defaults)
|
27
30
|
super(*defaults)
|
28
|
-
@
|
29
|
-
@
|
31
|
+
@__Lock__ = ::Mutex.new
|
32
|
+
@__Condition__ = ::ConditionVariable.new
|
30
33
|
end
|
31
34
|
|
32
35
|
protected
|
33
36
|
|
34
37
|
def synchronize
|
35
|
-
if @
|
38
|
+
if @__Lock__.owned?
|
36
39
|
yield
|
37
40
|
else
|
38
|
-
@
|
41
|
+
@__Lock__.synchronize { yield }
|
39
42
|
end
|
40
43
|
end
|
41
44
|
|
42
45
|
def ns_wait(timeout = nil)
|
43
|
-
@
|
46
|
+
@__Condition__.wait @__Lock__, timeout
|
44
47
|
self
|
45
48
|
end
|
46
49
|
end
|
47
50
|
|
48
51
|
# @!visibility private
|
49
52
|
# @!macro internal_implementation_note
|
50
|
-
class
|
53
|
+
class MonitorLockableObject < AbstractLockableObject
|
54
|
+
include ConditionSignalling
|
55
|
+
|
51
56
|
safe_initialization!
|
52
57
|
|
53
58
|
def initialize(*defaults)
|
54
59
|
super(*defaults)
|
55
|
-
@
|
56
|
-
@
|
60
|
+
@__Lock__ = ::Monitor.new
|
61
|
+
@__Condition__ = @__Lock__.new_cond
|
57
62
|
end
|
58
63
|
|
59
64
|
protected
|
60
65
|
|
61
66
|
def synchronize # TODO may be a problem with lock.synchronize { lock.wait }
|
62
|
-
@
|
67
|
+
@__Lock__.synchronize { yield }
|
63
68
|
end
|
64
69
|
|
65
70
|
def ns_wait(timeout = nil)
|
66
|
-
@
|
71
|
+
@__Condition__.wait timeout
|
67
72
|
self
|
68
73
|
end
|
69
74
|
end
|
@@ -10,9 +10,10 @@ module Concurrent
|
|
10
10
|
JRubyObject
|
11
11
|
when Concurrent.on_rbx?
|
12
12
|
RbxObject
|
13
|
-
when Concurrent.
|
14
|
-
|
13
|
+
when Concurrent.on_truffleruby?
|
14
|
+
TruffleRubyObject
|
15
15
|
else
|
16
|
+
warn 'Possibly unsupported Ruby implementation'
|
16
17
|
MriObject
|
17
18
|
end
|
18
19
|
private_constant :ObjectImplementation
|
@@ -134,8 +135,11 @@ module Concurrent
|
|
134
135
|
private
|
135
136
|
|
136
137
|
def self.define_initialize_volatile_with_cas
|
137
|
-
assignments = @volatile_cas_fields.map
|
138
|
-
|
138
|
+
assignments = @volatile_cas_fields.map do |name|
|
139
|
+
"@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }} = Concurrent::AtomicReference.new(nil)"
|
140
|
+
end.join("\n")
|
141
|
+
|
142
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
139
143
|
def initialize_volatile_with_cas
|
140
144
|
super
|
141
145
|
#{assignments}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Concurrent
|
2
|
+
module Synchronization
|
3
|
+
|
4
|
+
module TruffleRubyAttrVolatile
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def attr_volatile(*names)
|
11
|
+
names.each do |name|
|
12
|
+
ivar = :"@volatile_#{name}"
|
13
|
+
|
14
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
15
|
+
def #{name}
|
16
|
+
full_memory_barrier
|
17
|
+
#{ivar}
|
18
|
+
end
|
19
|
+
|
20
|
+
def #{name}=(value)
|
21
|
+
#{ivar} = value
|
22
|
+
full_memory_barrier
|
23
|
+
end
|
24
|
+
RUBY
|
25
|
+
end
|
26
|
+
|
27
|
+
names.map { |n| [n, :"#{n}="] }.flatten
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def full_memory_barrier
|
32
|
+
TruffleRuby.full_memory_barrier
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# @!visibility private
|
37
|
+
# @!macro internal_implementation_note
|
38
|
+
class TruffleRubyObject < AbstractObject
|
39
|
+
include TruffleRubyAttrVolatile
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
# nothing to do
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -21,14 +21,16 @@ module Concurrent
|
|
21
21
|
# => 2
|
22
22
|
|
23
23
|
Volatile = case
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
24
|
+
when Concurrent.on_cruby?
|
25
|
+
MriAttrVolatile
|
26
|
+
when Concurrent.on_jruby?
|
27
|
+
JRubyAttrVolatile
|
28
|
+
when Concurrent.on_rbx?
|
29
|
+
RbxAttrVolatile
|
30
|
+
when Concurrent.on_truffleruby?
|
31
|
+
TruffleRubyAttrVolatile
|
32
|
+
else
|
33
|
+
MriAttrVolatile
|
34
|
+
end
|
33
35
|
end
|
34
36
|
end
|