concurrent-ruby 1.0.5 → 1.1.10

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 (164) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +155 -0
  3. data/Gemfile +37 -0
  4. data/LICENSE.txt +18 -18
  5. data/README.md +260 -103
  6. data/Rakefile +329 -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 +189 -0
  13. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +307 -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 → concurrent-ruby/concurrent}/agent.rb +7 -7
  23. data/lib/concurrent-ruby/concurrent/array.rb +66 -0
  24. data/lib/{concurrent → concurrent-ruby/concurrent}/async.rb +28 -24
  25. data/lib/{concurrent → concurrent-ruby/concurrent}/atom.rb +10 -10
  26. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_boolean.rb +26 -22
  27. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_fixnum.rb +27 -23
  28. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
  29. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +205 -0
  30. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/count_down_latch.rb +7 -7
  31. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/cyclic_barrier.rb +1 -1
  32. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/event.rb +3 -3
  33. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_count_down_latch.rb +9 -6
  34. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_boolean.rb +2 -0
  35. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_count_down_latch.rb +1 -0
  36. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_semaphore.rb +18 -2
  37. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/read_write_lock.rb +2 -1
  38. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/reentrant_read_write_lock.rb +7 -7
  39. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/ruby_thread_local_var.rb +60 -40
  40. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/semaphore.rb +34 -13
  41. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/thread_local_var.rb +8 -8
  42. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/mutex_atomic.rb +3 -8
  43. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/numeric_cas_wrapper.rb +1 -1
  44. data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
  45. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
  46. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/atomic_reference_map_backend.rb +3 -3
  47. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/mri_map_backend.rb +1 -1
  48. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/non_concurrent_map_backend.rb +1 -2
  49. data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
  50. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/non_concurrent_priority_queue.rb +30 -30
  51. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb +11 -1
  52. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/dereferenceable.rb +3 -3
  53. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/logging.rb +6 -1
  54. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/observable.rb +7 -7
  55. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  56. data/lib/{concurrent → concurrent-ruby/concurrent}/configuration.rb +15 -15
  57. data/lib/{concurrent → concurrent-ruby/concurrent}/constants.rb +1 -1
  58. data/lib/{concurrent → concurrent-ruby/concurrent}/dataflow.rb +2 -1
  59. data/lib/{concurrent → concurrent-ruby/concurrent}/delay.rb +9 -7
  60. data/lib/{concurrent → concurrent-ruby/concurrent}/exchanger.rb +21 -25
  61. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/abstract_executor_service.rb +35 -38
  62. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/cached_thread_pool.rb +5 -5
  63. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/executor_service.rb +17 -17
  64. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/fixed_thread_pool.rb +47 -33
  65. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_executor_service.rb +20 -17
  66. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_single_thread_executor.rb +4 -3
  67. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_thread_pool_executor.rb +29 -9
  68. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_executor_service.rb +10 -6
  69. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_single_thread_executor.rb +0 -1
  70. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_thread_pool_executor.rb +46 -42
  71. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/safe_task_executor.rb +5 -5
  72. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/simple_executor_service.rb +1 -1
  73. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/single_thread_executor.rb +3 -2
  74. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/thread_pool_executor.rb +7 -6
  75. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/timer_set.rb +14 -17
  76. data/lib/{concurrent → concurrent-ruby/concurrent}/future.rb +4 -1
  77. data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
  78. data/lib/{concurrent → concurrent-ruby/concurrent}/immutable_struct.rb +9 -1
  79. data/lib/{concurrent → concurrent-ruby/concurrent}/ivar.rb +5 -6
  80. data/lib/concurrent-ruby/concurrent/map.rb +346 -0
  81. data/lib/{concurrent → concurrent-ruby/concurrent}/maybe.rb +1 -1
  82. data/lib/{concurrent → concurrent-ruby/concurrent}/mutable_struct.rb +27 -16
  83. data/lib/{concurrent → concurrent-ruby/concurrent}/mvar.rb +2 -2
  84. data/lib/{concurrent → concurrent-ruby/concurrent}/promise.rb +54 -21
  85. data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
  86. data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
  87. data/lib/{concurrent → concurrent-ruby/concurrent}/scheduled_task.rb +29 -16
  88. data/lib/concurrent-ruby/concurrent/set.rb +74 -0
  89. data/lib/{concurrent → concurrent-ruby/concurrent}/settable_struct.rb +12 -1
  90. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_lockable_object.rb +5 -5
  91. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_struct.rb +18 -4
  92. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/condition.rb +2 -0
  93. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_object.rb +1 -0
  94. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lock.rb +2 -0
  95. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lockable_object.rb +8 -10
  96. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mri_object.rb +1 -0
  97. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +88 -0
  98. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/object.rb +53 -23
  99. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_lockable_object.rb +6 -0
  100. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_object.rb +1 -0
  101. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
  102. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/volatile.rb +11 -9
  103. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization.rb +4 -5
  104. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +88 -0
  105. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/striped64.rb +9 -4
  106. data/lib/{concurrent → concurrent-ruby/concurrent}/timer_task.rb +15 -35
  107. data/lib/{concurrent → concurrent-ruby/concurrent}/tuple.rb +1 -1
  108. data/lib/{concurrent → concurrent-ruby/concurrent}/tvar.rb +21 -58
  109. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/engine.rb +4 -4
  110. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -0
  111. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
  112. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/processor_counter.rb +5 -35
  113. data/lib/concurrent-ruby/concurrent/version.rb +3 -0
  114. data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
  115. data/lib/{concurrent.rb → concurrent-ruby/concurrent.rb} +24 -20
  116. metadata +149 -134
  117. data/lib/concurrent/array.rb +0 -39
  118. data/lib/concurrent/atomic/atomic_reference.rb +0 -51
  119. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +0 -8
  120. data/lib/concurrent/atomic_reference/direct_update.rb +0 -81
  121. data/lib/concurrent/atomic_reference/jruby+truffle.rb +0 -2
  122. data/lib/concurrent/atomic_reference/jruby.rb +0 -16
  123. data/lib/concurrent/atomic_reference/rbx.rb +0 -22
  124. data/lib/concurrent/atomic_reference/ruby.rb +0 -32
  125. data/lib/concurrent/atomics.rb +0 -53
  126. data/lib/concurrent/edge.rb +0 -26
  127. data/lib/concurrent/hash.rb +0 -36
  128. data/lib/concurrent/lazy_register.rb +0 -81
  129. data/lib/concurrent/map.rb +0 -240
  130. data/lib/concurrent/synchronization/mri_lockable_object.rb +0 -71
  131. data/lib/concurrent/synchronization/truffle_lockable_object.rb +0 -9
  132. data/lib/concurrent/synchronization/truffle_object.rb +0 -31
  133. data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +0 -30
  134. data/lib/concurrent/utility/at_exit.rb +0 -97
  135. data/lib/concurrent/utility/monotonic_time.rb +0 -58
  136. data/lib/concurrent/utility/native_extension_loader.rb +0 -73
  137. data/lib/concurrent/version.rb +0 -4
  138. /data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/abstract_thread_local_var.rb +0 -0
  139. /data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_thread_local_var.rb +0 -0
  140. /data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_fixnum.rb +0 -0
  141. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_notify_observer_set.rb +0 -0
  142. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_write_observer_set.rb +0 -0
  143. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/java_non_concurrent_priority_queue.rb +0 -0
  144. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/synchronized_map_backend.rb +0 -0
  145. /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/deprecation.rb +0 -0
  146. /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/obligation.rb +0 -0
  147. /data/lib/{concurrent → concurrent-ruby/concurrent}/errors.rb +0 -0
  148. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/immediate_executor.rb +0 -0
  149. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/indirect_immediate_executor.rb +0 -0
  150. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serial_executor_service.rb +0 -0
  151. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution.rb +0 -0
  152. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution_delegator.rb +0 -0
  153. /data/lib/{concurrent → concurrent-ruby/concurrent}/executors.rb +0 -0
  154. /data/lib/{concurrent → concurrent-ruby/concurrent}/options.rb +0 -0
  155. /data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_object.rb +0 -0
  156. /data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_lockable_object.rb +0 -0
  157. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/synchronized_delegator.rb +0 -0
  158. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/adder.rb +0 -0
  159. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/cheap_lockable.rb +0 -0
  160. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/power_of_two_tuple.rb +0 -0
  161. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/volatile.rb +0 -0
  162. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/xor_shift_random.rb +0 -0
  163. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util.rb +0 -0
  164. /data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_integer.rb +0 -0
@@ -0,0 +1,47 @@
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
@@ -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,88 @@
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_cruby(klass)
16
+ klass.class_eval do
17
+ def initialize(*args, &block)
18
+ @_monitor = Monitor.new
19
+ super
20
+ end
21
+
22
+ def initialize_copy(other)
23
+ # make sure a copy is not sharing a monitor with the original object!
24
+ @_monitor = Monitor.new
25
+ super
26
+ end
27
+ end
28
+
29
+ klass.superclass.instance_methods(false).each do |method|
30
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
31
+ def #{method}(*args)
32
+ monitor = @_monitor
33
+ monitor or raise("BUG: Internal monitor was not properly initialized. Please report this to the concurrent-ruby developers.")
34
+ monitor.synchronize { super }
35
+ end
36
+ RUBY
37
+ end
38
+ end
39
+
40
+ def self.make_synchronized_on_rbx(klass)
41
+ klass.class_eval do
42
+ private
43
+
44
+ def _mon_initialize
45
+ @_monitor ||= Monitor.new # avoid double initialisation
46
+ end
47
+
48
+ def self.new(*args)
49
+ obj = super(*args)
50
+ obj.send(:_mon_initialize)
51
+ obj
52
+ end
53
+ end
54
+
55
+ klass.superclass.instance_methods(false).each do |method|
56
+ case method
57
+ when :new_range, :new_reserved
58
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
59
+ def #{method}(*args)
60
+ obj = super
61
+ obj.send(:_mon_initialize)
62
+ obj
63
+ end
64
+ RUBY
65
+ else
66
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
67
+ def #{method}(*args)
68
+ monitor = @_monitor
69
+ monitor or raise("BUG: Internal monitor was not properly initialized. Please report this to the concurrent-ruby developers.")
70
+ monitor.synchronize { super }
71
+ end
72
+ RUBY
73
+ end
74
+ end
75
+ end
76
+
77
+ def self.make_synchronized_on_truffleruby(klass)
78
+ klass.superclass.instance_methods(false).each do |method|
79
+ klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
80
+ def #{method}(*args, &block)
81
+ TruffleRuby.synchronized(self) { super(*args, &block) }
82
+ end
83
+ RUBY
84
+ end
85
+ end
86
+ end
87
+ end
88
+ 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 :padding_0, :padding_1, :padding_2, :padding_3, :padding_4, :padding_5, :padding_6, :padding_7, :padding_8, :padding_9, :padding_10, :padding_11
101
+ end
102
+ padding
98
103
  end
99
104
 
100
105
  extend Volatile
@@ -25,9 +25,7 @@ module Concurrent
25
25
  # Should the task experience an unrecoverable crash only the task thread will
26
26
  # crash. This makes the `TimerTask` very fault tolerant. Additionally, the
27
27
  # `TimerTask` thread can respond to the success or failure of the task,
28
- # performing logging or ancillary operations. `TimerTask` can also be
29
- # configured with a timeout value allowing it to kill a task that runs too
30
- # long.
28
+ # performing logging or ancillary operations.
31
29
  #
32
30
  # One other advantage of `TimerTask` is that it forces the business logic to
33
31
  # be completely decoupled from the concurrency logic. The business logic can
@@ -48,9 +46,7 @@ module Concurrent
48
46
  # {http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html
49
47
  # Observable} module. On execution the `TimerTask` will notify the observers
50
48
  # with three arguments: time of execution, the result of the block (or nil on
51
- # failure), and any raised exceptions (or nil on success). If the timeout
52
- # interval is exceeded the observer will receive a `Concurrent::TimeoutError`
53
- # object as the third argument.
49
+ # failure), and any raised exceptions (or nil on success).
54
50
  #
55
51
  # @!macro copy_options
56
52
  #
@@ -59,20 +55,18 @@ module Concurrent
59
55
  # task.execute
60
56
  #
61
57
  # task.execution_interval #=> 60 (default)
62
- # task.timeout_interval #=> 30 (default)
63
58
  #
64
59
  # # wait 60 seconds...
65
60
  # #=> 'Boom!'
66
61
  #
67
62
  # task.shutdown #=> true
68
63
  #
69
- # @example Configuring `:execution_interval` and `:timeout_interval`
70
- # task = Concurrent::TimerTask.new(execution_interval: 5, timeout_interval: 5) do
64
+ # @example Configuring `:execution_interval`
65
+ # task = Concurrent::TimerTask.new(execution_interval: 5) do
71
66
  # puts 'Boom!'
72
67
  # end
73
68
  #
74
69
  # task.execution_interval #=> 5
75
- # task.timeout_interval #=> 5
76
70
  #
77
71
  # @example Immediate execution with `:run_now`
78
72
  # task = Concurrent::TimerTask.new(run_now: true){ puts 'Boom!' }
@@ -115,24 +109,23 @@ module Concurrent
115
109
  # def update(time, result, ex)
116
110
  # if result
117
111
  # print "(#{time}) Execution successfully returned #{result}\n"
118
- # elsif ex.is_a?(Concurrent::TimeoutError)
119
- # print "(#{time}) Execution timed out\n"
120
112
  # else
121
113
  # print "(#{time}) Execution failed with error #{ex}\n"
122
114
  # end
123
115
  # end
124
116
  # end
125
117
  #
126
- # task = Concurrent::TimerTask.new(execution_interval: 1, timeout_interval: 1){ 42 }
118
+ # task = Concurrent::TimerTask.new(execution_interval: 1){ 42 }
127
119
  # task.add_observer(TaskObserver.new)
128
120
  # task.execute
121
+ # sleep 4
129
122
  #
130
123
  # #=> (2013-10-13 19:08:58 -0400) Execution successfully returned 42
131
124
  # #=> (2013-10-13 19:08:59 -0400) Execution successfully returned 42
132
125
  # #=> (2013-10-13 19:09:00 -0400) Execution successfully returned 42
133
126
  # task.shutdown
134
127
  #
135
- # task = Concurrent::TimerTask.new(execution_interval: 1, timeout_interval: 1){ sleep }
128
+ # task = Concurrent::TimerTask.new(execution_interval: 1){ sleep }
136
129
  # task.add_observer(TaskObserver.new)
137
130
  # task.execute
138
131
  #
@@ -164,12 +157,10 @@ module Concurrent
164
157
 
165
158
  # Create a new TimerTask with the given task and configuration.
166
159
  #
167
- # @!macro [attach] timer_task_initialize
160
+ # @!macro timer_task_initialize
168
161
  # @param [Hash] opts the options defining task execution.
169
162
  # @option opts [Integer] :execution_interval number of seconds between
170
163
  # task executions (default: EXECUTION_INTERVAL)
171
- # @option opts [Integer] :timeout_interval number of seconds a task can
172
- # run before it is considered to have failed (default: TIMEOUT_INTERVAL)
173
164
  # @option opts [Boolean] :run_now Whether to run the task immediately
174
165
  # upon instantiation or to wait until the first # execution_interval
175
166
  # has passed (default: false)
@@ -189,6 +180,7 @@ module Concurrent
189
180
  def initialize(opts = {}, &task)
190
181
  raise ArgumentError.new('no block given') unless block_given?
191
182
  super
183
+ set_deref_options opts
192
184
  end
193
185
 
194
186
  # Is the executor running?
@@ -254,18 +246,14 @@ module Concurrent
254
246
  # @return [Fixnum] Number of seconds the task can run before it is
255
247
  # considered to have failed.
256
248
  def timeout_interval
257
- synchronize { @timeout_interval }
249
+ warn 'TimerTask timeouts are now ignored as these were not able to be implemented correctly'
258
250
  end
259
251
 
260
252
  # @!attribute [rw] timeout_interval
261
253
  # @return [Fixnum] Number of seconds the task can run before it is
262
254
  # considered to have failed.
263
255
  def timeout_interval=(value)
264
- if (value = value.to_f) <= 0.0
265
- raise ArgumentError.new('must be greater than zero')
266
- else
267
- synchronize { @timeout_interval = value }
268
- end
256
+ warn 'TimerTask timeouts are now ignored as these were not able to be implemented correctly'
269
257
  end
270
258
 
271
259
  private :post, :<<
@@ -276,10 +264,13 @@ module Concurrent
276
264
  set_deref_options(opts)
277
265
 
278
266
  self.execution_interval = opts[:execution] || opts[:execution_interval] || EXECUTION_INTERVAL
279
- self.timeout_interval = opts[:timeout] || opts[:timeout_interval] || TIMEOUT_INTERVAL
267
+ if opts[:timeout] || opts[:timeout_interval]
268
+ warn 'TimeTask timeouts are now ignored as these were not able to be implemented correctly'
269
+ end
280
270
  @run_now = opts[:now] || opts[:run_now]
281
271
  @executor = Concurrent::SafeTaskExecutor.new(task)
282
272
  @running = Concurrent::AtomicBoolean.new(false)
273
+ @value = nil
283
274
 
284
275
  self.observers = Collection::CopyOnNotifyObserverSet.new
285
276
  end
@@ -305,7 +296,6 @@ module Concurrent
305
296
  # @!visibility private
306
297
  def execute_task(completion)
307
298
  return nil unless @running.true?
308
- ScheduledTask.execute(execution_interval, args: [completion], &method(:timeout_task))
309
299
  _success, value, reason = @executor.execute(self)
310
300
  if completion.try?
311
301
  self.value = value
@@ -317,15 +307,5 @@ module Concurrent
317
307
  end
318
308
  nil
319
309
  end
320
-
321
- # @!visibility private
322
- def timeout_task(completion)
323
- return unless @running.true?
324
- if completion.try?
325
- self.value = value
326
- schedule_next_task
327
- observers.notify_observers(Time.now, nil, Concurrent::TimeoutError.new)
328
- end
329
- end
330
310
  end
331
311
  end
@@ -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,14 +8,13 @@ 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
 
15
15
  # Create a new `TVar` with an initial value.
16
16
  def initialize(value)
17
17
  @value = value
18
- @version = 0
19
18
  @lock = Mutex.new
20
19
  end
21
20
 
@@ -43,16 +42,6 @@ module Concurrent
43
42
  @value = value
44
43
  end
45
44
 
46
- # @!visibility private
47
- def unsafe_version # :nodoc:
48
- @version
49
- end
50
-
51
- # @!visibility private
52
- def unsafe_increment_version # :nodoc:
53
- @version += 1
54
- end
55
-
56
45
  # @!visibility private
57
46
  def unsafe_lock # :nodoc:
58
47
  @lock
@@ -162,52 +151,41 @@ module Concurrent
162
151
 
163
152
  class Transaction
164
153
 
165
- ABORTED = Object.new
154
+ ABORTED = ::Object.new
166
155
 
167
- ReadLogEntry = Struct.new(:tvar, :version)
156
+ OpenEntry = Struct.new(:value, :modified)
168
157
 
169
158
  AbortError = Class.new(StandardError)
170
159
  LeaveError = Class.new(StandardError)
171
160
 
172
161
  def initialize
173
- @read_log = []
174
- @write_log = {}
162
+ @open_tvars = {}
175
163
  end
176
164
 
177
165
  def read(tvar)
178
- Concurrent::abort_transaction unless valid?
179
-
180
- if @write_log.has_key? tvar
181
- @write_log[tvar]
182
- else
183
- @read_log.push(ReadLogEntry.new(tvar, tvar.unsafe_version))
184
- tvar.unsafe_value
185
- end
166
+ entry = open(tvar)
167
+ entry.value
186
168
  end
187
169
 
188
170
  def write(tvar, value)
189
- # Have we already written to this TVar?
171
+ entry = open(tvar)
172
+ entry.modified = true
173
+ entry.value = value
174
+ end
190
175
 
191
- unless @write_log.has_key? tvar
192
- # Try to lock the TVar
176
+ def open(tvar)
177
+ entry = @open_tvars[tvar]
193
178
 
179
+ unless entry
194
180
  unless tvar.unsafe_lock.try_lock
195
- # Someone else is writing to this TVar - abort
196
181
  Concurrent::abort_transaction
197
182
  end
198
183
 
199
- # If we previously wrote to it, check the version hasn't changed
200
-
201
- @read_log.each do |log_entry|
202
- if log_entry.tvar == tvar and tvar.unsafe_version > log_entry.version
203
- Concurrent::abort_transaction
204
- end
205
- end
184
+ entry = OpenEntry.new(tvar.unsafe_value, false)
185
+ @open_tvars[tvar] = entry
206
186
  end
207
187
 
208
- # Record the value written
209
-
210
- @write_log[tvar] = value
188
+ entry
211
189
  end
212
190
 
213
191
  def abort
@@ -215,32 +193,17 @@ module Concurrent
215
193
  end
216
194
 
217
195
  def commit
218
- return false unless valid?
219
-
220
- @write_log.each_pair do |tvar, value|
221
- tvar.unsafe_value = value
222
- tvar.unsafe_increment_version
223
- end
224
-
225
- unlock
226
-
227
- true
228
- end
229
-
230
- def valid?
231
- @read_log.each do |log_entry|
232
- unless @write_log.has_key? log_entry.tvar
233
- if log_entry.tvar.unsafe_version > log_entry.version
234
- return false
235
- end
196
+ @open_tvars.each do |tvar, entry|
197
+ if entry.modified
198
+ tvar.unsafe_value = entry.value
236
199
  end
237
200
  end
238
201
 
239
- true
202
+ unlock
240
203
  end
241
204
 
242
205
  def unlock
243
- @write_log.each_key do |tvar|
206
+ @open_tvars.each_key do |tvar|
244
207
  tvar.unsafe_lock.unlock
245
208
  end
246
209
  end
@@ -8,7 +8,7 @@ module Concurrent
8
8
  end
9
9
 
10
10
  def on_jruby_9000?
11
- on_jruby? && ruby_version(:>=, 9, 0, 0, JRUBY_VERSION)
11
+ on_jruby? && ruby_version(JRUBY_VERSION, :>=, 9, 0, 0)
12
12
  end
13
13
 
14
14
  def on_cruby?
@@ -19,8 +19,8 @@ module Concurrent
19
19
  ruby_engine == 'rbx'
20
20
  end
21
21
 
22
- def on_truffle?
23
- ruby_engine == 'jruby+truffle'
22
+ def on_truffleruby?
23
+ ruby_engine == 'truffleruby'
24
24
  end
25
25
 
26
26
  def on_windows?
@@ -39,7 +39,7 @@ module Concurrent
39
39
  defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
40
40
  end
41
41
 
42
- def ruby_version(comparison, major, minor, patch, version = RUBY_VERSION)
42
+ def ruby_version(version = RUBY_VERSION, comparison, major, minor, patch)
43
43
  result = (version.split('.').map(&:to_i) <=> [major, minor, patch])
44
44
  comparisons = { :== => [0],
45
45
  :>= => [1, 0],
@@ -0,0 +1,90 @@
1
+ require 'concurrent/synchronization'
2
+
3
+ module Concurrent
4
+
5
+ # @!macro monotonic_get_time
6
+ #
7
+ # Returns the current time a tracked by the application monotonic clock.
8
+ #
9
+ # @param [Symbol] unit the time unit to be returned, can be either
10
+ # :float_second, :float_millisecond, :float_microsecond, :second,
11
+ # :millisecond, :microsecond, or :nanosecond default to :float_second.
12
+ #
13
+ # @return [Float] The current monotonic time since some unspecified
14
+ # starting point
15
+ #
16
+ # @!macro monotonic_clock_warning
17
+ if defined?(Process::CLOCK_MONOTONIC)
18
+
19
+ def monotonic_time(unit = :float_second)
20
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, unit)
21
+ end
22
+
23
+ elsif Concurrent.on_jruby?
24
+
25
+ # @!visibility private
26
+ TIME_UNITS = Hash.new { |_hash, key| raise ArgumentError, "unexpected unit: #{key}" }.compare_by_identity
27
+ TIME_UNITS.merge!(
28
+ second: 1_000_000_000,
29
+ millisecond: 1_000_000,
30
+ microsecond: 1_000,
31
+ nanosecond: 1,
32
+ float_second: 1_000_000_000.0,
33
+ float_millisecond: 1_000_000.0,
34
+ float_microsecond: 1_000.0,
35
+ )
36
+ TIME_UNITS.freeze
37
+ private_constant :TIME_UNITS
38
+
39
+ def monotonic_time(unit = :float_second)
40
+ java.lang.System.nanoTime() / TIME_UNITS[unit]
41
+ end
42
+
43
+ else
44
+
45
+ class_definition = Class.new(Synchronization::LockableObject) do
46
+ def initialize
47
+ @last_time = Time.now.to_f
48
+ @time_units = Hash.new { |_hash, key| raise ArgumentError, "unexpected unit: #{key}" }.compare_by_identity
49
+ @time_units.merge!(
50
+ second: [nil, true],
51
+ millisecond: [1_000, true],
52
+ microsecond: [1_000_000, true],
53
+ nanosecond: [1_000_000_000, true],
54
+ float_second: [nil, false],
55
+ float_millisecond: [1_000.0, false],
56
+ float_microsecond: [1_000_000.0, false],
57
+ )
58
+ super()
59
+ end
60
+
61
+ # @!visibility private
62
+ def get_time(unit)
63
+ synchronize do
64
+ now = Time.now.to_f
65
+ if @last_time < now
66
+ @last_time = now
67
+ else # clock has moved back in time
68
+ @last_time += 0.000_001
69
+ end
70
+ scale, to_int = @time_units[unit]
71
+ now *= scale if scale
72
+ now = now.to_i if to_int
73
+ now
74
+ end
75
+ end
76
+ end
77
+
78
+ # Clock that cannot be set and represents monotonic time since
79
+ # some unspecified starting point.
80
+ #
81
+ # @!visibility private
82
+ GLOBAL_MONOTONIC_CLOCK = class_definition.new
83
+ private_constant :GLOBAL_MONOTONIC_CLOCK
84
+
85
+ def monotonic_time(unit = :float_second)
86
+ GLOBAL_MONOTONIC_CLOCK.get_time(unit)
87
+ end
88
+ end
89
+ module_function :monotonic_time
90
+ end