concurrent-ruby 1.1.10 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -1
  3. data/Gemfile +1 -2
  4. data/README.md +23 -20
  5. data/Rakefile +75 -65
  6. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +10 -25
  7. data/lib/concurrent-ruby/concurrent/agent.rb +2 -1
  8. data/lib/concurrent-ruby/concurrent/array.rb +3 -13
  9. data/lib/concurrent-ruby/concurrent/atom.rb +1 -1
  10. data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +5 -4
  11. data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +5 -4
  12. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +3 -0
  13. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +81 -151
  14. data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +1 -1
  15. data/lib/concurrent-ruby/concurrent/atomic/event.rb +1 -1
  16. data/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb +109 -0
  17. data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +1 -0
  18. data/lib/concurrent-ruby/concurrent/atomic/locals.rb +189 -0
  19. data/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb +28 -0
  20. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +11 -5
  21. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +11 -5
  22. data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +1 -1
  23. data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +1 -1
  24. data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +2 -1
  25. data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +5 -3
  26. data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +6 -9
  27. data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +96 -89
  28. data/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb +37 -0
  29. data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +15 -4
  30. data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +1 -1
  31. data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +1 -1
  32. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +2 -0
  33. data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +2 -2
  34. data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +16 -8
  35. data/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb +23 -20
  36. data/lib/concurrent-ruby/concurrent/concern/logging.rb +86 -2
  37. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  38. data/lib/concurrent-ruby/concurrent/configuration.rb +4 -87
  39. data/lib/concurrent-ruby/concurrent/delay.rb +2 -2
  40. data/lib/concurrent-ruby/concurrent/errors.rb +5 -0
  41. data/lib/concurrent-ruby/concurrent/exchanger.rb +1 -0
  42. data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +1 -1
  43. data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +4 -0
  44. data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +6 -9
  45. data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +5 -0
  46. data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +7 -0
  47. data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +1 -1
  48. data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +1 -1
  49. data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +4 -1
  50. data/lib/concurrent-ruby/concurrent/executor/timer_set.rb +6 -2
  51. data/lib/concurrent-ruby/concurrent/hash.rb +5 -12
  52. data/lib/concurrent-ruby/concurrent/immutable_struct.rb +1 -1
  53. data/lib/concurrent-ruby/concurrent/ivar.rb +2 -1
  54. data/lib/concurrent-ruby/concurrent/map.rb +43 -39
  55. data/lib/concurrent-ruby/concurrent/maybe.rb +1 -1
  56. data/lib/concurrent-ruby/concurrent/mutable_struct.rb +1 -1
  57. data/lib/concurrent-ruby/concurrent/mvar.rb +1 -1
  58. data/lib/concurrent-ruby/concurrent/promise.rb +1 -1
  59. data/lib/concurrent-ruby/concurrent/promises.rb +40 -29
  60. data/lib/concurrent-ruby/concurrent/re_include.rb +2 -0
  61. data/lib/concurrent-ruby/concurrent/scheduled_task.rb +1 -1
  62. data/lib/concurrent-ruby/concurrent/set.rb +0 -10
  63. data/lib/concurrent-ruby/concurrent/settable_struct.rb +2 -2
  64. data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +5 -1
  65. data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +1 -3
  66. data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +2 -0
  67. data/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb +29 -0
  68. data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +3 -1
  69. data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +2 -0
  70. data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +5 -2
  71. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +6 -5
  72. data/lib/concurrent-ruby/concurrent/synchronization/object.rb +12 -44
  73. data/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb +36 -0
  74. data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +77 -12
  75. data/lib/concurrent-ruby/concurrent/synchronization.rb +1 -18
  76. data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +36 -39
  77. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +1 -37
  78. data/lib/concurrent-ruby/concurrent/timer_task.rb +59 -9
  79. data/lib/concurrent-ruby/concurrent/tuple.rb +1 -5
  80. data/lib/concurrent-ruby/concurrent/tvar.rb +2 -1
  81. data/lib/concurrent-ruby/concurrent/utility/engine.rb +5 -16
  82. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +3 -74
  83. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +8 -10
  84. data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +1 -0
  85. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +118 -58
  86. data/lib/concurrent-ruby/concurrent/version.rb +1 -1
  87. metadata +13 -17
  88. data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +0 -66
  89. data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +0 -37
  90. data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +0 -181
  91. data/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb +0 -927
  92. data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +0 -45
  93. data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +0 -44
  94. data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +0 -71
  95. data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +0 -49
  96. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +0 -47
  97. data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +0 -118
@@ -2,49 +2,46 @@ require 'delegate'
2
2
  require 'monitor'
3
3
 
4
4
  module Concurrent
5
- unless defined?(SynchronizedDelegator)
6
-
7
- # This class provides a trivial way to synchronize all calls to a given object
8
- # by wrapping it with a `Delegator` that performs `Monitor#enter/exit` calls
9
- # around the delegated `#send`. Example:
10
- #
11
- # array = [] # not thread-safe on many impls
12
- # array = SynchronizedDelegator.new([]) # thread-safe
13
- #
14
- # A simple `Monitor` provides a very coarse-grained way to synchronize a given
15
- # object, in that it will cause synchronization for methods that have no need
16
- # for it, but this is a trivial way to get thread-safety where none may exist
17
- # currently on some implementations.
18
- #
19
- # This class is currently being considered for inclusion into stdlib, via
20
- # https://bugs.ruby-lang.org/issues/8556
21
- #
22
- # @!visibility private
23
- class SynchronizedDelegator < SimpleDelegator
24
- def setup
25
- @old_abort = Thread.abort_on_exception
26
- Thread.abort_on_exception = true
27
- end
5
+ # This class provides a trivial way to synchronize all calls to a given object
6
+ # by wrapping it with a `Delegator` that performs `Monitor#enter/exit` calls
7
+ # around the delegated `#send`. Example:
8
+ #
9
+ # array = [] # not thread-safe on many impls
10
+ # array = SynchronizedDelegator.new([]) # thread-safe
11
+ #
12
+ # A simple `Monitor` provides a very coarse-grained way to synchronize a given
13
+ # object, in that it will cause synchronization for methods that have no need
14
+ # for it, but this is a trivial way to get thread-safety where none may exist
15
+ # currently on some implementations.
16
+ #
17
+ # This class is currently being considered for inclusion into stdlib, via
18
+ # https://bugs.ruby-lang.org/issues/8556
19
+ #
20
+ # @!visibility private
21
+ class SynchronizedDelegator < SimpleDelegator
22
+ def setup
23
+ @old_abort = Thread.abort_on_exception
24
+ Thread.abort_on_exception = true
25
+ end
28
26
 
29
- def teardown
30
- Thread.abort_on_exception = @old_abort
31
- end
27
+ def teardown
28
+ Thread.abort_on_exception = @old_abort
29
+ end
32
30
 
33
- def initialize(obj)
34
- __setobj__(obj)
35
- @monitor = Monitor.new
36
- end
31
+ def initialize(obj)
32
+ __setobj__(obj)
33
+ @monitor = Monitor.new
34
+ end
37
35
 
38
- def method_missing(method, *args, &block)
39
- monitor = @monitor
40
- begin
41
- monitor.enter
42
- super
43
- ensure
44
- monitor.exit
45
- end
36
+ def method_missing(method, *args, &block)
37
+ monitor = @monitor
38
+ begin
39
+ monitor.enter
40
+ super
41
+ ensure
42
+ monitor.exit
46
43
  end
47
-
48
44
  end
45
+
49
46
  end
50
47
  end
@@ -1,4 +1,5 @@
1
1
  require 'concurrent/thread_safe/util'
2
+ require 'concurrent/utility/engine'
2
3
 
3
4
  # Shim for TruffleRuby.synchronized
4
5
  if Concurrent.on_truffleruby? && !TruffleRuby.respond_to?(:synchronized)
@@ -37,43 +38,6 @@ module Concurrent
37
38
  end
38
39
  end
39
40
 
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
41
  def self.make_synchronized_on_truffleruby(klass)
78
42
  klass.superclass.instance_methods(false).each do |method|
79
43
  klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
@@ -32,6 +32,17 @@ module Concurrent
32
32
  # be tested separately then passed to the `TimerTask` for scheduling and
33
33
  # running.
34
34
  #
35
+ # A `TimerTask` supports two different types of interval calculations.
36
+ # A fixed delay will always wait the same amount of time between the
37
+ # completion of one task and the start of the next. A fixed rate will
38
+ # attempt to maintain a constant rate of execution regardless of the
39
+ # duration of the task. For example, if a fixed rate task is scheduled
40
+ # to run every 60 seconds but the task itself takes 10 seconds to
41
+ # complete, the next task will be scheduled to run 50 seconds after
42
+ # the start of the previous task. If the task takes 70 seconds to
43
+ # complete, the next task will be start immediately after the previous
44
+ # task completes. Tasks will not be executed concurrently.
45
+ #
35
46
  # In some cases it may be necessary for a `TimerTask` to affect its own
36
47
  # execution cycle. To facilitate this, a reference to the TimerTask instance
37
48
  # is passed as an argument to the provided block every time the task is
@@ -74,6 +85,12 @@ module Concurrent
74
85
  #
75
86
  # #=> 'Boom!'
76
87
  #
88
+ # @example Configuring `:interval_type` with either :fixed_delay or :fixed_rate, default is :fixed_delay
89
+ # task = Concurrent::TimerTask.new(execution_interval: 5, interval_type: :fixed_rate) do
90
+ # puts 'Boom!'
91
+ # end
92
+ # task.interval_type #=> :fixed_rate
93
+ #
77
94
  # @example Last `#value` and `Dereferenceable` mixin
78
95
  # task = Concurrent::TimerTask.new(
79
96
  # dup_on_deref: true,
@@ -87,7 +104,7 @@ module Concurrent
87
104
  #
88
105
  # @example Controlling execution from within the block
89
106
  # timer_task = Concurrent::TimerTask.new(execution_interval: 1) do |task|
90
- # task.execution_interval.times{ print 'Boom! ' }
107
+ # task.execution_interval.to_i.times{ print 'Boom! ' }
91
108
  # print "\n"
92
109
  # task.execution_interval += 1
93
110
  # if task.execution_interval > 5
@@ -96,7 +113,7 @@ module Concurrent
96
113
  # end
97
114
  # end
98
115
  #
99
- # timer_task.execute # blocking call - this task will stop itself
116
+ # timer_task.execute
100
117
  # #=> Boom!
101
118
  # #=> Boom! Boom!
102
119
  # #=> Boom! Boom! Boom!
@@ -152,18 +169,30 @@ module Concurrent
152
169
  # Default `:execution_interval` in seconds.
153
170
  EXECUTION_INTERVAL = 60
154
171
 
155
- # Default `:timeout_interval` in seconds.
156
- TIMEOUT_INTERVAL = 30
172
+ # Maintain the interval between the end of one execution and the start of the next execution.
173
+ FIXED_DELAY = :fixed_delay
174
+
175
+ # Maintain the interval between the start of one execution and the start of the next.
176
+ # If execution time exceeds the interval, the next execution will start immediately
177
+ # after the previous execution finishes. Executions will not run concurrently.
178
+ FIXED_RATE = :fixed_rate
179
+
180
+ # Default `:interval_type`
181
+ DEFAULT_INTERVAL_TYPE = FIXED_DELAY
157
182
 
158
183
  # Create a new TimerTask with the given task and configuration.
159
184
  #
160
185
  # @!macro timer_task_initialize
161
186
  # @param [Hash] opts the options defining task execution.
162
- # @option opts [Integer] :execution_interval number of seconds between
187
+ # @option opts [Float] :execution_interval number of seconds between
163
188
  # task executions (default: EXECUTION_INTERVAL)
164
189
  # @option opts [Boolean] :run_now Whether to run the task immediately
165
190
  # upon instantiation or to wait until the first # execution_interval
166
191
  # has passed (default: false)
192
+ # @options opts [Symbol] :interval_type method to calculate the interval
193
+ # between executions, can be either :fixed_rate or :fixed_delay.
194
+ # (default: :fixed_delay)
195
+ # @option opts [Executor] executor, default is `global_io_executor`
167
196
  #
168
197
  # @!macro deref_options
169
198
  #
@@ -242,6 +271,10 @@ module Concurrent
242
271
  end
243
272
  end
244
273
 
274
+ # @!attribute [r] interval_type
275
+ # @return [Symbol] method to calculate the interval between executions
276
+ attr_reader :interval_type
277
+
245
278
  # @!attribute [rw] timeout_interval
246
279
  # @return [Fixnum] Number of seconds the task can run before it is
247
280
  # considered to have failed.
@@ -264,11 +297,17 @@ module Concurrent
264
297
  set_deref_options(opts)
265
298
 
266
299
  self.execution_interval = opts[:execution] || opts[:execution_interval] || EXECUTION_INTERVAL
300
+ if opts[:interval_type] && ![FIXED_DELAY, FIXED_RATE].include?(opts[:interval_type])
301
+ raise ArgumentError.new('interval_type must be either :fixed_delay or :fixed_rate')
302
+ end
267
303
  if opts[:timeout] || opts[:timeout_interval]
268
304
  warn 'TimeTask timeouts are now ignored as these were not able to be implemented correctly'
269
305
  end
306
+
270
307
  @run_now = opts[:now] || opts[:run_now]
271
- @executor = Concurrent::SafeTaskExecutor.new(task)
308
+ @interval_type = opts[:interval_type] || DEFAULT_INTERVAL_TYPE
309
+ @task = Concurrent::SafeTaskExecutor.new(task)
310
+ @executor = opts[:executor] || Concurrent.global_io_executor
272
311
  @running = Concurrent::AtomicBoolean.new(false)
273
312
  @value = nil
274
313
 
@@ -289,17 +328,18 @@ module Concurrent
289
328
 
290
329
  # @!visibility private
291
330
  def schedule_next_task(interval = execution_interval)
292
- ScheduledTask.execute(interval, args: [Concurrent::Event.new], &method(:execute_task))
331
+ ScheduledTask.execute(interval, executor: @executor, args: [Concurrent::Event.new], &method(:execute_task))
293
332
  nil
294
333
  end
295
334
 
296
335
  # @!visibility private
297
336
  def execute_task(completion)
298
337
  return nil unless @running.true?
299
- _success, value, reason = @executor.execute(self)
338
+ start_time = Concurrent.monotonic_time
339
+ _success, value, reason = @task.execute(self)
300
340
  if completion.try?
301
341
  self.value = value
302
- schedule_next_task
342
+ schedule_next_task(calculate_next_interval(start_time))
303
343
  time = Time.now
304
344
  observers.notify_observers do
305
345
  [time, self.value, reason]
@@ -307,5 +347,15 @@ module Concurrent
307
347
  end
308
348
  nil
309
349
  end
350
+
351
+ # @!visibility private
352
+ def calculate_next_interval(start_time)
353
+ if @interval_type == FIXED_RATE
354
+ run_time = Concurrent.monotonic_time - start_time
355
+ [execution_interval - run_time, 0].max
356
+ else # FIXED_DELAY
357
+ execution_interval
358
+ end
359
+ end
310
360
  end
311
361
  end
@@ -23,16 +23,12 @@ module Concurrent
23
23
  # The (fixed) size of the tuple.
24
24
  attr_reader :size
25
25
 
26
- # @!visibility private
27
- Tuple = defined?(Rubinius::Tuple) ? Rubinius::Tuple : ::Array
28
- private_constant :Tuple
29
-
30
26
  # Create a new tuple of the given size.
31
27
  #
32
28
  # @param [Integer] size the number of elements in the tuple
33
29
  def initialize(size)
34
30
  @size = size
35
- @tuple = tuple = Tuple.new(size)
31
+ @tuple = tuple = ::Array.new(size)
36
32
  i = 0
37
33
  while i < size
38
34
  tuple[i] = Concurrent::AtomicReference.new
@@ -1,5 +1,5 @@
1
1
  require 'set'
2
- require 'concurrent/synchronization'
2
+ require 'concurrent/synchronization/object'
3
3
 
4
4
  module Concurrent
5
5
 
@@ -149,6 +149,7 @@ module Concurrent
149
149
 
150
150
  private
151
151
 
152
+ # @!visibility private
152
153
  class Transaction
153
154
 
154
155
  ABORTED = ::Object.new
@@ -1,26 +1,19 @@
1
1
  module Concurrent
2
+ # @!visibility private
2
3
  module Utility
3
4
 
4
5
  # @!visibility private
5
6
  module EngineDetector
6
- def on_jruby?
7
- ruby_engine == 'jruby'
8
- end
9
-
10
- def on_jruby_9000?
11
- on_jruby? && ruby_version(JRUBY_VERSION, :>=, 9, 0, 0)
12
- end
13
-
14
7
  def on_cruby?
15
- ruby_engine == 'ruby'
8
+ RUBY_ENGINE == 'ruby'
16
9
  end
17
10
 
18
- def on_rbx?
19
- ruby_engine == 'rbx'
11
+ def on_jruby?
12
+ RUBY_ENGINE == 'jruby'
20
13
  end
21
14
 
22
15
  def on_truffleruby?
23
- ruby_engine == 'truffleruby'
16
+ RUBY_ENGINE == 'truffleruby'
24
17
  end
25
18
 
26
19
  def on_windows?
@@ -35,10 +28,6 @@ module Concurrent
35
28
  !(RbConfig::CONFIG['host_os'] =~ /linux/).nil?
36
29
  end
37
30
 
38
- def ruby_engine
39
- defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
40
- end
41
-
42
31
  def ruby_version(version = RUBY_VERSION, comparison, major, minor, patch)
43
32
  result = (version.split('.').map(&:to_i) <=> [major, minor, patch])
44
33
  comparisons = { :== => [0],
@@ -1,10 +1,8 @@
1
- require 'concurrent/synchronization'
2
-
3
1
  module Concurrent
4
2
 
5
3
  # @!macro monotonic_get_time
6
4
  #
7
- # Returns the current time a tracked by the application monotonic clock.
5
+ # Returns the current time as tracked by the application monotonic clock.
8
6
  #
9
7
  # @param [Symbol] unit the time unit to be returned, can be either
10
8
  # :float_second, :float_millisecond, :float_microsecond, :second,
@@ -14,77 +12,8 @@ module Concurrent
14
12
  # starting point
15
13
  #
16
14
  # @!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
15
+ def monotonic_time(unit = :float_second)
16
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, unit)
88
17
  end
89
18
  module_function :monotonic_time
90
19
  end
@@ -1,9 +1,10 @@
1
1
  require 'concurrent/utility/engine'
2
+ # Synchronization::AbstractObject must be defined before loading the extension
3
+ require 'concurrent/synchronization/abstract_object'
2
4
 
3
5
  module Concurrent
4
-
6
+ # @!visibility private
5
7
  module Utility
6
-
7
8
  # @!visibility private
8
9
  module NativeExtensionLoader
9
10
 
@@ -15,15 +16,7 @@ module Concurrent
15
16
  defined?(@c_extensions_loaded) && @c_extensions_loaded
16
17
  end
17
18
 
18
- def java_extensions_loaded?
19
- defined?(@java_extensions_loaded) && @java_extensions_loaded
20
- end
21
-
22
19
  def load_native_extensions
23
- unless defined? Synchronization::AbstractObject
24
- raise 'native_extension_loader loaded before Synchronization::AbstractObject'
25
- end
26
-
27
20
  if Concurrent.on_cruby? && !c_extensions_loaded?
28
21
  ['concurrent/concurrent_ruby_ext',
29
22
  "concurrent/#{RUBY_VERSION[0..2]}/concurrent_ruby_ext"
@@ -54,6 +47,10 @@ module Concurrent
54
47
  @c_extensions_loaded = true
55
48
  end
56
49
 
50
+ def java_extensions_loaded?
51
+ defined?(@java_extensions_loaded) && @java_extensions_loaded
52
+ end
53
+
57
54
  def set_java_extensions_loaded
58
55
  @java_extensions_loaded = true
59
56
  end
@@ -77,3 +74,4 @@ module Concurrent
77
74
  extend Utility::NativeExtensionLoader
78
75
  end
79
76
 
77
+ Concurrent.load_native_extensions
@@ -1,4 +1,5 @@
1
1
  module Concurrent
2
+ # @!visibility private
2
3
  module Utility
3
4
  # @private
4
5
  module NativeInteger