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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -1
  3. data/lib/concurrent/agent.rb +5 -1
  4. data/lib/concurrent/async.rb +77 -38
  5. data/lib/concurrent/atom.rb +2 -1
  6. data/lib/concurrent/atomic/atomic_boolean.rb +1 -1
  7. data/lib/concurrent/atomic/atomic_fixnum.rb +1 -1
  8. data/lib/concurrent/atomic/atomic_reference.rb +1 -1
  9. data/lib/concurrent/atomic/semaphore.rb +1 -1
  10. data/lib/concurrent/atomic_reference/jruby+truffle.rb +1 -0
  11. data/lib/concurrent/atomic_reference/jruby.rb +1 -1
  12. data/lib/concurrent/atomic_reference/ruby.rb +1 -1
  13. data/lib/concurrent/concern/dereferenceable.rb +9 -24
  14. data/lib/concurrent/concern/obligation.rb +11 -8
  15. data/lib/concurrent/delay.rb +1 -1
  16. data/lib/concurrent/exchanger.rb +30 -17
  17. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +6 -1
  18. data/lib/concurrent/ivar.rb +1 -1
  19. data/lib/concurrent/lazy_register.rb +11 -8
  20. data/lib/concurrent/map.rb +1 -1
  21. data/lib/concurrent/maybe.rb +6 -3
  22. data/lib/concurrent/mvar.rb +26 -2
  23. data/lib/concurrent/promise.rb +1 -1
  24. data/lib/concurrent/synchronization.rb +3 -0
  25. data/lib/concurrent/synchronization/abstract_lockable_object.rb +1 -20
  26. data/lib/concurrent/synchronization/abstract_object.rb +1 -27
  27. data/lib/concurrent/synchronization/jruby_object.rb +26 -18
  28. data/lib/concurrent/synchronization/lockable_object.rb +29 -16
  29. data/lib/concurrent/synchronization/mri_object.rb +27 -19
  30. data/lib/concurrent/synchronization/object.rb +48 -53
  31. data/lib/concurrent/synchronization/rbx_lockable_object.rb +9 -8
  32. data/lib/concurrent/synchronization/rbx_object.rb +29 -21
  33. data/lib/concurrent/synchronization/volatile.rb +34 -0
  34. data/lib/concurrent/timer_task.rb +0 -1
  35. data/lib/concurrent/tvar.rb +3 -1
  36. data/lib/concurrent/utility/engine.rb +4 -0
  37. data/lib/concurrent/utility/native_extension_loader.rb +6 -3
  38. data/lib/concurrent/version.rb +2 -2
  39. data/lib/concurrent_ruby_ext.jar +0 -0
  40. 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 defined? JRubyLockableObject
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
- # TODO (pitr 12-Sep-2015): make private for c-r, prohibit subclassing
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
- # @!visibility private
5
- # @!macro internal_implementation_note
6
- class MriObject < AbstractObject
4
+ module MriAttrVolatile
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
7
8
 
8
- def initialize
9
- # nothing to do
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
- def self.attr_volatile(*names)
18
- names.each do |name|
19
- ivar = :"@volatile_#{name}"
20
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
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
- def #{name}=(value)
26
- #{ivar} = value
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 defined? JRubyObject
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
- # TODO fix documentation
20
- # @!macro [attach] synchronization_object
21
- #
22
- # Safe synchronization under any Ruby implementation.
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
- # Initializes default volatile fields with cas if any.
51
- # @param [Array<Object>] defaults values for fields, in same order as they are defined
52
- def initialize(*defaults)
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 safly, does not have to be synchronized
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.ensure_ivar_visibility! if 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
- (defined?(@safe_initialization) && @safe_initialization) || (superclass.respond_to?(:safe_initialization?) && superclass.safe_initialization?)
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
- # TODO documentation
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 = :"@VolatileCas_#{name}"
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.map { |n| [n, :"#{n}=", :"swap_#{n}", :"compare_and_set_#{n}"] }.flatten
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 initialize_volatile_cas_fields(defaults)
142
- self.class.volatile_cas_fields.zip(defaults) do |name, default|
143
- instance_variable_set :"@VolatileCas_#{name}", AtomicReference.new(default)
144
- end
145
- nil
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
- # @!method ensure_ivar_visibility!
149
- # @!macro synchronization_object_method_ensure_ivar_visibility
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
- Rubinius.lock(self)
22
- begin
23
- @__owner__ = Thread.current
24
- result = yield
25
- ensure
26
- @__owner__ = nil
27
- Rubinius.unlock(self)
28
- result
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
- # @!visibility private
6
- # @!macro internal_implementation_note
7
- class RbxObject < AbstractObject
8
- def initialize
9
- # nothing to do
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
- def self.attr_volatile *names
18
- names.each do |name|
19
- ivar = :"@volatile_#{name}"
20
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
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
- def #{name}=(value)
27
- #{ivar} = value
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
@@ -271,7 +271,6 @@ module Concurrent
271
271
  private
272
272
 
273
273
  def ns_initialize(opts, &task)
274
- init_mutex(self)
275
274
  set_deref_options(opts)
276
275
 
277
276
  self.execution_interval = opts[:execution] || opts[:execution_interval] || EXECUTION_INTERVAL
@@ -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)