concurrent-ruby 1.1.8 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -0
  3. data/Gemfile +2 -8
  4. data/README.md +49 -28
  5. data/Rakefile +59 -75
  6. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +0 -0
  7. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +52 -22
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +10 -25
  9. data/lib/concurrent-ruby/concurrent/agent.rb +2 -1
  10. data/lib/concurrent-ruby/concurrent/array.rb +0 -10
  11. data/lib/concurrent-ruby/concurrent/async.rb +1 -0
  12. data/lib/concurrent-ruby/concurrent/atom.rb +1 -1
  13. data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +5 -4
  14. data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +5 -4
  15. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +3 -0
  16. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +82 -151
  17. data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +1 -1
  18. data/lib/concurrent-ruby/concurrent/atomic/event.rb +3 -3
  19. data/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb +109 -0
  20. data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +1 -0
  21. data/lib/concurrent-ruby/concurrent/atomic/locals.rb +188 -0
  22. data/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb +28 -0
  23. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +11 -5
  24. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +11 -5
  25. data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +1 -1
  26. data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +19 -3
  27. data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +2 -1
  28. data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +9 -9
  29. data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +32 -14
  30. data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +96 -89
  31. data/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb +37 -0
  32. data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +15 -4
  33. data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +1 -1
  34. data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +1 -1
  35. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +2 -0
  36. data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
  37. data/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +11 -1
  38. data/lib/concurrent-ruby/concurrent/concern/logging.rb +86 -2
  39. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  40. data/lib/concurrent-ruby/concurrent/configuration.rb +4 -87
  41. data/lib/concurrent-ruby/concurrent/delay.rb +2 -2
  42. data/lib/concurrent-ruby/concurrent/errors.rb +5 -0
  43. data/lib/concurrent-ruby/concurrent/exchanger.rb +1 -0
  44. data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +17 -14
  45. data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +13 -3
  46. data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +3 -3
  47. data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +4 -0
  48. data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +10 -4
  49. data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +26 -37
  50. data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +6 -6
  51. data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +1 -1
  52. data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +4 -1
  53. data/lib/concurrent-ruby/concurrent/hash.rb +0 -9
  54. data/lib/concurrent-ruby/concurrent/immutable_struct.rb +1 -1
  55. data/lib/concurrent-ruby/concurrent/ivar.rb +2 -1
  56. data/lib/concurrent-ruby/concurrent/map.rb +18 -8
  57. data/lib/concurrent-ruby/concurrent/maybe.rb +1 -1
  58. data/lib/concurrent-ruby/concurrent/mutable_struct.rb +1 -1
  59. data/lib/concurrent-ruby/concurrent/mvar.rb +1 -1
  60. data/lib/concurrent-ruby/concurrent/promise.rb +2 -1
  61. data/lib/concurrent-ruby/concurrent/promises.rb +7 -6
  62. data/lib/concurrent-ruby/concurrent/re_include.rb +2 -0
  63. data/lib/concurrent-ruby/concurrent/scheduled_task.rb +30 -17
  64. data/lib/concurrent-ruby/concurrent/set.rb +12 -14
  65. data/lib/concurrent-ruby/concurrent/settable_struct.rb +2 -2
  66. data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +5 -1
  67. data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +1 -3
  68. data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +2 -0
  69. data/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb +29 -0
  70. data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +3 -1
  71. data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +2 -0
  72. data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +6 -5
  73. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +18 -5
  74. data/lib/concurrent-ruby/concurrent/synchronization/object.rb +12 -44
  75. data/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb +36 -0
  76. data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +77 -12
  77. data/lib/concurrent-ruby/concurrent/synchronization.rb +1 -18
  78. data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +36 -39
  79. data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +2 -39
  80. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +16 -27
  81. data/lib/concurrent-ruby/concurrent/timer_task.rb +11 -33
  82. data/lib/concurrent-ruby/concurrent/tuple.rb +1 -5
  83. data/lib/concurrent-ruby/concurrent/tvar.rb +22 -61
  84. data/lib/concurrent-ruby/concurrent/utility/engine.rb +5 -16
  85. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +7 -46
  86. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +8 -10
  87. data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +1 -0
  88. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +36 -89
  89. data/lib/concurrent-ruby/concurrent/version.rb +1 -1
  90. data/lib/concurrent-ruby/concurrent-ruby.rb +5 -1
  91. metadata +11 -12
  92. data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +0 -66
  93. data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +0 -37
  94. data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +0 -181
  95. data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +0 -45
  96. data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +0 -44
  97. data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +0 -65
  98. data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +0 -49
  99. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +0 -47
@@ -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,15 +109,13 @@ 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
129
121
  # sleep 4
@@ -133,7 +125,7 @@ module Concurrent
133
125
  # #=> (2013-10-13 19:09:00 -0400) Execution successfully returned 42
134
126
  # task.shutdown
135
127
  #
136
- # task = Concurrent::TimerTask.new(execution_interval: 1, timeout_interval: 1){ sleep }
128
+ # task = Concurrent::TimerTask.new(execution_interval: 1){ sleep }
137
129
  # task.add_observer(TaskObserver.new)
138
130
  # task.execute
139
131
  #
@@ -169,8 +161,6 @@ module Concurrent
169
161
  # @param [Hash] opts the options defining task execution.
170
162
  # @option opts [Integer] :execution_interval number of seconds between
171
163
  # task executions (default: EXECUTION_INTERVAL)
172
- # @option opts [Integer] :timeout_interval number of seconds a task can
173
- # run before it is considered to have failed (default: TIMEOUT_INTERVAL)
174
164
  # @option opts [Boolean] :run_now Whether to run the task immediately
175
165
  # upon instantiation or to wait until the first # execution_interval
176
166
  # has passed (default: false)
@@ -256,18 +246,14 @@ module Concurrent
256
246
  # @return [Fixnum] Number of seconds the task can run before it is
257
247
  # considered to have failed.
258
248
  def timeout_interval
259
- synchronize { @timeout_interval }
249
+ warn 'TimerTask timeouts are now ignored as these were not able to be implemented correctly'
260
250
  end
261
251
 
262
252
  # @!attribute [rw] timeout_interval
263
253
  # @return [Fixnum] Number of seconds the task can run before it is
264
254
  # considered to have failed.
265
255
  def timeout_interval=(value)
266
- if (value = value.to_f) <= 0.0
267
- raise ArgumentError.new('must be greater than zero')
268
- else
269
- synchronize { @timeout_interval = value }
270
- end
256
+ warn 'TimerTask timeouts are now ignored as these were not able to be implemented correctly'
271
257
  end
272
258
 
273
259
  private :post, :<<
@@ -278,7 +264,9 @@ module Concurrent
278
264
  set_deref_options(opts)
279
265
 
280
266
  self.execution_interval = opts[:execution] || opts[:execution_interval] || EXECUTION_INTERVAL
281
- 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
282
270
  @run_now = opts[:now] || opts[:run_now]
283
271
  @executor = Concurrent::SafeTaskExecutor.new(task)
284
272
  @running = Concurrent::AtomicBoolean.new(false)
@@ -308,7 +296,6 @@ module Concurrent
308
296
  # @!visibility private
309
297
  def execute_task(completion)
310
298
  return nil unless @running.true?
311
- ScheduledTask.execute(timeout_interval, args: [completion], &method(:timeout_task))
312
299
  _success, value, reason = @executor.execute(self)
313
300
  if completion.try?
314
301
  self.value = value
@@ -320,14 +307,5 @@ module Concurrent
320
307
  end
321
308
  nil
322
309
  end
323
-
324
- # @!visibility private
325
- def timeout_task(completion)
326
- return unless @running.true?
327
- if completion.try?
328
- schedule_next_task
329
- observers.notify_observers(Time.now, nil, Concurrent::TimeoutError.new)
330
- end
331
- end
332
310
  end
333
311
  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
 
@@ -15,7 +15,6 @@ module Concurrent
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
@@ -160,57 +149,44 @@ module Concurrent
160
149
 
161
150
  private
162
151
 
152
+ # @!visibility private
163
153
  class Transaction
164
154
 
165
155
  ABORTED = ::Object.new
166
156
 
167
- ReadLogEntry = Struct.new(:tvar, :version)
157
+ OpenEntry = Struct.new(:value, :modified)
168
158
 
169
159
  AbortError = Class.new(StandardError)
170
160
  LeaveError = Class.new(StandardError)
171
161
 
172
162
  def initialize
173
- @read_log = []
174
- @write_log = {}
163
+ @open_tvars = {}
175
164
  end
176
165
 
177
166
  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
167
+ entry = open(tvar)
168
+ entry.value
186
169
  end
187
170
 
188
171
  def write(tvar, value)
189
- # Have we already written to this TVar?
172
+ entry = open(tvar)
173
+ entry.modified = true
174
+ entry.value = value
175
+ end
190
176
 
191
- if @write_log.has_key? tvar
192
- # Record the value written
193
- @write_log[tvar] = value
194
- else
195
- # Try to lock the TVar
177
+ def open(tvar)
178
+ entry = @open_tvars[tvar]
196
179
 
180
+ unless entry
197
181
  unless tvar.unsafe_lock.try_lock
198
- # Someone else is writing to this TVar - abort
199
182
  Concurrent::abort_transaction
200
183
  end
201
184
 
202
- # Record the value written
203
-
204
- @write_log[tvar] = value
205
-
206
- # If we previously read from it, check the version hasn't changed
207
-
208
- @read_log.each do |log_entry|
209
- if log_entry.tvar == tvar and tvar.unsafe_version > log_entry.version
210
- Concurrent::abort_transaction
211
- end
212
- end
185
+ entry = OpenEntry.new(tvar.unsafe_value, false)
186
+ @open_tvars[tvar] = entry
213
187
  end
188
+
189
+ entry
214
190
  end
215
191
 
216
192
  def abort
@@ -218,32 +194,17 @@ module Concurrent
218
194
  end
219
195
 
220
196
  def commit
221
- return false unless valid?
222
-
223
- @write_log.each_pair do |tvar, value|
224
- tvar.unsafe_value = value
225
- tvar.unsafe_increment_version
226
- end
227
-
228
- unlock
229
-
230
- true
231
- end
232
-
233
- def valid?
234
- @read_log.each do |log_entry|
235
- unless @write_log.has_key? log_entry.tvar
236
- if log_entry.tvar.unsafe_version > log_entry.version
237
- return false
238
- end
197
+ @open_tvars.each do |tvar, entry|
198
+ if entry.modified
199
+ tvar.unsafe_value = entry.value
239
200
  end
240
201
  end
241
202
 
242
- true
203
+ unlock
243
204
  end
244
205
 
245
206
  def unlock
246
- @write_log.each_key do |tvar|
207
+ @open_tvars.each_key do |tvar|
247
208
  tvar.unsafe_lock.unlock
248
209
  end
249
210
  end
@@ -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,58 +1,19 @@
1
- require 'concurrent/synchronization'
2
-
3
1
  module Concurrent
4
2
 
5
- class_definition = Class.new(Synchronization::LockableObject) do
6
- def initialize
7
- @last_time = Time.now.to_f
8
- super()
9
- end
10
-
11
- if defined?(Process::CLOCK_MONOTONIC)
12
- # @!visibility private
13
- def get_time
14
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
15
- end
16
- elsif Concurrent.on_jruby?
17
- # @!visibility private
18
- def get_time
19
- java.lang.System.nanoTime() / 1_000_000_000.0
20
- end
21
- else
22
-
23
- # @!visibility private
24
- def get_time
25
- synchronize do
26
- now = Time.now.to_f
27
- if @last_time < now
28
- @last_time = now
29
- else # clock has moved back in time
30
- @last_time += 0.000_001
31
- end
32
- end
33
- end
34
-
35
- end
36
- end
37
-
38
- # Clock that cannot be set and represents monotonic time since
39
- # some unspecified starting point.
40
- #
41
- # @!visibility private
42
- GLOBAL_MONOTONIC_CLOCK = class_definition.new
43
- private_constant :GLOBAL_MONOTONIC_CLOCK
44
-
45
3
  # @!macro monotonic_get_time
46
4
  #
47
- # Returns the current time a tracked by the application monotonic clock.
5
+ # Returns the current time as tracked by the application monotonic clock.
6
+ #
7
+ # @param [Symbol] unit the time unit to be returned, can be either
8
+ # :float_second, :float_millisecond, :float_microsecond, :second,
9
+ # :millisecond, :microsecond, or :nanosecond default to :float_second.
48
10
  #
49
11
  # @return [Float] The current monotonic time since some unspecified
50
12
  # starting point
51
13
  #
52
14
  # @!macro monotonic_clock_warning
53
- def monotonic_time
54
- GLOBAL_MONOTONIC_CLOCK.get_time
15
+ def monotonic_time(unit = :float_second)
16
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, unit)
55
17
  end
56
-
57
18
  module_function :monotonic_time
58
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
@@ -3,6 +3,7 @@ require 'rbconfig'
3
3
  require 'concurrent/delay'
4
4
 
5
5
  module Concurrent
6
+ # @!visibility private
6
7
  module Utility
7
8
 
8
9
  # @!visibility private
@@ -12,64 +13,10 @@ module Concurrent
12
13
  @physical_processor_count = Delay.new { compute_physical_processor_count }
13
14
  end
14
15
 
15
- # Number of processors seen by the OS and used for process scheduling. For
16
- # performance reasons the calculated value will be memoized on the first
17
- # call.
18
- #
19
- # When running under JRuby the Java runtime call
20
- # `java.lang.Runtime.getRuntime.availableProcessors` will be used. According
21
- # to the Java documentation this "value may change during a particular
22
- # invocation of the virtual machine... [applications] should therefore
23
- # occasionally poll this property." Subsequently the result will NOT be
24
- # memoized under JRuby.
25
- #
26
- # Ruby's Etc.nprocessors will be used if available (MRI 2.2+).
27
- #
28
- # On Windows the Win32 API will be queried for the
29
- # `NumberOfLogicalProcessors from Win32_Processor`. This will return the
30
- # total number "logical processors for the current instance of the
31
- # processor", which taked into account hyperthreading.
32
- #
33
- # * AIX: /usr/sbin/pmcycles (AIX 5+), /usr/sbin/lsdev
34
- # * Alpha: /usr/bin/nproc (/proc/cpuinfo exists but cannot be used)
35
- # * BSD: /sbin/sysctl
36
- # * Cygwin: /proc/cpuinfo
37
- # * Darwin: /usr/bin/hwprefs, /usr/sbin/sysctl
38
- # * HP-UX: /usr/sbin/ioscan
39
- # * IRIX: /usr/sbin/sysconf
40
- # * Linux: /proc/cpuinfo
41
- # * Minix 3+: /proc/cpuinfo
42
- # * Solaris: /usr/sbin/psrinfo
43
- # * Tru64 UNIX: /usr/sbin/psrinfo
44
- # * UnixWare: /usr/sbin/psrinfo
45
- #
46
- # @return [Integer] number of processors seen by the OS or Java runtime
47
- #
48
- # @see https://github.com/grosser/parallel/blob/4fc8b89d08c7091fe0419ca8fba1ec3ce5a8d185/lib/parallel.rb
49
- #
50
- # @see http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#availableProcessors()
51
- # @see http://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx
52
16
  def processor_count
53
17
  @processor_count.value
54
18
  end
55
19
 
56
- # Number of physical processor cores on the current system. For performance
57
- # reasons the calculated value will be memoized on the first call.
58
- #
59
- # On Windows the Win32 API will be queried for the `NumberOfCores from
60
- # Win32_Processor`. This will return the total number "of cores for the
61
- # current instance of the processor." On Unix-like operating systems either
62
- # the `hwprefs` or `sysctl` utility will be called in a subshell and the
63
- # returned value will be used. In the rare case where none of these methods
64
- # work or an exception is raised the function will simply return 1.
65
- #
66
- # @return [Integer] number physical processor cores on the current system
67
- #
68
- # @see https://github.com/grosser/parallel/blob/4fc8b89d08c7091fe0419ca8fba1ec3ce5a8d185/lib/parallel.rb
69
- #
70
- # @see http://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx
71
- # @see http://www.unix.com/man-page/osx/1/HWPREFS/
72
- # @see http://linux.die.net/man/8/sysctl
73
20
  def physical_processor_count
74
21
  @physical_processor_count.value
75
22
  end
@@ -79,47 +26,14 @@ module Concurrent
79
26
  def compute_processor_count
80
27
  if Concurrent.on_jruby?
81
28
  java.lang.Runtime.getRuntime.availableProcessors
82
- elsif Etc.respond_to?(:nprocessors) && (nprocessor = Etc.nprocessors rescue nil)
83
- nprocessor
84
29
  else
85
- os_name = RbConfig::CONFIG["target_os"]
86
- if os_name =~ /mingw|mswin/
87
- require 'win32ole'
88
- result = WIN32OLE.connect("winmgmts://").ExecQuery(
89
- "select NumberOfLogicalProcessors from Win32_Processor")
90
- result.to_enum.collect(&:NumberOfLogicalProcessors).reduce(:+)
91
- elsif File.readable?("/proc/cpuinfo") && (cpuinfo_count = IO.read("/proc/cpuinfo").scan(/^processor/).size) > 0
92
- cpuinfo_count
93
- elsif File.executable?("/usr/bin/nproc")
94
- IO.popen("/usr/bin/nproc --all", &:read).to_i
95
- elsif File.executable?("/usr/bin/hwprefs")
96
- IO.popen("/usr/bin/hwprefs thread_count", &:read).to_i
97
- elsif File.executable?("/usr/sbin/psrinfo")
98
- IO.popen("/usr/sbin/psrinfo", &:read).scan(/^.*on-*line/).size
99
- elsif File.executable?("/usr/sbin/ioscan")
100
- IO.popen("/usr/sbin/ioscan -kC processor", &:read).scan(/^.*processor/).size
101
- elsif File.executable?("/usr/sbin/pmcycles")
102
- IO.popen("/usr/sbin/pmcycles -m", &:read).count("\n")
103
- elsif File.executable?("/usr/sbin/lsdev")
104
- IO.popen("/usr/sbin/lsdev -Cc processor -S 1", &:read).count("\n")
105
- elsif File.executable?("/usr/sbin/sysconf") and os_name =~ /irix/i
106
- IO.popen("/usr/sbin/sysconf NPROC_ONLN", &:read).to_i
107
- elsif File.executable?("/usr/sbin/sysctl")
108
- IO.popen("/usr/sbin/sysctl -n hw.ncpu", &:read).to_i
109
- elsif File.executable?("/sbin/sysctl")
110
- IO.popen("/sbin/sysctl -n hw.ncpu", &:read).to_i
111
- else
112
- # TODO (pitr-ch 05-Nov-2016): warn about failures
113
- 1
114
- end
30
+ Etc.nprocessors
115
31
  end
116
- rescue
117
- return 1
118
32
  end
119
33
 
120
34
  def compute_physical_processor_count
121
35
  ppc = case RbConfig::CONFIG["target_os"]
122
- when /darwin1/
36
+ when /darwin\d\d/
123
37
  IO.popen("/usr/sbin/sysctl -n hw.physicalcpu", &:read).to_i
124
38
  when /linux/
125
39
  cores = {} # unique physical ID / core ID combinations
@@ -153,10 +67,43 @@ module Concurrent
153
67
  @processor_counter = Utility::ProcessorCounter.new
154
68
  singleton_class.send :attr_reader, :processor_counter
155
69
 
70
+ # Number of processors seen by the OS and used for process scheduling. For
71
+ # performance reasons the calculated value will be memoized on the first
72
+ # call.
73
+ #
74
+ # When running under JRuby the Java runtime call
75
+ # `java.lang.Runtime.getRuntime.availableProcessors` will be used. According
76
+ # to the Java documentation this "value may change during a particular
77
+ # invocation of the virtual machine... [applications] should therefore
78
+ # occasionally poll this property." Subsequently the result will NOT be
79
+ # memoized under JRuby.
80
+ #
81
+ # Otherwise Ruby's Etc.nprocessors will be used.
82
+ #
83
+ # @return [Integer] number of processors seen by the OS or Java runtime
84
+ #
85
+ # @see http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#availableProcessors()
156
86
  def self.processor_count
157
87
  processor_counter.processor_count
158
88
  end
159
89
 
90
+ # Number of physical processor cores on the current system. For performance
91
+ # reasons the calculated value will be memoized on the first call.
92
+ #
93
+ # On Windows the Win32 API will be queried for the `NumberOfCores from
94
+ # Win32_Processor`. This will return the total number "of cores for the
95
+ # current instance of the processor." On Unix-like operating systems either
96
+ # the `hwprefs` or `sysctl` utility will be called in a subshell and the
97
+ # returned value will be used. In the rare case where none of these methods
98
+ # work or an exception is raised the function will simply return 1.
99
+ #
100
+ # @return [Integer] number physical processor cores on the current system
101
+ #
102
+ # @see https://github.com/grosser/parallel/blob/4fc8b89d08c7091fe0419ca8fba1ec3ce5a8d185/lib/parallel.rb
103
+ #
104
+ # @see http://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx
105
+ # @see http://www.unix.com/man-page/osx/1/HWPREFS/
106
+ # @see http://linux.die.net/man/8/sysctl
160
107
  def self.physical_processor_count
161
108
  processor_counter.physical_processor_count
162
109
  end
@@ -1,3 +1,3 @@
1
1
  module Concurrent
2
- VERSION = '1.1.8'
2
+ VERSION = '1.2.0'
3
3
  end
@@ -1 +1,5 @@
1
- require_relative "./concurrent"
1
+ # This file is here so that there is a file with the same name as the gem that
2
+ # can be required by Bundler.require. Applications should normally
3
+ # require 'concurrent'.
4
+
5
+ require_relative "concurrent"