concurrent-ruby 1.2.2 → 1.3.6

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -2
  3. data/Gemfile +6 -6
  4. data/README.md +7 -3
  5. data/Rakefile +50 -25
  6. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +1 -1
  7. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +1 -1
  8. data/lib/concurrent-ruby/concurrent/agent.rb +2 -2
  9. data/lib/concurrent-ruby/concurrent/array.rb +3 -3
  10. data/lib/concurrent-ruby/concurrent/async.rb +1 -1
  11. data/lib/concurrent-ruby/concurrent/atom.rb +1 -1
  12. data/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb +1 -0
  13. data/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb +23 -20
  14. data/lib/concurrent-ruby/concurrent/collection/ruby_timeout_queue.rb +55 -0
  15. data/lib/concurrent-ruby/concurrent/collection/timeout_queue.rb +18 -0
  16. data/lib/concurrent-ruby/concurrent/concern/logging.rb +17 -12
  17. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  18. data/lib/concurrent-ruby/concurrent/delay.rb +1 -1
  19. data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +6 -4
  20. data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +5 -7
  21. data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +7 -0
  22. data/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb +2 -0
  23. data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +61 -31
  24. data/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb +1 -1
  25. data/lib/concurrent-ruby/concurrent/executor/timer_set.rb +10 -3
  26. data/lib/concurrent-ruby/concurrent/executors.rb +0 -1
  27. data/lib/concurrent-ruby/concurrent/hash.rb +5 -3
  28. data/lib/concurrent-ruby/concurrent/map.rb +3 -3
  29. data/lib/concurrent-ruby/concurrent/mvar.rb +4 -4
  30. data/lib/concurrent-ruby/concurrent/promise.rb +2 -2
  31. data/lib/concurrent-ruby/concurrent/promises.rb +33 -23
  32. data/lib/concurrent-ruby/concurrent/scheduled_task.rb +1 -1
  33. data/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb +1 -1
  34. data/lib/concurrent-ruby/concurrent/synchronization/object.rb +1 -1
  35. data/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb +1 -1
  36. data/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb +1 -1
  37. data/lib/concurrent-ruby/concurrent/timer_task.rb +65 -10
  38. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +116 -6
  39. data/lib/concurrent-ruby/concurrent/version.rb +1 -1
  40. metadata +5 -5
  41. data/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb +0 -927
  42. data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +0 -81
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1cad803df2c0fe187f3208dce2972feaa94daefcbd3749770abe3abfc0642fe9
4
- data.tar.gz: 216b0196496fde70f53cc82b83cd593ec5267a53dcac9a312f254ae627f7761e
3
+ metadata.gz: e27f11f8dd5047c9ca365ca8babf3241defab1d707be5055720d1b905e5aa188
4
+ data.tar.gz: 3c5c5e998d8bd76b3b1faf813b870e779d9546149bb6a88a229659dfd741dd13
5
5
  SHA512:
6
- metadata.gz: 605762fd9c26a5a783dcb834f9db5d818ba2b52431b382a7abd33aaddfcc0df8c5005abf0e1a7ebacf3aced9ebb61ee7080fd59050805422f4fc5593925ae935
7
- data.tar.gz: ae916f03459f583497ab268aa82cc79d24dcddb2c51a86abf86313ad77faf975d10d22048ca03179c6583832fc0e25f3f3c1618de0668f9a2774486d7e15e41c
6
+ metadata.gz: c5cf562bf20ba3f20c5ed974a90b55d5f9f08e70fb4af2b722b296ebc1f2726daf431b7410199f19b310b22da260d85d6508c472ef59356903b51ab1123d4d1d
7
+ data.tar.gz: e187fd07e9e10852e408a6c371be9b734b1821fbc42b7c820440caafa5febef3786cf4fd473bd81f1e28c59e1cb4f177ebeec47ef913ed9445425003022c0a65
data/CHANGELOG.md CHANGED
@@ -1,5 +1,53 @@
1
1
  ## Current
2
2
 
3
+ ## Release v1.3.6 (13 December 2025)
4
+
5
+ concurrent-ruby:
6
+
7
+ * See the [release notes on GitHub](https://github.com/ruby-concurrency/concurrent-ruby/releases/tag/v1.3.6).
8
+
9
+ ## Release v1.3.5, edge v0.7.2 (15 January 2025)
10
+
11
+ concurrent-ruby:
12
+
13
+ * (#1062) Remove dependency on logger.
14
+
15
+ concurrent-ruby-edge:
16
+
17
+ * (#1062) Remove dependency on logger.
18
+
19
+ ## Release v1.3.4 (10 August 2024)
20
+
21
+ * (#1060) Fix bug with return value of `Concurrent.available_processor_count` when `cpu.cfs_quota_us` is -1.
22
+ * (#1058) Add `Concurrent.cpu_shares` that is cgroups aware.
23
+
24
+ ## Release v1.3.3 (9 June 2024)
25
+
26
+ * (#1053) Improve the speed of `Concurrent.physical_processor_count` on Windows.
27
+
28
+ ## Release v1.3.2, edge v0.7.1 (7 June 2024)
29
+
30
+ concurrent-ruby:
31
+
32
+ * (#1051) Remove dependency on `win32ole`.
33
+
34
+ concurrent-ruby-edge:
35
+
36
+ * (#1052) Fix dependency on `concurrent-ruby` to allow the latest release.
37
+
38
+ ## Release v1.3.1 (29 May 2024)
39
+
40
+ * Release 1.3.0 was broken when pushed to RubyGems. 1.3.1 is a packaging fix.
41
+
42
+ ## Release v1.3.0 (28 May 2024)
43
+
44
+ * (#1042) Align Java Executor Service behavior for `shuttingdown?`, `shutdown?`
45
+ * (#1038) Add `Concurrent.available_processor_count` that is cgroups aware.
46
+
47
+ ## Release v1.2.3 (16 Jan 2024)
48
+
49
+ * See [the GitHub release](https://github.com/ruby-concurrency/concurrent-ruby/releases/tag/v1.2.3) for details.
50
+
3
51
  ## Release v1.2.2 (24 Feb 2023)
4
52
 
5
53
  * (#993) Fix arguments passed to `Concurrent::Map`'s `default_proc`.
@@ -264,7 +312,7 @@ concurrent-ruby-edge:
264
312
  * Simplification of `RubySingleThreadExecutor`
265
313
  * `Async` improvements
266
314
  - Each object uses its own `SingleThreadExecutor` instead of the global thread pool.
267
- - No longers supports executor injection
315
+ - No longer supports executor injection
268
316
  - Much better documentation
269
317
  * `Atom` updates
270
318
  - No longer `Dereferenceable`
@@ -439,7 +487,7 @@ Please see the [roadmap](https://github.com/ruby-concurrency/concurrent-ruby/iss
439
487
  * Fixed bug with return value of `Concurrent::Actor::Utils::Pool#ask`
440
488
  * Fixed timing bug in `TimerTask`
441
489
  * Fixed bug when creating a `JavaThreadPoolExecutor` with minimum pool size of zero
442
- * Removed confusing warning when not using native extenstions
490
+ * Removed confusing warning when not using native extensions
443
491
  * Improved documentation
444
492
 
445
493
  ## Release v0.7.0 (13 August 2014)
data/Gemfile CHANGED
@@ -1,18 +1,18 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- require File.join(File.dirname(__FILE__), 'lib/concurrent-ruby/concurrent/version')
4
- require File.join(File.dirname(__FILE__ ), 'lib/concurrent-ruby-edge/concurrent/edge/version')
3
+ version = File.read("#{__dir__}/lib/concurrent-ruby/concurrent/version.rb")[/'(.+)'/, 1] or raise
4
+ edge_version = File.read("#{__dir__}/lib/concurrent-ruby-edge/concurrent/edge/version.rb")[/'(.+)'/, 1] or raise
5
5
 
6
6
  no_path = ENV['NO_PATH']
7
7
  options = no_path ? {} : { path: '.' }
8
8
 
9
- gem 'concurrent-ruby', Concurrent::VERSION, options
10
- gem 'concurrent-ruby-edge', Concurrent::EDGE_VERSION, options
11
- gem 'concurrent-ruby-ext', Concurrent::VERSION, options.merge(platform: :mri)
9
+ gem 'concurrent-ruby', version, options
10
+ gem 'concurrent-ruby-edge', edge_version, options
11
+ gem 'concurrent-ruby-ext', version, options.merge(platform: :mri)
12
12
 
13
13
  group :development do
14
14
  gem 'rake', '~> 13.0'
15
- gem 'rake-compiler', '~> 1.0', '>= 1.0.7'
15
+ gem 'rake-compiler', '~> 1.0', '>= 1.0.7', '!= 1.2.4'
16
16
  gem 'rake-compiler-dock', '~> 1.0'
17
17
  gem 'pry', '~> 0.11', platforms: :mri
18
18
  end
data/README.md CHANGED
@@ -207,7 +207,7 @@ Deprecated features are still available and bugs are being fixed, but new featur
207
207
  These are available in the `concurrent-ruby-edge` companion gem.
208
208
 
209
209
  These features are under active development and may change frequently. They are expected not to
210
- keep backward compatibility (there may also lack tests and documentation). Semantic versions will
210
+ keep backward compatibility (they may also lack tests and documentation). Semantic versions will
211
211
  be obeyed though. Features developed in `concurrent-ruby-edge` are expected to move to
212
212
  `concurrent-ruby` when final.
213
213
 
@@ -284,7 +284,7 @@ To use the tools in the Edge gem it must be required separately:
284
284
  require 'concurrent-edge'
285
285
  ```
286
286
 
287
- If the library does not behave as expected, `Concurrent.use_stdlib_logger(Logger::DEBUG)` could
287
+ If the library does not behave as expected, `Concurrent.use_simple_logger(:DEBUG)` could
288
288
  help to reveal the problem.
289
289
 
290
290
  ## Installation
@@ -358,7 +358,8 @@ best practice is to depend on `concurrent-ruby` and let users to decide if they
358
358
  * Recent CRuby
359
359
  * JRuby, `rbenv install jruby-9.2.17.0`
360
360
  * Set env variable `CONCURRENT_JRUBY_HOME` to point to it, e.g. `/usr/local/opt/rbenv/versions/jruby-9.2.17.0`
361
- * Install Docker, required for Windows builds
361
+ * Install Docker or Podman, required for Windows builds
362
+ * If `bundle config get path` is set, use `bundle config set --local path.system true` otherwise the `gem name, path: '.'` gems won't be found (Bundler limitation).
362
363
 
363
364
  ### Publishing the Gem
364
365
 
@@ -375,7 +376,10 @@ best practice is to depend on `concurrent-ruby` and let users to decide if they
375
376
  * [Benoit Daloze](https://github.com/eregon)
376
377
  * [Matthew Draper](https://github.com/matthewd)
377
378
  * [Rafael França](https://github.com/rafaelfranca)
379
+ * [Charles Oliver Nutter](https://github.com/headius)
380
+ * [Ben Sheldon](https://github.com/bensheldon)
378
381
  * [Samuel Williams](https://github.com/ioquatix)
382
+ * [Joshua Young](https://github.com/joshuay03)
379
383
 
380
384
  ### Special Thanks to
381
385
 
data/Rakefile CHANGED
@@ -1,6 +1,5 @@
1
- require_relative 'lib/concurrent-ruby/concurrent/version'
2
- require_relative 'lib/concurrent-ruby-edge/concurrent/edge/version'
3
- require_relative 'lib/concurrent-ruby/concurrent/utility/engine'
1
+ version = File.read("#{__dir__}/lib/concurrent-ruby/concurrent/version.rb")[/'(.+)'/, 1] or raise
2
+ edge_version = File.read("#{__dir__}/lib/concurrent-ruby-edge/concurrent/edge/version.rb")[/'(.+)'/, 1] or raise
4
3
 
5
4
  core_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby.gemspec')
6
5
  ext_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-ext.gemspec')
@@ -8,14 +7,16 @@ edge_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-edge.
8
7
 
9
8
  require 'rake/javaextensiontask'
10
9
 
11
- ENV['JRUBY_HOME'] = ENV['CONCURRENT_JRUBY_HOME'] if ENV['CONCURRENT_JRUBY_HOME'] && !Concurrent.on_jruby?
10
+ ENV['JRUBY_HOME'] = ENV['CONCURRENT_JRUBY_HOME'] if ENV['CONCURRENT_JRUBY_HOME'] && RUBY_ENGINE != 'jruby'
12
11
 
13
12
  Rake::JavaExtensionTask.new('concurrent_ruby', core_gemspec) do |ext|
14
13
  ext.ext_dir = 'ext/concurrent-ruby'
15
14
  ext.lib_dir = 'lib/concurrent-ruby/concurrent'
15
+ ext.source_version = '8'
16
+ ext.target_version = '8'
16
17
  end
17
18
 
18
- unless Concurrent.on_jruby? || Concurrent.on_truffleruby?
19
+ if RUBY_ENGINE == 'ruby'
19
20
  require 'rake/extensiontask'
20
21
 
21
22
  Rake::ExtensionTask.new('concurrent_ruby_ext', ext_gemspec) do |ext|
@@ -28,6 +29,10 @@ unless Concurrent.on_jruby? || Concurrent.on_truffleruby?
28
29
  end
29
30
  end
30
31
 
32
+ def which?(executable)
33
+ !`which #{executable} 2>/dev/null`.empty?
34
+ end
35
+
31
36
  require 'rake_compiler_dock'
32
37
  namespace :repackage do
33
38
  desc '* with Windows fat distributions'
@@ -42,12 +47,19 @@ namespace :repackage do
42
47
  Rake::Task['lib/concurrent-ruby/concurrent/concurrent_ruby.jar'].invoke
43
48
 
44
49
  # build all gem files
50
+ rack_compiler_dock_kwargs = {}
51
+ if which?('podman') and (!which?('docker') || `docker --version`.include?('podman'))
52
+ # podman and only podman available, so RakeCompilerDock will use podman, otherwise it uses docker
53
+ rack_compiler_dock_kwargs = {
54
+ options: ['--privileged'], # otherwise the directory in the image is empty
55
+ runas: false
56
+ }
57
+ end
45
58
  %w[x86-mingw32 x64-mingw32].each do |plat|
46
59
  RakeCompilerDock.sh(
47
60
  "bundle install --local && bundle exec rake native:#{plat} gem --trace",
48
61
  platform: plat,
49
- options: ['--privileged'], # otherwise the directory in the image is empty
50
- runas: false)
62
+ **rack_compiler_dock_kwargs)
51
63
  end
52
64
  end
53
65
  end
@@ -57,7 +69,7 @@ require 'rubygems'
57
69
  require 'rubygems/package_task'
58
70
 
59
71
  Gem::PackageTask.new(core_gemspec) {} if core_gemspec
60
- Gem::PackageTask.new(ext_gemspec) {} if ext_gemspec && !Concurrent.on_jruby?
72
+ Gem::PackageTask.new(ext_gemspec) {} if ext_gemspec && RUBY_ENGINE != 'jruby'
61
73
  Gem::PackageTask.new(edge_gemspec) {} if edge_gemspec
62
74
 
63
75
  CLEAN.include(
@@ -85,9 +97,9 @@ begin
85
97
  task :installed do
86
98
  Bundler.with_original_env do
87
99
  Dir.chdir(__dir__) do
88
- sh "gem install pkg/concurrent-ruby-#{Concurrent::VERSION}.gem"
89
- sh "gem install pkg/concurrent-ruby-ext-#{Concurrent::VERSION}.gem" if Concurrent.on_cruby?
90
- sh "gem install pkg/concurrent-ruby-edge-#{Concurrent::EDGE_VERSION}.gem"
100
+ sh "gem install pkg/concurrent-ruby-#{version}.gem"
101
+ sh "gem install pkg/concurrent-ruby-ext-#{version}.gem" if RUBY_ENGINE == 'ruby'
102
+ sh "gem install pkg/concurrent-ruby-edge-#{edge_version}.gem"
91
103
  ENV['NO_PATH'] = 'true'
92
104
  sh 'bundle update'
93
105
  sh 'bundle exec rake spec:ci'
@@ -117,7 +129,7 @@ rescue LoadError => e
117
129
  puts 'RSpec is not installed, skipping test task definitions: ' + e.message
118
130
  end
119
131
 
120
- current_yard_version_name = Concurrent::VERSION
132
+ current_yard_version_name = version
121
133
 
122
134
  begin
123
135
  require 'yard'
@@ -221,6 +233,8 @@ namespace :release do
221
233
  # Depends on environment of @pitr-ch
222
234
 
223
235
  task :checks do
236
+ raise '$CONCURRENT_JRUBY_HOME must be set' unless ENV['CONCURRENT_JRUBY_HOME']
237
+
224
238
  Dir.chdir(__dir__) do
225
239
  sh 'test -z "$(git status --porcelain)"' do |ok, res|
226
240
  unless ok
@@ -251,15 +265,19 @@ namespace :release do
251
265
 
252
266
  desc '* test actual installed gems instead of cloned repository on MRI and JRuby'
253
267
  task :test do
268
+ raise '$CONCURRENT_JRUBY_HOME must be set' unless ENV['CONCURRENT_JRUBY_HOME']
269
+
254
270
  Dir.chdir(__dir__) do
255
271
  puts "Testing with the installed gem"
256
272
 
257
273
  Bundler.with_original_env do
258
274
  sh 'ruby -v'
275
+ sh 'bundle install'
259
276
  sh 'bundle exec rake spec:installed'
260
277
 
261
- env = { "PATH" => "#{ENV['CONCURRENT_JRUBY_HOME']}/bin:#{ENV['PATH']}" }
278
+ env = { "PATH" => "#{ENV.fetch('CONCURRENT_JRUBY_HOME')}/bin:#{ENV['PATH']}" }
262
279
  sh env, 'ruby -v'
280
+ sh env, 'bundle install'
263
281
  sh env, 'bundle exec rake spec:installed'
264
282
  end
265
283
 
@@ -271,8 +289,8 @@ namespace :release do
271
289
  task :publish => ['publish:ask', 'publish:tag', 'publish:rubygems', 'publish:post_steps']
272
290
 
273
291
  namespace :publish do
274
- publish_base = true
275
- publish_edge = false
292
+ publish_base = nil
293
+ publish_edge = nil
276
294
 
277
295
  task :ask do
278
296
  begin
@@ -280,8 +298,15 @@ namespace :release do
280
298
  input = STDIN.gets.strip.downcase
281
299
  end until %w(y n).include?(input)
282
300
  exit 1 if input == 'n'
301
+
302
+ begin
303
+ STDOUT.puts 'Do you want to publish `concurrent-ruby`? (y/n)'
304
+ input = STDIN.gets.strip.downcase
305
+ end until %w(y n).include?(input)
306
+ publish_base = input == 'y'
307
+
283
308
  begin
284
- STDOUT.puts 'It will publish `concurrent-ruby`. Do you want to publish `concurrent-ruby-edge`? (y/n)'
309
+ STDOUT.puts 'Do you want to publish `concurrent-ruby-edge`? (y/n)'
285
310
  input = STDIN.gets.strip.downcase
286
311
  end until %w(y n).include?(input)
287
312
  publish_edge = input == 'y'
@@ -290,21 +315,21 @@ namespace :release do
290
315
  desc '** tag HEAD with current version and push to github'
291
316
  task :tag => :ask do
292
317
  Dir.chdir(__dir__) do
293
- sh "git tag v#{Concurrent::VERSION}" if publish_base
294
- sh "git push origin v#{Concurrent::VERSION}" if publish_base
295
- sh "git tag edge-v#{Concurrent::EDGE_VERSION}" if publish_edge
296
- sh "git push origin edge-v#{Concurrent::EDGE_VERSION}" if publish_edge
318
+ sh "git tag v#{version}" if publish_base
319
+ sh "git push origin v#{version}" if publish_base
320
+ sh "git tag edge-v#{edge_version}" if publish_edge
321
+ sh "git push origin edge-v#{edge_version}" if publish_edge
297
322
  end
298
323
  end
299
324
 
300
325
  desc '** push all *.gem files to rubygems'
301
326
  task :rubygems => :ask do
302
327
  Dir.chdir(__dir__) do
303
- sh "gem push pkg/concurrent-ruby-#{Concurrent::VERSION}.gem" if publish_base
304
- sh "gem push pkg/concurrent-ruby-edge-#{Concurrent::EDGE_VERSION}.gem" if publish_edge
305
- sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}.gem" if publish_base
306
- sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}-x64-mingw32.gem" if publish_base
307
- sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}-x86-mingw32.gem" if publish_base
328
+ sh "gem push pkg/concurrent-ruby-#{version}.gem" if publish_base
329
+ sh "gem push pkg/concurrent-ruby-edge-#{edge_version}.gem" if publish_edge
330
+ sh "gem push pkg/concurrent-ruby-ext-#{version}.gem" if publish_base
331
+ sh "gem push pkg/concurrent-ruby-ext-#{version}-x64-mingw32.gem" if publish_base
332
+ sh "gem push pkg/concurrent-ruby-ext-#{version}-x86-mingw32.gem" if publish_base
308
333
  end
309
334
  end
310
335
 
@@ -481,7 +481,7 @@ public class ConcurrentHashMapV8<K, V>
481
481
  *
482
482
  * Maintaining API and serialization compatibility with previous
483
483
  * versions of this class introduces several oddities. Mainly: We
484
- * leave untouched but unused constructor arguments refering to
484
+ * leave untouched but unused constructor arguments referring to
485
485
  * concurrencyLevel. We accept a loadFactor constructor argument,
486
486
  * but apply it only to initial table capacity (which is the only
487
487
  * time that we can guarantee to honor it.) We also declare an
@@ -484,7 +484,7 @@ public class ConcurrentHashMapV8<K, V>
484
484
  *
485
485
  * Maintaining API and serialization compatibility with previous
486
486
  * versions of this class introduces several oddities. Mainly: We
487
- * leave untouched but unused constructor arguments refering to
487
+ * leave untouched but unused constructor arguments referring to
488
488
  * concurrencyLevel. We accept a loadFactor constructor argument,
489
489
  * but apply it only to initial table capacity (which is the only
490
490
  * time that we can guarantee to honor it.) We also declare an
@@ -371,7 +371,7 @@ module Concurrent
371
371
  # @param [Float] timeout the maximum number of seconds to wait
372
372
  # @return [Boolean] true if all actions complete before timeout
373
373
  #
374
- # @raise [Concurrent::TimeoutError] when timout is reached
374
+ # @raise [Concurrent::TimeoutError] when timeout is reached
375
375
  #
376
376
  # @!macro agent_await_warning
377
377
  def await_for!(timeout)
@@ -477,7 +477,7 @@ module Concurrent
477
477
  # @param [Array<Concurrent::Agent>] agents the Agents on which to wait
478
478
  # @return [Boolean] true if all actions complete before timeout
479
479
  #
480
- # @raise [Concurrent::TimeoutError] when timout is reached
480
+ # @raise [Concurrent::TimeoutError] when timeout is reached
481
481
  # @!macro agent_await_warning
482
482
  def await_for!(timeout, *agents)
483
483
  raise Concurrent::TimeoutError unless await_for(timeout, *agents)
@@ -21,9 +21,9 @@ module Concurrent
21
21
  # @!macro internal_implementation_note
22
22
  ArrayImplementation = case
23
23
  when Concurrent.on_cruby?
24
- # Array is thread-safe in practice because CRuby runs
25
- # threads one at a time and does not do context
26
- # switching during the execution of C functions.
24
+ # Array is not fully thread-safe on CRuby, see
25
+ # https://github.com/ruby-concurrency/concurrent-ruby/issues/929
26
+ # So we will need to add synchronization here
27
27
  ::Array
28
28
 
29
29
  when Concurrent.on_jruby?
@@ -218,7 +218,7 @@ module Concurrent
218
218
 
219
219
  # @!method self.new(*args, &block)
220
220
  #
221
- # Instanciate a new object and ensure proper initialization of the
221
+ # Instantiate a new object and ensure proper initialization of the
222
222
  # synchronization mechanisms.
223
223
  #
224
224
  # @param [Array<Object>] args Zero or more arguments to be passed to the
@@ -113,7 +113,7 @@ module Concurrent
113
113
  # @option opts [Proc] :validator (nil) Optional proc used to validate new
114
114
  # values. It must accept one and only one argument which will be the
115
115
  # intended new value. The validator will return true if the new value
116
- # is acceptable else return false (preferrably) or raise an exception.
116
+ # is acceptable else return false (preferably) or raise an exception.
117
117
  #
118
118
  # @!macro deref_options
119
119
  #
@@ -6,6 +6,7 @@ module Concurrent
6
6
  # @!visibility private
7
7
  def self.mutex_owned_per_thread?
8
8
  return false if Concurrent.on_jruby? || Concurrent.on_truffleruby?
9
+ return RUBY_VERSION < "3.0" if Concurrent.on_cruby?
9
10
 
10
11
  mutex = Mutex.new
11
12
  # Lock the mutex:
@@ -8,74 +8,77 @@ module Concurrent
8
8
  # @!visibility private
9
9
  class SynchronizedMapBackend < NonConcurrentMapBackend
10
10
 
11
- require 'mutex_m'
12
- include Mutex_m
13
- # WARNING: Mutex_m is a non-reentrant lock, so the synchronized methods are
14
- # not allowed to call each other.
11
+ def initialize(*args, &block)
12
+ super
13
+
14
+ # WARNING: Mutex is a non-reentrant lock, so the synchronized methods are
15
+ # not allowed to call each other.
16
+ @mutex = Mutex.new
17
+ end
15
18
 
16
19
  def [](key)
17
- synchronize { super }
20
+ @mutex.synchronize { super }
18
21
  end
19
22
 
20
23
  def []=(key, value)
21
- synchronize { super }
24
+ @mutex.synchronize { super }
22
25
  end
23
26
 
24
27
  def compute_if_absent(key)
25
- synchronize { super }
28
+ @mutex.synchronize { super }
26
29
  end
27
30
 
28
31
  def compute_if_present(key)
29
- synchronize { super }
32
+ @mutex.synchronize { super }
30
33
  end
31
34
 
32
35
  def compute(key)
33
- synchronize { super }
36
+ @mutex.synchronize { super }
34
37
  end
35
38
 
36
39
  def merge_pair(key, value)
37
- synchronize { super }
40
+ @mutex.synchronize { super }
38
41
  end
39
42
 
40
43
  def replace_pair(key, old_value, new_value)
41
- synchronize { super }
44
+ @mutex.synchronize { super }
42
45
  end
43
46
 
44
47
  def replace_if_exists(key, new_value)
45
- synchronize { super }
48
+ @mutex.synchronize { super }
46
49
  end
47
50
 
48
51
  def get_and_set(key, value)
49
- synchronize { super }
52
+ @mutex.synchronize { super }
50
53
  end
51
54
 
52
55
  def key?(key)
53
- synchronize { super }
56
+ @mutex.synchronize { super }
54
57
  end
55
58
 
56
59
  def delete(key)
57
- synchronize { super }
60
+ @mutex.synchronize { super }
58
61
  end
59
62
 
60
63
  def delete_pair(key, value)
61
- synchronize { super }
64
+ @mutex.synchronize { super }
62
65
  end
63
66
 
64
67
  def clear
65
- synchronize { super }
68
+ @mutex.synchronize { super }
66
69
  end
67
70
 
68
71
  def size
69
- synchronize { super }
72
+ @mutex.synchronize { super }
70
73
  end
71
74
 
72
75
  def get_or_default(key, default_value)
73
- synchronize { super }
76
+ @mutex.synchronize { super }
74
77
  end
75
78
 
76
79
  private
77
80
  def dupped_backend
78
- synchronize { super }
81
+ @mutex.synchronize { super }
79
82
  end
80
83
  end
81
84
  end
@@ -0,0 +1,55 @@
1
+ module Concurrent
2
+ module Collection
3
+ # @!visibility private
4
+ # @!macro ruby_timeout_queue
5
+ class RubyTimeoutQueue < ::Queue
6
+ def initialize(*args)
7
+ if RUBY_VERSION >= '3.2'
8
+ raise "#{self.class.name} is not needed on Ruby 3.2 or later, use ::Queue instead"
9
+ end
10
+
11
+ super(*args)
12
+
13
+ @mutex = Mutex.new
14
+ @cond_var = ConditionVariable.new
15
+ end
16
+
17
+ def push(obj)
18
+ @mutex.synchronize do
19
+ super(obj)
20
+ @cond_var.signal
21
+ end
22
+ end
23
+ alias_method :enq, :push
24
+ alias_method :<<, :push
25
+
26
+ def pop(non_block = false, timeout: nil)
27
+ if non_block && timeout
28
+ raise ArgumentError, "can't set a timeout if non_block is enabled"
29
+ end
30
+
31
+ if non_block
32
+ super(true)
33
+ elsif timeout
34
+ @mutex.synchronize do
35
+ deadline = Concurrent.monotonic_time + timeout
36
+ while (now = Concurrent.monotonic_time) < deadline && empty?
37
+ @cond_var.wait(@mutex, deadline - now)
38
+ end
39
+ begin
40
+ return super(true)
41
+ rescue ThreadError
42
+ # still empty
43
+ nil
44
+ end
45
+ end
46
+ else
47
+ super(false)
48
+ end
49
+ end
50
+ alias_method :deq, :pop
51
+ alias_method :shift, :pop
52
+ end
53
+ private_constant :RubyTimeoutQueue
54
+ end
55
+ end
@@ -0,0 +1,18 @@
1
+ module Concurrent
2
+ module Collection
3
+ # @!visibility private
4
+ # @!macro internal_implementation_note
5
+ TimeoutQueueImplementation = if RUBY_VERSION >= '3.2'
6
+ ::Queue
7
+ else
8
+ require 'concurrent/collection/ruby_timeout_queue'
9
+ RubyTimeoutQueue
10
+ end
11
+ private_constant :TimeoutQueueImplementation
12
+
13
+ # @!visibility private
14
+ # @!macro timeout_queue
15
+ class TimeoutQueue < TimeoutQueueImplementation
16
+ end
17
+ end
18
+ end