concurrent-ruby 1.0.5 → 1.1.1

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 (109) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +65 -0
  3. data/Gemfile +39 -0
  4. data/{LICENSE.txt → LICENSE.md} +2 -0
  5. data/README.md +207 -105
  6. data/Rakefile +314 -0
  7. data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
  9. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
  10. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
  11. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
  12. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +159 -0
  13. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +306 -0
  14. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
  15. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
  16. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
  17. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
  18. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
  19. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
  20. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
  21. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
  22. data/lib/concurrent/agent.rb +7 -7
  23. data/lib/concurrent/array.rb +59 -32
  24. data/lib/concurrent/async.rb +4 -4
  25. data/lib/concurrent/atom.rb +9 -9
  26. data/lib/concurrent/atomic/atomic_boolean.rb +24 -20
  27. data/lib/concurrent/atomic/atomic_fixnum.rb +27 -23
  28. data/lib/concurrent/atomic/atomic_markable_reference.rb +164 -0
  29. data/lib/concurrent/atomic/atomic_reference.rb +185 -32
  30. data/lib/concurrent/atomic/count_down_latch.rb +6 -6
  31. data/lib/concurrent/atomic/cyclic_barrier.rb +1 -1
  32. data/lib/concurrent/atomic/event.rb +1 -1
  33. data/lib/concurrent/atomic/java_count_down_latch.rb +9 -6
  34. data/lib/concurrent/atomic/mutex_atomic_boolean.rb +2 -0
  35. data/lib/concurrent/atomic/mutex_count_down_latch.rb +1 -0
  36. data/lib/concurrent/atomic/read_write_lock.rb +2 -1
  37. data/lib/concurrent/atomic/reentrant_read_write_lock.rb +3 -1
  38. data/lib/concurrent/atomic/semaphore.rb +8 -8
  39. data/lib/concurrent/atomic/thread_local_var.rb +7 -7
  40. data/lib/concurrent/atomic_reference/mutex_atomic.rb +3 -8
  41. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +1 -1
  42. data/lib/concurrent/atomics.rb +0 -43
  43. data/lib/concurrent/collection/lock_free_stack.rb +158 -0
  44. data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +3 -3
  45. data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +1 -2
  46. data/lib/concurrent/collection/non_concurrent_priority_queue.rb +29 -29
  47. data/lib/concurrent/concern/dereferenceable.rb +1 -1
  48. data/lib/concurrent/concern/logging.rb +6 -1
  49. data/lib/concurrent/concern/observable.rb +7 -7
  50. data/lib/concurrent/concurrent_ruby.jar +0 -0
  51. data/lib/concurrent/configuration.rb +1 -6
  52. data/lib/concurrent/constants.rb +1 -1
  53. data/lib/concurrent/dataflow.rb +2 -1
  54. data/lib/concurrent/delay.rb +9 -7
  55. data/lib/concurrent/exchanger.rb +21 -25
  56. data/lib/concurrent/executor/abstract_executor_service.rb +2 -2
  57. data/lib/concurrent/executor/cached_thread_pool.rb +1 -1
  58. data/lib/concurrent/executor/executor_service.rb +15 -15
  59. data/lib/concurrent/executor/fixed_thread_pool.rb +18 -18
  60. data/lib/concurrent/executor/java_thread_pool_executor.rb +10 -7
  61. data/lib/concurrent/executor/single_thread_executor.rb +2 -2
  62. data/lib/concurrent/executor/thread_pool_executor.rb +6 -6
  63. data/lib/concurrent/executor/timer_set.rb +1 -1
  64. data/lib/concurrent/future.rb +4 -1
  65. data/lib/concurrent/hash.rb +53 -30
  66. data/lib/concurrent/ivar.rb +5 -6
  67. data/lib/concurrent/map.rb +178 -81
  68. data/lib/concurrent/maybe.rb +1 -1
  69. data/lib/concurrent/mutable_struct.rb +15 -14
  70. data/lib/concurrent/mvar.rb +2 -2
  71. data/lib/concurrent/promise.rb +53 -21
  72. data/lib/concurrent/promises.rb +1936 -0
  73. data/lib/concurrent/re_include.rb +58 -0
  74. data/lib/concurrent/set.rb +66 -0
  75. data/lib/concurrent/settable_struct.rb +1 -0
  76. data/lib/concurrent/synchronization/abstract_lockable_object.rb +5 -5
  77. data/lib/concurrent/synchronization/abstract_struct.rb +6 -4
  78. data/lib/concurrent/synchronization/lockable_object.rb +6 -6
  79. data/lib/concurrent/synchronization/{mri_lockable_object.rb → mutex_lockable_object.rb} +19 -14
  80. data/lib/concurrent/synchronization/object.rb +8 -4
  81. data/lib/concurrent/synchronization/truffleruby_object.rb +46 -0
  82. data/lib/concurrent/synchronization/volatile.rb +11 -9
  83. data/lib/concurrent/synchronization.rb +4 -5
  84. data/lib/concurrent/thread_safe/util/data_structures.rb +63 -0
  85. data/lib/concurrent/thread_safe/util/striped64.rb +9 -4
  86. data/lib/concurrent/timer_task.rb +5 -2
  87. data/lib/concurrent/tuple.rb +1 -1
  88. data/lib/concurrent/tvar.rb +2 -2
  89. data/lib/concurrent/utility/193.rb +17 -0
  90. data/lib/concurrent/utility/at_exit.rb +1 -1
  91. data/lib/concurrent/utility/engine.rb +4 -4
  92. data/lib/concurrent/utility/monotonic_time.rb +3 -3
  93. data/lib/concurrent/utility/native_extension_loader.rb +31 -33
  94. data/lib/concurrent/utility/processor_counter.rb +0 -2
  95. data/lib/concurrent/version.rb +2 -2
  96. data/lib/concurrent-ruby.rb +1 -0
  97. data/lib/concurrent.rb +26 -20
  98. metadata +33 -18
  99. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +0 -8
  100. data/lib/concurrent/atomic_reference/direct_update.rb +0 -81
  101. data/lib/concurrent/atomic_reference/jruby+truffle.rb +0 -2
  102. data/lib/concurrent/atomic_reference/jruby.rb +0 -16
  103. data/lib/concurrent/atomic_reference/rbx.rb +0 -22
  104. data/lib/concurrent/atomic_reference/ruby.rb +0 -32
  105. data/lib/concurrent/edge.rb +0 -26
  106. data/lib/concurrent/lazy_register.rb +0 -81
  107. data/lib/concurrent/synchronization/truffle_lockable_object.rb +0 -9
  108. data/lib/concurrent/synchronization/truffle_object.rb +0 -31
  109. 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::RbxSet
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::TruffleRubySet
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
@@ -6,7 +6,7 @@ module Concurrent
6
6
 
7
7
  protected
8
8
 
9
- # @!macro [attach] synchronization_object_method_synchronize
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 [attach] synchronization_object_method_ns_wait_until
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 [attach] synchronization_object_method_ns_wait
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 [attach] synchronization_object_method_ns_signal
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 [attach] synchronization_object_method_ns_broadcast
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 [attach] struct_length
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 [attach] struct_members
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
- parent.const_get(name)
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
- MriMonitorLockableObject
8
+ MonitorLockableObject
9
9
  when Concurrent.on_cruby? && Concurrent.ruby_version(:>, 1, 9, 3)
10
- MriMutexLockableObject
10
+ MutexLockableObject
11
11
  when Concurrent.on_jruby?
12
12
  JRubyLockableObject
13
13
  when Concurrent.on_rbx?
14
14
  RbxLockableObject
15
- when Concurrent.on_truffle?
16
- MriMutexLockableObject
15
+ when Concurrent.on_truffleruby?
16
+ MutexLockableObject
17
17
  else
18
18
  warn 'Possibly unsupported Ruby implementation'
19
- MriMonitorLockableObject
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 {Event} implementation as an example of this class use
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
- class MriLockableObject < AbstractLockableObject
7
+ module ConditionSignalling
7
8
  protected
8
9
 
9
10
  def ns_signal
10
- @__condition__.signal
11
+ @__Condition__.signal
11
12
  self
12
13
  end
13
14
 
14
15
  def ns_broadcast
15
- @__condition__.broadcast
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 MriMutexLockableObject < MriLockableObject
24
+ class MutexLockableObject < AbstractLockableObject
25
+ include ConditionSignalling
26
+
24
27
  safe_initialization!
25
28
 
26
29
  def initialize(*defaults)
27
30
  super(*defaults)
28
- @__lock__ = ::Mutex.new
29
- @__condition__ = ::ConditionVariable.new
31
+ @__Lock__ = ::Mutex.new
32
+ @__Condition__ = ::ConditionVariable.new
30
33
  end
31
34
 
32
35
  protected
33
36
 
34
37
  def synchronize
35
- if @__lock__.owned?
38
+ if @__Lock__.owned?
36
39
  yield
37
40
  else
38
- @__lock__.synchronize { yield }
41
+ @__Lock__.synchronize { yield }
39
42
  end
40
43
  end
41
44
 
42
45
  def ns_wait(timeout = nil)
43
- @__condition__.wait @__lock__, timeout
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 MriMonitorLockableObject < MriLockableObject
53
+ class MonitorLockableObject < AbstractLockableObject
54
+ include ConditionSignalling
55
+
51
56
  safe_initialization!
52
57
 
53
58
  def initialize(*defaults)
54
59
  super(*defaults)
55
- @__lock__ = ::Monitor.new
56
- @__condition__ = @__lock__.new_cond
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
- @__lock__.synchronize { yield }
67
+ @__Lock__.synchronize { yield }
63
68
  end
64
69
 
65
70
  def ns_wait(timeout = nil)
66
- @__condition__.wait timeout
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.on_truffle?
14
- TruffleObject
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 { |name| "@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }} = AtomicReference.new(nil)" }.join("\n")
138
- class_eval <<-RUBY
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
- 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
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
@@ -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/truffle_object'
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/mri_lockable_object'
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:doc/synchronization.md}
27
- # {include:file:doc/synchronization-notes.md}
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
@@ -0,0 +1,63 @@
1
+ require 'concurrent/thread_safe/util'
2
+
3
+ # Shim for TruffleRuby.synchronized
4
+ if Concurrent.on_truffleruby? && !TruffleRuby.respond_to?(:synchronized)
5
+ module TruffleRuby
6
+ def self.synchronized(object, &block)
7
+ Truffle::System.synchronized(object, &block)
8
+ end
9
+ end
10
+ end
11
+
12
+ module Concurrent
13
+ module ThreadSafe
14
+ module Util
15
+ def self.make_synchronized_on_rbx(klass)
16
+ klass.class_eval do
17
+ private
18
+
19
+ def _mon_initialize
20
+ @_monitor = Monitor.new unless @_monitor # avoid double initialisation
21
+ end
22
+
23
+ def self.new(*args)
24
+ obj = super(*args)
25
+ obj.send(:_mon_initialize)
26
+ obj
27
+ end
28
+ end
29
+
30
+ klass.superclass.instance_methods(false).each do |method|
31
+ case method
32
+ when :new_range, :new_reserved
33
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
34
+ def #{method}(*args)
35
+ obj = super
36
+ obj.send(:_mon_initialize)
37
+ obj
38
+ end
39
+ RUBY
40
+ else
41
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
42
+ def #{method}(*args)
43
+ monitor = @_monitor
44
+ monitor or raise("BUG: Internal monitor was not properly initialized. Please report this to the concurrent-ruby developers.")
45
+ monitor.synchronize { super }
46
+ end
47
+ RUBY
48
+ end
49
+ end
50
+ end
51
+
52
+ def self.make_synchronized_on_truffleruby(klass)
53
+ klass.superclass.instance_methods(false).each do |method|
54
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
55
+ def #{method}(*args, &block)
56
+ TruffleRuby.synchronized(self) { super(*args, &block) }
57
+ end
58
+ RUBY
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -86,15 +86,20 @@ module Concurrent
86
86
  # @!visibility private
87
87
  class Cell < Concurrent::AtomicReference
88
88
 
89
- # TODO: this only adds padding after the :value slot, need to find a way to add padding before the slot
90
- # @!visibility private
91
- attr_reader *(12.times.collect{ |i| "padding_#{i}".to_sym })
92
-
93
89
  alias_method :cas, :compare_and_set
94
90
 
95
91
  def cas_computed
96
92
  cas(current_value = value, yield(current_value))
97
93
  end
94
+
95
+ # @!visibility private
96
+ def self.padding
97
+ # TODO: this only adds padding after the :value slot, need to find a way to add padding before the slot
98
+ # TODO (pitr-ch 28-Jul-2018): the padding instance vars may not be created
99
+ # hide from yardoc in a method
100
+ attr_reader *(12.times.collect{ |i| "padding_#{i}".to_sym })
101
+ end
102
+ padding
98
103
  end
99
104
 
100
105
  extend Volatile
@@ -126,6 +126,7 @@ module Concurrent
126
126
  # task = Concurrent::TimerTask.new(execution_interval: 1, timeout_interval: 1){ 42 }
127
127
  # task.add_observer(TaskObserver.new)
128
128
  # task.execute
129
+ # sleep 4
129
130
  #
130
131
  # #=> (2013-10-13 19:08:58 -0400) Execution successfully returned 42
131
132
  # #=> (2013-10-13 19:08:59 -0400) Execution successfully returned 42
@@ -164,7 +165,7 @@ module Concurrent
164
165
 
165
166
  # Create a new TimerTask with the given task and configuration.
166
167
  #
167
- # @!macro [attach] timer_task_initialize
168
+ # @!macro timer_task_initialize
168
169
  # @param [Hash] opts the options defining task execution.
169
170
  # @option opts [Integer] :execution_interval number of seconds between
170
171
  # task executions (default: EXECUTION_INTERVAL)
@@ -189,6 +190,7 @@ module Concurrent
189
190
  def initialize(opts = {}, &task)
190
191
  raise ArgumentError.new('no block given') unless block_given?
191
192
  super
193
+ set_deref_options opts
192
194
  end
193
195
 
194
196
  # Is the executor running?
@@ -280,6 +282,7 @@ module Concurrent
280
282
  @run_now = opts[:now] || opts[:run_now]
281
283
  @executor = Concurrent::SafeTaskExecutor.new(task)
282
284
  @running = Concurrent::AtomicBoolean.new(false)
285
+ @value = nil
283
286
 
284
287
  self.observers = Collection::CopyOnNotifyObserverSet.new
285
288
  end
@@ -305,7 +308,7 @@ module Concurrent
305
308
  # @!visibility private
306
309
  def execute_task(completion)
307
310
  return nil unless @running.true?
308
- ScheduledTask.execute(execution_interval, args: [completion], &method(:timeout_task))
311
+ ScheduledTask.execute(timeout_interval, args: [completion], &method(:timeout_task))
309
312
  _success, value, reason = @executor.execute(self)
310
313
  if completion.try?
311
314
  self.value = value
@@ -24,7 +24,7 @@ module Concurrent
24
24
  attr_reader :size
25
25
 
26
26
  # @!visibility private
27
- Tuple = defined?(Rubinius::Tuple) ? Rubinius::Tuple : Array
27
+ Tuple = defined?(Rubinius::Tuple) ? Rubinius::Tuple : ::Array
28
28
  private_constant :Tuple
29
29
 
30
30
  # Create a new tuple of the given size.
@@ -8,7 +8,7 @@ module Concurrent
8
8
  #
9
9
  # @!macro thread_safe_variable_comparison
10
10
  #
11
- # {include:file:doc/tvar.md}
11
+ # {include:file:docs-source/tvar.md}
12
12
  class TVar < Synchronization::Object
13
13
  safe_initialization!
14
14
 
@@ -162,7 +162,7 @@ module Concurrent
162
162
 
163
163
  class Transaction
164
164
 
165
- ABORTED = Object.new
165
+ ABORTED = ::Object.new
166
166
 
167
167
  ReadLogEntry = Struct.new(:tvar, :version)
168
168
 
@@ -0,0 +1,17 @@
1
+ require_relative 'engine'
2
+
3
+ if Concurrent.ruby_version :<, 2, 0, 0
4
+ # @!visibility private
5
+ module Kernel
6
+ def __dir__
7
+ File.dirname __FILE__
8
+ end
9
+ end
10
+
11
+ # @!visibility private
12
+ class LoadError < ScriptError
13
+ def path
14
+ message.split(' -- ').last
15
+ end
16
+ end
17
+ end
@@ -16,7 +16,7 @@ module Concurrent
16
16
  end
17
17
 
18
18
  # Add a handler to be run at `Kernel#at_exit`
19
- # @param [Object] handler_id optionally provide an id, if allready present, handler is replaced
19
+ # @param [Object] handler_id optionally provide an id, if already present, handler is replaced
20
20
  # @yield the handler
21
21
  # @return id of the handler
22
22
  def add(handler_id = nil, &handler)