concurrent-ruby 1.0.0.pre4-java → 1.0.0.pre5-java
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 +11 -1
- data/lib/concurrent/agent.rb +5 -1
- data/lib/concurrent/async.rb +77 -38
- data/lib/concurrent/atom.rb +2 -1
- data/lib/concurrent/atomic/atomic_boolean.rb +1 -1
- data/lib/concurrent/atomic/atomic_fixnum.rb +1 -1
- data/lib/concurrent/atomic/atomic_reference.rb +1 -1
- data/lib/concurrent/atomic/semaphore.rb +1 -1
- data/lib/concurrent/atomic_reference/jruby+truffle.rb +1 -0
- data/lib/concurrent/atomic_reference/jruby.rb +1 -1
- data/lib/concurrent/atomic_reference/ruby.rb +1 -1
- data/lib/concurrent/concern/dereferenceable.rb +9 -24
- data/lib/concurrent/concern/obligation.rb +11 -8
- data/lib/concurrent/delay.rb +1 -1
- data/lib/concurrent/exchanger.rb +30 -17
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +6 -1
- data/lib/concurrent/ivar.rb +1 -1
- data/lib/concurrent/lazy_register.rb +11 -8
- data/lib/concurrent/map.rb +1 -1
- data/lib/concurrent/maybe.rb +6 -3
- data/lib/concurrent/mvar.rb +26 -2
- data/lib/concurrent/promise.rb +1 -1
- data/lib/concurrent/synchronization.rb +3 -0
- data/lib/concurrent/synchronization/abstract_lockable_object.rb +1 -20
- data/lib/concurrent/synchronization/abstract_object.rb +1 -27
- data/lib/concurrent/synchronization/jruby_object.rb +26 -18
- data/lib/concurrent/synchronization/lockable_object.rb +29 -16
- data/lib/concurrent/synchronization/mri_object.rb +27 -19
- data/lib/concurrent/synchronization/object.rb +48 -53
- data/lib/concurrent/synchronization/rbx_lockable_object.rb +9 -8
- data/lib/concurrent/synchronization/rbx_object.rb +29 -21
- data/lib/concurrent/synchronization/volatile.rb +34 -0
- data/lib/concurrent/timer_task.rb +0 -1
- data/lib/concurrent/tvar.rb +3 -1
- data/lib/concurrent/utility/engine.rb +4 -0
- data/lib/concurrent/utility/native_extension_loader.rb +6 -3
- data/lib/concurrent/version.rb +2 -2
- data/lib/concurrent_ruby_ext.jar +0 -0
- metadata +7 -5
@@ -8,9 +8,9 @@ module Concurrent
|
|
8
8
|
MriMonitorLockableObject
|
9
9
|
when Concurrent.on_cruby? && Concurrent.ruby_version(:>, 1, 9, 3)
|
10
10
|
MriMutexLockableObject
|
11
|
-
when
|
11
|
+
when Concurrent.on_jruby?
|
12
12
|
JRubyLockableObject
|
13
|
-
when Concurrent.on_rbx?
|
13
|
+
when Concurrent.on_rbx? || Concurrent.on_truffle?
|
14
14
|
RbxLockableObject
|
15
15
|
else
|
16
16
|
warn 'Possibly unsupported Ruby implementation'
|
@@ -18,20 +18,36 @@ module Concurrent
|
|
18
18
|
end
|
19
19
|
private_constant :LockableObjectImplementation
|
20
20
|
|
21
|
-
#
|
21
|
+
# Safe synchronization under any Ruby implementation.
|
22
|
+
# It provides methods like {#synchronize}, {#wait}, {#signal} and {#broadcast}.
|
23
|
+
# Provides a single layer which can improve its implementation over time without changes needed to
|
24
|
+
# the classes using it. Use {Synchronization::Object} not this abstract class.
|
25
|
+
#
|
26
|
+
# @note this object does not support usage together with
|
27
|
+
# [`Thread#wakeup`](http://ruby-doc.org/core-2.2.0/Thread.html#method-i-wakeup)
|
28
|
+
# and [`Thread#raise`](http://ruby-doc.org/core-2.2.0/Thread.html#method-i-raise).
|
29
|
+
# `Thread#sleep` and `Thread#wakeup` will work as expected but mixing `Synchronization::Object#wait` and
|
30
|
+
# `Thread#wakeup` will not work on all platforms.
|
31
|
+
#
|
32
|
+
# @see {Event} implementation as an example of this class use
|
33
|
+
#
|
34
|
+
# @example simple
|
35
|
+
# class AnClass < Synchronization::Object
|
36
|
+
# def initialize
|
37
|
+
# super
|
38
|
+
# synchronize { @value = 'asd' }
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# def value
|
42
|
+
# synchronize { @value }
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# @!visibility private
|
22
47
|
class LockableObject < LockableObjectImplementation
|
23
48
|
|
49
|
+
# TODO (pitr 12-Sep-2015): make private for c-r, prohibit subclassing
|
24
50
|
# TODO (pitr 12-Sep-2015): we inherit too much ourselves :/
|
25
|
-
def self.allow_only_direct_descendants!
|
26
|
-
this = self
|
27
|
-
singleton_class.send :define_method, :inherited do |child|
|
28
|
-
# super child
|
29
|
-
|
30
|
-
if child.superclass != this
|
31
|
-
warn "all children of #{this} are final, subclassing is not supported use composition."
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
51
|
|
36
52
|
# @!method initialize(*args, &block)
|
37
53
|
# @!macro synchronization_object_method_initialize
|
@@ -39,9 +55,6 @@ module Concurrent
|
|
39
55
|
# @!method synchronize
|
40
56
|
# @!macro synchronization_object_method_synchronize
|
41
57
|
|
42
|
-
# @!method initialize(*args, &block)
|
43
|
-
# @!macro synchronization_object_method_ns_initialize
|
44
|
-
|
45
58
|
# @!method wait_until(timeout = nil, &condition)
|
46
59
|
# @!macro synchronization_object_method_ns_wait_until
|
47
60
|
|
@@ -1,35 +1,43 @@
|
|
1
1
|
module Concurrent
|
2
2
|
module Synchronization
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
module MriAttrVolatile
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
module ClassMethods
|
10
|
+
def attr_volatile(*names)
|
11
|
+
names.each do |name|
|
12
|
+
ivar = :"@volatile_#{name}"
|
13
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
14
|
+
def #{name}
|
15
|
+
#{ivar}
|
16
|
+
end
|
17
|
+
|
18
|
+
def #{name}=(value)
|
19
|
+
#{ivar} = value
|
20
|
+
end
|
21
|
+
RUBY
|
22
|
+
end
|
23
|
+
names.map { |n| [n, :"#{n}="] }.flatten
|
24
|
+
end
|
10
25
|
end
|
11
26
|
|
12
27
|
def full_memory_barrier
|
13
28
|
# relying on undocumented behavior of CRuby, GVL acquire has lock which ensures visibility of ivars
|
14
29
|
# https://github.com/ruby/ruby/blob/ruby_2_2/thread_pthread.c#L204-L211
|
15
30
|
end
|
31
|
+
end
|
16
32
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
def #{name}
|
22
|
-
#{ivar}
|
23
|
-
end
|
33
|
+
# @!visibility private
|
34
|
+
# @!macro internal_implementation_note
|
35
|
+
class MriObject < AbstractObject
|
36
|
+
include MriAttrVolatile
|
24
37
|
|
25
|
-
|
26
|
-
|
27
|
-
end
|
28
|
-
RUBY
|
29
|
-
end
|
30
|
-
names.map { |n| [n, :"#{n}="] }.flatten
|
38
|
+
def initialize
|
39
|
+
# nothing to do
|
31
40
|
end
|
32
41
|
end
|
33
|
-
|
34
42
|
end
|
35
43
|
end
|
@@ -6,52 +6,32 @@ module Concurrent
|
|
6
6
|
ObjectImplementation = case
|
7
7
|
when Concurrent.on_cruby?
|
8
8
|
MriObject
|
9
|
-
when
|
9
|
+
when Concurrent.on_jruby?
|
10
10
|
JRubyObject
|
11
|
-
when Concurrent.on_rbx?
|
11
|
+
when Concurrent.on_rbx? || Concurrent.on_truffle?
|
12
12
|
RbxObject
|
13
13
|
else
|
14
|
-
warn 'Possibly unsupported Ruby implementation'
|
15
14
|
MriObject
|
16
15
|
end
|
17
16
|
private_constant :ObjectImplementation
|
18
17
|
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
# It provides methods like {#synchronize}, {#wait}, {#signal} and {#broadcast}.
|
24
|
-
# Provides a single layer which can improve its implementation over time without changes needed to
|
25
|
-
# the classes using it. Use {Synchronization::Object} not this abstract class.
|
26
|
-
#
|
27
|
-
# @note this object does not support usage together with
|
28
|
-
# [`Thread#wakeup`](http://ruby-doc.org/core-2.2.0/Thread.html#method-i-wakeup)
|
29
|
-
# and [`Thread#raise`](http://ruby-doc.org/core-2.2.0/Thread.html#method-i-raise).
|
30
|
-
# `Thread#sleep` and `Thread#wakeup` will work as expected but mixing `Synchronization::Object#wait` and
|
31
|
-
# `Thread#wakeup` will not work on all platforms.
|
32
|
-
#
|
33
|
-
# @see {Event} implementation as an example of this class use
|
34
|
-
#
|
35
|
-
# @example simple
|
36
|
-
# class AnClass < Synchronization::Object
|
37
|
-
# def initialize
|
38
|
-
# super
|
39
|
-
# synchronize { @value = 'asd' }
|
40
|
-
# end
|
41
|
-
#
|
42
|
-
# def value
|
43
|
-
# synchronize { @value }
|
44
|
-
# end
|
45
|
-
# end
|
46
|
-
#
|
18
|
+
# Abstract object providing final, volatile, ans CAS extensions to build other concurrent abstractions.
|
19
|
+
# - final instance variables see {Object.safe_initialization!}
|
20
|
+
# - volatile instance variables see {Object.attr_volatile}
|
21
|
+
# - volatile instance variables see {Object.attr_volatile_with_cas}
|
47
22
|
class Object < ObjectImplementation
|
48
23
|
|
24
|
+
# @!method self.attr_volatile(*names)
|
25
|
+
# Creates methods for reading and writing (as `attr_accessor` does) to a instance variable with
|
26
|
+
# volatile (Java) semantic. The instance variable should be accessed oly through generated methods.
|
27
|
+
#
|
28
|
+
# @param [Array<Symbol>] names of the instance variables to be volatile
|
29
|
+
# @return [Array<Symbol>] names of defined method names
|
30
|
+
|
49
31
|
# Has to be called by children.
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
super()
|
54
|
-
initialize_volatile_cas_fields(defaults)
|
32
|
+
def initialize
|
33
|
+
super
|
34
|
+
initialize_volatile_with_cas
|
55
35
|
end
|
56
36
|
|
57
37
|
# By calling this method on a class, it and all its children are marked to be constructed safely. Meaning that
|
@@ -62,7 +42,7 @@ module Concurrent
|
|
62
42
|
# safe_initialization!
|
63
43
|
#
|
64
44
|
# def initialize
|
65
|
-
# @AFinalValue = 'value' # published
|
45
|
+
# @AFinalValue = 'value' # published safely, does not have to be synchronized
|
66
46
|
# end
|
67
47
|
# end
|
68
48
|
def self.safe_initialization!
|
@@ -72,17 +52,20 @@ module Concurrent
|
|
72
52
|
def self.new(*)
|
73
53
|
object = super
|
74
54
|
ensure
|
75
|
-
object.
|
55
|
+
object.full_memory_barrier if object
|
76
56
|
end
|
77
57
|
|
78
58
|
@safe_initialization = true
|
79
59
|
end
|
80
60
|
|
61
|
+
# @return [true, false] if this class is safely initialized.
|
81
62
|
def self.safe_initialization?
|
82
|
-
|
63
|
+
@safe_initialization = false unless defined? @safe_initialization
|
64
|
+
@safe_initialization || (superclass.respond_to?(:safe_initialization?) && superclass.safe_initialization?)
|
83
65
|
end
|
84
66
|
|
85
|
-
# For testing purposes, quite slow.
|
67
|
+
# For testing purposes, quite slow. Injects assert code to new method which will raise if class instance contains
|
68
|
+
# any instance variables with CamelCase names and isn't {.safe_initialization?}.
|
86
69
|
def self.ensure_safe_initialization_when_final_fields_are_present
|
87
70
|
Object.class_eval do
|
88
71
|
def self.new(*)
|
@@ -96,14 +79,22 @@ module Concurrent
|
|
96
79
|
end
|
97
80
|
end
|
98
81
|
|
99
|
-
#
|
82
|
+
# Creates methods for reading and writing to a instance variable with
|
83
|
+
# volatile (Java) semantic as {.attr_volatile} does.
|
84
|
+
# The instance variable should be accessed oly through generated methods.
|
85
|
+
# This method generates following methods: `value`, `value=(new_value) #=> new_value`,
|
86
|
+
# `swap_value(new_value) #=> old_value`,
|
87
|
+
# `compare_and_set_value(expected, value) #=> true || false`, `update_value(&block)`.
|
88
|
+
# @param [Array<Symbol>] names of the instance variables to be volatile with CAS.
|
89
|
+
# @return [Array<Symbol>] names of defined method names.
|
100
90
|
def self.attr_volatile_with_cas(*names)
|
101
91
|
@volatile_cas_fields ||= []
|
102
92
|
@volatile_cas_fields += names
|
103
93
|
safe_initialization!
|
94
|
+
define_initialize_volatile_with_cas
|
104
95
|
|
105
96
|
names.each do |name|
|
106
|
-
ivar = :"@
|
97
|
+
ivar = :"@VolatileCas#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }}"
|
107
98
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
108
99
|
def #{name}
|
109
100
|
#{ivar}.get
|
@@ -126,11 +117,12 @@ module Concurrent
|
|
126
117
|
end
|
127
118
|
RUBY
|
128
119
|
end
|
129
|
-
names.
|
120
|
+
names.flat_map { |n| [n, :"#{n}=", :"swap_#{n}", :"compare_and_set_#{n}", :"update_#{n}"] }
|
130
121
|
end
|
131
122
|
|
123
|
+
# @param [true,false] inherited should inherited volatile with CAS fields be returned?
|
124
|
+
# @return [Array<Symbol>] Returns defined volatile with CAS fields on this class.
|
132
125
|
def self.volatile_cas_fields(inherited = true)
|
133
|
-
# TODO (pitr 11-Sep-2015): maybe use constant for better optimisation on Truffle since it will not speculate on ivar being final
|
134
126
|
@volatile_cas_fields ||= []
|
135
127
|
((superclass.volatile_cas_fields if superclass.respond_to?(:volatile_cas_fields) && inherited) || []) +
|
136
128
|
@volatile_cas_fields
|
@@ -138,18 +130,21 @@ module Concurrent
|
|
138
130
|
|
139
131
|
private
|
140
132
|
|
141
|
-
def
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
133
|
+
def self.define_initialize_volatile_with_cas
|
134
|
+
assignments = @volatile_cas_fields.map { |name| "@VolatileCas#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }} = AtomicReference.new(nil)" }.join("\n")
|
135
|
+
class_eval <<-RUBY
|
136
|
+
def initialize_volatile_with_cas
|
137
|
+
super
|
138
|
+
#{assignments}
|
139
|
+
end
|
140
|
+
RUBY
|
146
141
|
end
|
147
142
|
|
148
|
-
|
149
|
-
|
143
|
+
private_class_method :define_initialize_volatile_with_cas
|
144
|
+
|
145
|
+
def initialize_volatile_with_cas
|
146
|
+
end
|
150
147
|
|
151
|
-
# @!method self.attr_volatile(*names)
|
152
|
-
# @!macro synchronization_object_method_self_attr_volatile
|
153
148
|
end
|
154
149
|
end
|
155
150
|
end
|
@@ -18,15 +18,16 @@ module Concurrent
|
|
18
18
|
if @__owner__ == Thread.current
|
19
19
|
yield
|
20
20
|
else
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
29
|
end
|
30
|
+
result
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
@@ -1,37 +1,45 @@
|
|
1
1
|
module Concurrent
|
2
2
|
module Synchronization
|
3
3
|
|
4
|
+
module RbxAttrVolatile
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
4
8
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
9
|
+
module ClassMethods
|
10
|
+
def attr_volatile(*names)
|
11
|
+
names.each do |name|
|
12
|
+
ivar = :"@volatile_#{name}"
|
13
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
14
|
+
def #{name}
|
15
|
+
Rubinius.memory_barrier
|
16
|
+
#{ivar}
|
17
|
+
end
|
18
|
+
|
19
|
+
def #{name}=(value)
|
20
|
+
#{ivar} = value
|
21
|
+
Rubinius.memory_barrier
|
22
|
+
end
|
23
|
+
RUBY
|
24
|
+
end
|
25
|
+
names.map { |n| [n, :"#{n}="] }.flatten
|
26
|
+
end
|
10
27
|
end
|
11
28
|
|
12
29
|
def full_memory_barrier
|
13
30
|
# Rubinius instance variables are not volatile so we need to insert barrier
|
14
31
|
Rubinius.memory_barrier
|
15
32
|
end
|
33
|
+
end
|
16
34
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
def #{name}
|
22
|
-
Rubinius.memory_barrier
|
23
|
-
#{ivar}
|
24
|
-
end
|
35
|
+
# @!visibility private
|
36
|
+
# @!macro internal_implementation_note
|
37
|
+
class RbxObject < AbstractObject
|
38
|
+
include RbxAttrVolatile
|
25
39
|
|
26
|
-
|
27
|
-
|
28
|
-
Rubinius.memory_barrier
|
29
|
-
end
|
30
|
-
RUBY
|
31
|
-
end
|
32
|
-
names.map { |n| [n, :"#{n}="] }.flatten
|
40
|
+
def initialize
|
41
|
+
# nothing to do
|
33
42
|
end
|
34
43
|
end
|
35
|
-
|
36
44
|
end
|
37
45
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Concurrent
|
2
|
+
module Synchronization
|
3
|
+
|
4
|
+
# Volatile adds the attr_volatile class method when included.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# class Foo
|
8
|
+
# include Concurrent::Synchronization::Volatile
|
9
|
+
#
|
10
|
+
# attr_volatile :bar
|
11
|
+
#
|
12
|
+
# def initialize
|
13
|
+
# self.bar = 1
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# foo = Foo.new
|
18
|
+
# foo.bar
|
19
|
+
# => 1
|
20
|
+
# foo.bar = 2
|
21
|
+
# => 2
|
22
|
+
|
23
|
+
Volatile = case
|
24
|
+
when Concurrent.on_cruby?
|
25
|
+
MriAttrVolatile
|
26
|
+
when Concurrent.on_jruby?
|
27
|
+
JRubyAttrVolatile
|
28
|
+
when Concurrent.on_rbx? || Concurrent.on_truffle?
|
29
|
+
RbxAttrVolatile
|
30
|
+
else
|
31
|
+
MriAttrVolatile
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/concurrent/tvar.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'set'
|
2
|
+
require 'concurrent/synchronization'
|
2
3
|
|
3
4
|
module Concurrent
|
4
5
|
|
@@ -8,7 +9,8 @@ module Concurrent
|
|
8
9
|
# @!macro thread_safe_variable_comparison
|
9
10
|
#
|
10
11
|
# {include:file:doc/tvar.md}
|
11
|
-
class TVar
|
12
|
+
class TVar < Synchronization::Object
|
13
|
+
safe_initialization!
|
12
14
|
|
13
15
|
# Create a new `TVar` with an initial value.
|
14
16
|
def initialize(value)
|