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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 207cadfd4ec0e25f6ba9881ef8f32ea86c5772074d4aff5e2ab5d5bdf4613e09
4
- data.tar.gz: b41c0dd080a6d2fbf1d2c97bf2e9a8db0e99849ba875d32ade39384838e20e23
3
+ metadata.gz: f224c72d89a1bd079ad1086c9ed28a1d4d6432c718b9e0624c9a32afc8500cc8
4
+ data.tar.gz: dfb811189c8e7eeb2ea1f17fc1e680657dffe767c77bb09312e85a4f29f2bd60
5
5
  SHA512:
6
- metadata.gz: 4edf0b84df6aa42a69c6ff231c730d12a64df6819ebea508599b469d88951c47ce4b091d3f3fc41afcb9196986091efe57d156161510f03cfb8ee0ebaf66ff0c
7
- data.tar.gz: a18c3ef751cadd220d424779e96d96ead76362ad4e7bfcfb2341d9ba4baed6f0b8427c452e31868e512ab2b3a8226fe350041e0e5b87cd28e10d9ce1b5334c72
6
+ metadata.gz: 807b1aac5e1bdee569df0b9e38fff1ed339f2c8569cd0a7ab565cbbecb23ffc9c6cf968e457e2acecf3abd187ac43da16dc2fb91716c912e78c08aa122dcaf0e
7
+ data.tar.gz: 07c37140aa1417ad32daa0de92f4c0883c7a96c1c53fba9aa09e34598632b3ad274283034064df41181e59964d0c79e41d083f17912e8e121c4f2d774c988b81
data/CHANGELOG.md CHANGED
@@ -1,7 +1,43 @@
1
1
  ## Current
2
2
 
3
+ ## Release v1.2.0 (23 Jan 2023)
4
+
5
+ * (#962) Fix ReentrantReadWriteLock to use the same granularity for locals as for Mutex it uses.
6
+ * (#983) Add FiberLocalVar
7
+ * (#934) concurrent-ruby now supports requiring individual classes (public classes listed in the docs), e.g., `require 'concurrent/map'`
8
+ * (#976) Let `Promises.any_fulfilled_future` take an `Event`
9
+ * Improve documentation of various classes
10
+ * (#975) Set the Ruby compatibility version at 2.3
11
+ * (#972) Remove Rubinius-related code
12
+
13
+ ## Release v1.1.10 (22 Mar 2022)
14
+
15
+ concurrent-ruby:
16
+
17
+ * (#951) Set the Ruby compatibility version at 2.2
18
+ * (#939, #933) The `caller_runs` fallback policy no longer blocks reads from the job queue by worker threads
19
+ * (#938, #761, #652) You can now explicitly `prune_pool` a thread pool (Sylvain Joyeux)
20
+ * (#937, #757, #670) We switched the Yahoo stock API for demos to Alpha Vantage (Gustavo Caso)
21
+ * (#932, #931) We changed how `SafeTaskExecutor` handles local jump errors (Aaron Jensen)
22
+ * (#927) You can use keyword arguments in your initialize when using `Async` (Matt Larraz)
23
+ * (#926, #639) We removed timeout from `TimerTask` because it wasn't sound, and now it's a no-op with a warning (Jacob Atzen)
24
+ * (#919) If you double-lock a re-entrant read-write lock, we promote to locked for writing (zp yuan)
25
+ * (#915) `monotonic_time` now accepts an optional unit parameter, as Ruby's `clock_gettime` (Jean Boussier)
26
+
27
+ ## Release v1.1.9 (5 Jun 2021)
28
+
29
+ concurrent-ruby:
30
+
31
+ * (#866) Child promise state not set to :pending immediately after #execute when parent has completed
32
+ * (#905, #872) Fix RubyNonConcurrentPriorityQueue#delete method
33
+ * (2df0337d) Make sure locks are not shared on shared when objects are dup/cloned
34
+ * (#900, #906, #796, #847, #911) Fix Concurrent::Set tread-safety issues on CRuby
35
+ * (#907) Add new ConcurrentMap backend for TruffleRuby
36
+
3
37
  ## Release v1.1.8 (20 January 2021)
4
38
 
39
+ concurrent-ruby:
40
+
5
41
  * (#885) Fix race condition in TVar for stale reads
6
42
  * (#884) RubyThreadLocalVar: Do not iterate over hash which might conflict with new pair addition
7
43
 
data/Gemfile CHANGED
@@ -2,7 +2,6 @@ source 'https://rubygems.org'
2
2
 
3
3
  require File.join(File.dirname(__FILE__), 'lib/concurrent-ruby/concurrent/version')
4
4
  require File.join(File.dirname(__FILE__ ), 'lib/concurrent-ruby-edge/concurrent/edge/version')
5
- require File.join(File.dirname(__FILE__ ), 'lib/concurrent-ruby/concurrent/utility/engine')
6
5
 
7
6
  no_path = ENV['NO_PATH']
8
7
  options = no_path ? {} : { path: '.' }
@@ -12,7 +11,7 @@ gem 'concurrent-ruby-edge', Concurrent::EDGE_VERSION, options
12
11
  gem 'concurrent-ruby-ext', Concurrent::VERSION, options.merge(platform: :mri)
13
12
 
14
13
  group :development do
15
- gem 'rake', (Concurrent.ruby_version :<, 2, 2, 0) ? '~> 12.0' : '~> 13.0'
14
+ gem 'rake', '~> 13.0'
16
15
  gem 'rake-compiler', '~> 1.0', '>= 1.0.7'
17
16
  gem 'rake-compiler-dock', '~> 1.0'
18
17
  gem 'pry', '~> 0.11', platforms: :mri
@@ -26,7 +25,7 @@ end
26
25
 
27
26
  group :testing do
28
27
  gem 'rspec', '~> 3.7'
29
- gem 'timecop', '~> 0.7.4'
28
+ gem 'timecop', '~> 0.9'
30
29
  gem 'sigdump', require: false
31
30
  end
32
31
 
@@ -35,8 +34,3 @@ group :coverage, optional: !ENV['COVERAGE'] do
35
34
  gem 'simplecov', '~> 0.16.0', require: false
36
35
  gem 'coveralls', '~> 0.8.2', require: false
37
36
  end
38
-
39
- group :benchmarks, optional: true do
40
- gem 'benchmark-ips', '~> 2.7'
41
- gem 'bench9000'
42
- end
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # Concurrent Ruby
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/concurrent-ruby.svg)](http://badge.fury.io/rb/concurrent-ruby)
4
- [![Build Status](https://travis-ci.org/ruby-concurrency/concurrent-ruby.svg?branch=master)](https://travis-ci.org/ruby-concurrency/concurrent-ruby)
5
- [![Build status](https://ci.appveyor.com/api/projects/status/iq8aboyuu3etad4w?svg=true)](https://ci.appveyor.com/project/rubyconcurrency/concurrent-ruby)
6
4
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](http://opensource.org/licenses/MIT)
7
5
  [![Gitter chat](https://img.shields.io/badge/IRC%20(gitter)-devs%20%26%20users-brightgreen.svg)](https://gitter.im/ruby-concurrency/concurrent-ruby)
8
6
 
@@ -39,11 +37,13 @@ The design goals of this gem are:
39
37
  appreciate your help. Would you like to contribute? Great! Have a look at
40
38
  [issues with `looking-for-contributor` label](https://github.com/ruby-concurrency/concurrent-ruby/issues?q=is%3Aissue+is%3Aopen+label%3Alooking-for-contributor).** And if you pick something up let us know on the issue.
41
39
 
40
+ You can also get started by triaging issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to concurrent-ruby on CodeTriage](https://www.codetriage.com/ruby-concurrency/concurrent-ruby). [![Open Source Helpers](https://www.codetriage.com/ruby-concurrency/concurrent-ruby/badges/users.svg)](https://www.codetriage.com/ruby-concurrency/concurrent-ruby)
41
+
42
42
  ## Thread Safety
43
43
 
44
44
  *Concurrent Ruby makes one of the strongest thread safety guarantees of any Ruby concurrency
45
- library, providing consistent behavior and guarantees on all four of the main Ruby interpreters
46
- (MRI/CRuby, JRuby, Rubinius, TruffleRuby).*
45
+ library, providing consistent behavior and guarantees on all three main Ruby interpreters
46
+ (MRI/CRuby, JRuby, TruffleRuby).*
47
47
 
48
48
  Every abstraction in this library is thread safe. Specific thread safety guarantees are documented
49
49
  with each abstraction.
@@ -58,9 +58,9 @@ other Ruby library, many of which support the mantra of
58
58
  Concurrent Ruby is also the only Ruby library which provides a full suite of thread safe and
59
59
  immutable variable types and data structures.
60
60
 
61
- We've also initiated discussion to document [memory model](docs-source/synchronization.md) of Ruby which
62
- would provide consistent behaviour and guarantees on all four of the main Ruby interpreters
63
- (MRI/CRuby, JRuby, Rubinius, TruffleRuby).
61
+ We've also initiated discussion to document the [memory model](docs-source/synchronization.md) of Ruby which
62
+ would provide consistent behaviour and guarantees on all three main Ruby interpreters
63
+ (MRI/CRuby, JRuby, TruffleRuby).
64
64
 
65
65
  ## Features & Documentation
66
66
 
@@ -259,16 +259,9 @@ be obeyed though. Features developed in `concurrent-ruby-edge` are expected to m
259
259
 
260
260
  ## Supported Ruby versions
261
261
 
262
- * MRI 2.0 and above
263
- * JRuby 9000
264
- * TruffleRuby are supported.
265
- * Any Ruby interpreter that is compliant with Ruby 2.0 or newer.
266
-
267
- Actually we still support mri 1.9.3 and jruby 1.7.27 but we are looking at ways how to drop the support.
268
- Java 8 is preferred for JRuby but every Java version on which JRuby 9000 runs is supported.
269
-
270
- The legacy support for Rubinius is kept but it is no longer maintained, if you would like to help
271
- please respond to [#739](https://github.com/ruby-concurrency/concurrent-ruby/issues/739).
262
+ * MRI 2.3 and above
263
+ * Latest JRuby 9000
264
+ * Latest TruffleRuby
272
265
 
273
266
  ## Usage
274
267
 
@@ -278,7 +271,12 @@ Everything within this gem can be loaded simply by requiring it:
278
271
  require 'concurrent'
279
272
  ```
280
273
 
281
- *Requiring only specific abstractions from Concurrent Ruby is not yet supported.*
274
+ You can also require a specific abstraction [part of the public documentation](https://ruby-concurrency.github.io/concurrent-ruby/master/index.html) since concurrent-ruby 1.2.0, for example:
275
+ ```ruby
276
+ require 'concurrent/map'
277
+ require 'concurrent/atomic/atomic_reference'
278
+ require 'concurrent/executor/fixed_thread_pool'
279
+ ```
282
280
 
283
281
  To use the tools in the Edge gem it must be required separately:
284
282
 
@@ -353,23 +351,46 @@ and load the appropriate C extensions.
353
351
  No gems should depend on `concurrent-ruby-ext`. Doing so will force C extensions on your users. The
354
352
  best practice is to depend on `concurrent-ruby` and let users to decide if they want C extensions.
355
353
 
354
+ ## Building the gem
355
+
356
+ ### Requirements
357
+
358
+ * Recent CRuby
359
+ * JRuby, `rbenv install jruby-9.2.17.0`
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
362
+
363
+ ### Publishing the Gem
364
+
365
+ * Update `version.rb`
366
+ * Update the CHANGELOG
367
+ * Add the new version to `docs-source/signpost.md`. Needs to be done only if there are visible changes in the documentation.
368
+ * Commit (and push) the changes.
369
+ * Use `bundle exec rake release` to release the gem.
370
+ It consists of `['release:checks', 'release:build', 'release:test', 'release:publish']` steps.
371
+ It will ask at the end before publishing anything. Steps can also be executed individually.
372
+
356
373
  ## Maintainers
357
374
 
358
- * [Petr Chalupa](https://github.com/pitr-ch) (lead maintainer, point-of-contact)
359
- * [Jerry D'Antonio](https://github.com/jdantonio) (creator)
360
- * [Chris Seaton](https://github.com/chrisseaton)
375
+ * [Benoit Daloze](https://github.com/eregon)
376
+ * [Matthew Draper](https://github.com/matthewd)
377
+ * [Rafael França](https://github.com/rafaelfranca)
378
+ * [Samuel Williams](https://github.com/ioquatix)
361
379
 
362
380
  ### Special Thanks to
363
381
 
364
- * [Brian Durand](https://github.com/bdurand) for the `ref` gem
365
- * [Charles Oliver Nutter](https://github.com/headius) for the `atomic` and `thread_safe` gems
366
- * [thedarkone](https://github.com/thedarkone) for the `thread_safe` gem
382
+ * [Jerry D'Antonio](https://github.com/jdantonio) for creating the gem
383
+ * [Brian Durand](https://github.com/bdurand) for the `ref` gem
384
+ * [Charles Oliver Nutter](https://github.com/headius) for the `atomic` and `thread_safe` gems
385
+ * [thedarkone](https://github.com/thedarkone) for the `thread_safe` gem
367
386
 
368
- and to the past maintainers
387
+ to the past maintainers
369
388
 
370
- * [Michele Della Torre](https://github.com/mighe)
371
- * [Paweł Obrok](https://github.com/obrok)
372
- * [Lucas Allan](https://github.com/lucasallan)
389
+ * [Chris Seaton](https://github.com/chrisseaton)
390
+ * [Petr Chalupa](https://github.com/pitr-ch)
391
+ * [Michele Della Torre](https://github.com/mighe)
392
+ * [Paweł Obrok](https://github.com/obrok)
393
+ * [Lucas Allan](https://github.com/lucasallan)
373
394
 
374
395
  and to [Ruby Association](https://www.ruby.or.jp/en/) for sponsoring a project
375
396
  ["Enhancing Ruby’s concurrency tooling"](https://www.ruby.or.jp/en/news/20181106) in 2018.
data/Rakefile CHANGED
@@ -2,15 +2,6 @@ require_relative 'lib/concurrent-ruby/concurrent/version'
2
2
  require_relative 'lib/concurrent-ruby-edge/concurrent/edge/version'
3
3
  require_relative 'lib/concurrent-ruby/concurrent/utility/engine'
4
4
 
5
- if Concurrent.ruby_version :<, 2, 0, 0
6
- # @!visibility private
7
- module Kernel
8
- def __dir__
9
- File.dirname __FILE__
10
- end
11
- end
12
- end
13
-
14
5
  core_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby.gemspec')
15
6
  ext_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-ext.gemspec')
16
7
  edge_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-edge.gemspec')
@@ -24,7 +15,7 @@ Rake::JavaExtensionTask.new('concurrent_ruby', core_gemspec) do |ext|
24
15
  ext.lib_dir = 'lib/concurrent-ruby/concurrent'
25
16
  end
26
17
 
27
- unless Concurrent.on_jruby?
18
+ unless Concurrent.on_jruby? || Concurrent.on_truffleruby?
28
19
  require 'rake/extensiontask'
29
20
 
30
21
  Rake::ExtensionTask.new('concurrent_ruby_ext', ext_gemspec) do |ext|
@@ -43,14 +34,20 @@ namespace :repackage do
43
34
  task :all do
44
35
  Dir.chdir(__dir__) do
45
36
  # store gems in vendor cache for docker
46
- sh 'bundle package'
37
+ Bundler.with_original_env do
38
+ sh 'bundle package'
39
+ end
47
40
 
48
41
  # build only the jar file not the whole gem for java platform, the jar is part the concurrent-ruby-x.y.z.gem
49
42
  Rake::Task['lib/concurrent-ruby/concurrent/concurrent_ruby.jar'].invoke
50
43
 
51
44
  # build all gem files
52
45
  %w[x86-mingw32 x64-mingw32].each do |plat|
53
- RakeCompilerDock.sh "bundle install --local && bundle exec rake native:#{plat} gem --trace", platform: plat
46
+ RakeCompilerDock.sh(
47
+ "bundle install --local && bundle exec rake native:#{plat} gem --trace",
48
+ platform: plat,
49
+ options: ['--privileged'], # otherwise the directory in the image is empty
50
+ runas: false)
54
51
  end
55
52
  end
56
53
  end
@@ -63,7 +60,10 @@ Gem::PackageTask.new(core_gemspec) {} if core_gemspec
63
60
  Gem::PackageTask.new(ext_gemspec) {} if ext_gemspec && !Concurrent.on_jruby?
64
61
  Gem::PackageTask.new(edge_gemspec) {} if edge_gemspec
65
62
 
66
- CLEAN.include('lib/concurrent-ruby/concurrent/2.*', 'lib/concurrent-ruby/concurrent/*.jar')
63
+ CLEAN.include(
64
+ 'lib/concurrent-ruby/concurrent/concurrent_ruby_ext.*',
65
+ 'lib/concurrent-ruby/concurrent/2.*',
66
+ 'lib/concurrent-ruby/concurrent/*.jar')
67
67
 
68
68
  begin
69
69
  require 'rspec'
@@ -77,20 +77,21 @@ begin
77
77
  options = %w[ --color
78
78
  --backtrace
79
79
  --order defined
80
- --format documentation
81
- --tag ~notravis ]
80
+ --format documentation ]
82
81
  t.rspec_opts = [*options].join(' ')
83
82
  end
84
83
 
85
84
  desc '* test packaged and installed gems instead of local files'
86
85
  task :installed do
87
- 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"
91
- ENV['NO_PATH'] = 'true'
92
- sh 'bundle update'
93
- sh 'bundle exec rake spec:ci'
86
+ Bundler.with_original_env do
87
+ 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"
91
+ ENV['NO_PATH'] = 'true'
92
+ sh 'bundle update'
93
+ sh 'bundle exec rake spec:ci'
94
+ end
94
95
  end
95
96
  end
96
97
  end
@@ -98,6 +99,19 @@ begin
98
99
  desc 'executed in CI'
99
100
  task :ci => [:compile, 'spec:ci']
100
101
 
102
+ desc 'run each spec file in a separate process to help find missing requires'
103
+ task 'spec:isolated' do
104
+ glob = "#{ENV['DIR'] || 'spec'}/**/*_spec.rb"
105
+ from = ENV['FROM']
106
+ env = { 'ISOLATED' => 'true' }
107
+ Dir[glob].each do |spec|
108
+ next if from and from != spec
109
+ from = nil if from == spec
110
+
111
+ sh env, 'rspec', spec
112
+ end
113
+ end
114
+
101
115
  task :default => [:clobber, :compile, :spec]
102
116
  rescue LoadError => e
103
117
  puts 'RSpec is not installed, skipping test task definitions: ' + e.message
@@ -135,7 +149,7 @@ begin
135
149
  task :update_readme do
136
150
  Dir.chdir __dir__ do
137
151
  content = File.read(File.join('README.md')).
138
- gsub(/\[([\w ]+)\]\(http:\/\/ruby-concurrency\.github\.io\/concurrent-ruby\/master\/.*\)/) do |_|
152
+ gsub(/\[([\w ]+)\]\(http:\/\/ruby-concurrency\.github\.io\/concurrent-ruby\/master\/.*\)/) do |_|
139
153
  case $1
140
154
  when 'LockFreeLinkedSet'
141
155
  "{Concurrent::Edge::#{$1} #{$1}}"
@@ -165,9 +179,9 @@ begin
165
179
  desc "* of #{name} into subdir #{name}"
166
180
  YARD::Rake::YardocTask.new(name) do |yard|
167
181
  yard.options.push(
168
- '--output-dir', output_dir,
169
- '--main', 'tmp/README.md',
170
- *common_yard_options)
182
+ '--output-dir', output_dir,
183
+ '--main', 'tmp/README.md',
184
+ *common_yard_options)
171
185
  yard.files = ['./lib/concurrent-ruby/**/*.rb',
172
186
  './lib/concurrent-ruby-edge/**/*.rb',
173
187
  './ext/concurrent_ruby_ext/**/*.c',
@@ -189,39 +203,11 @@ begin
189
203
  desc "* signpost for versions"
190
204
  YARD::Rake::YardocTask.new(:signpost) do |yard|
191
205
  yard.options.push(
192
- '--output-dir', 'docs',
193
- '--main', 'docs-source/signpost.md',
194
- *common_yard_options)
206
+ '--output-dir', 'docs',
207
+ '--main', 'docs-source/signpost.md',
208
+ *common_yard_options)
195
209
  yard.files = ['no-lib']
196
210
  end
197
-
198
- define_uptodate_task = -> name do
199
- namespace name do
200
- desc "** ensure that #{name} generated documentation is matching the source code"
201
- task :uptodate do
202
- Dir.chdir(__dir__) do
203
- begin
204
- FileUtils.cp_r 'docs', 'docs-copy', verbose: true
205
- Rake::Task["yard:#{name}"].invoke
206
- sh 'diff -r docs/ docs-copy/' do |ok, res|
207
- unless ok
208
- begin
209
- STDOUT.puts 'Command failed. Continue? (y/n)'
210
- input = STDIN.gets.strip.downcase
211
- end until %w(y n).include?(input)
212
- exit 1 if input == 'n'
213
- end
214
- end
215
- ensure
216
- FileUtils.rm_rf 'docs-copy', verbose: true
217
- end
218
- end
219
- end
220
- end
221
- end
222
-
223
- define_uptodate_task.call current_yard_version_name
224
- define_uptodate_task.call 'master'
225
211
  end
226
212
 
227
213
  rescue LoadError => e
@@ -234,15 +220,13 @@ task :release => ['release:checks', 'release:build', 'release:test', 'release:pu
234
220
  namespace :release do
235
221
  # Depends on environment of @pitr-ch
236
222
 
237
- mri_version = '2.6.5'
238
- jruby_version = 'jruby-9.2.9.0'
239
-
240
- task :checks => "yard:#{current_yard_version_name}:uptodate" do
223
+ task :checks do
241
224
  Dir.chdir(__dir__) do
242
225
  sh 'test -z "$(git status --porcelain)"' do |ok, res|
243
226
  unless ok
244
227
  begin
245
- STDOUT.puts 'Command failed. Continue? (y/n)'
228
+ status = `git status --porcelain`
229
+ STDOUT.puts 'There are local changes that you might want to commit.', status, 'Continue? (y/n)'
246
230
  input = STDIN.gets.strip.downcase
247
231
  end until %w(y n).include?(input)
248
232
  exit 1 if input == 'n'
@@ -250,10 +234,10 @@ namespace :release do
250
234
  end
251
235
  sh 'git fetch'
252
236
  sh 'test $(git show-ref --verify --hash refs/heads/master) = ' +
253
- '$(git show-ref --verify --hash refs/remotes/origin/master)' do |ok, res|
237
+ '$(git show-ref --verify --hash refs/remotes/origin/master)' do |ok, res|
254
238
  unless ok
255
239
  begin
256
- STDOUT.puts 'Command failed. Continue? (y/n)'
240
+ STDOUT.puts 'Local master branch is not pushed to origin.', 'Continue? (y/n)'
257
241
  input = STDIN.gets.strip.downcase
258
242
  end until %w(y n).include?(input)
259
243
  exit 1 if input == 'n'
@@ -268,19 +252,18 @@ namespace :release do
268
252
  desc '* test actual installed gems instead of cloned repository on MRI and JRuby'
269
253
  task :test do
270
254
  Dir.chdir(__dir__) do
271
- old = ENV['RBENV_VERSION']
255
+ puts "Testing with the installed gem"
272
256
 
273
- ENV['RBENV_VERSION'] = mri_version
274
- sh 'rbenv version'
275
- sh 'bundle exec rake spec:installed'
257
+ Bundler.with_original_env do
258
+ sh 'ruby -v'
259
+ sh 'bundle exec rake spec:installed'
276
260
 
277
- ENV['RBENV_VERSION'] = jruby_version
278
- sh 'rbenv version'
279
- sh 'bundle exec rake spec:installed'
261
+ env = { "PATH" => "#{ENV['CONCURRENT_JRUBY_HOME']}/bin:#{ENV['PATH']}" }
262
+ sh env, 'ruby -v'
263
+ sh env, 'bundle exec rake spec:installed'
264
+ end
280
265
 
281
266
  puts 'Windows build is untested'
282
-
283
- ENV['RBENV_VERSION'] = old
284
267
  end
285
268
  end
286
269
 
@@ -292,12 +275,12 @@ namespace :release do
292
275
 
293
276
  task :ask do
294
277
  begin
295
- STDOUT.puts 'Do you want to publish anything? (y/n)'
278
+ STDOUT.puts 'Do you want to publish anything now? (y/n)'
296
279
  input = STDIN.gets.strip.downcase
297
280
  end until %w(y n).include?(input)
298
281
  exit 1 if input == 'n'
299
282
  begin
300
- STDOUT.puts 'Do you want to publish edge? (y/n)'
283
+ STDOUT.puts 'It will publish `concurrent-ruby`. Do you want to publish `concurrent-ruby-edge`? (y/n)'
301
284
  input = STDIN.gets.strip.downcase
302
285
  end until %w(y n).include?(input)
303
286
  publish_edge = input == 'y'
@@ -326,6 +309,7 @@ namespace :release do
326
309
 
327
310
  desc '** print post release steps'
328
311
  task :post_steps do
312
+ # TODO: (petr 05-Jun-2021) automate and renew the process
329
313
  puts 'Manually: create a release on GitHub with relevant changelog part'
330
314
  puts 'Manually: send email same as release with relevant changelog part'
331
315
  puts 'Manually: tweet'
@@ -10,6 +10,7 @@ import org.jruby.RubyNumeric;
10
10
  import org.jruby.RubyObject;
11
11
  import org.jruby.anno.JRubyClass;
12
12
  import org.jruby.anno.JRubyMethod;
13
+ import org.jruby.runtime.Block;
13
14
  import org.jruby.runtime.ObjectAllocator;
14
15
  import org.jruby.runtime.ThreadContext;
15
16
  import org.jruby.runtime.builtin.IRubyObject;
@@ -45,9 +46,13 @@ public class JavaSemaphoreLibrary {
45
46
  }
46
47
 
47
48
  @JRubyMethod
48
- public IRubyObject acquire(ThreadContext context, IRubyObject value) throws InterruptedException {
49
- this.semaphore.acquire(rubyFixnumToPositiveInt(value, "permits"));
50
- return context.nil;
49
+ public IRubyObject acquire(ThreadContext context, final Block block) throws InterruptedException {
50
+ return this.acquire(context, 1, block);
51
+ }
52
+
53
+ @JRubyMethod
54
+ public IRubyObject acquire(ThreadContext context, IRubyObject permits, final Block block) throws InterruptedException {
55
+ return this.acquire(context, rubyFixnumToPositiveInt(permits, "permits"), block);
51
56
  }
52
57
 
53
58
  @JRubyMethod(name = "available_permits")
@@ -60,30 +65,32 @@ public class JavaSemaphoreLibrary {
60
65
  return getRuntime().newFixnum(this.semaphore.drainPermits());
61
66
  }
62
67
 
63
- @JRubyMethod
64
- public IRubyObject acquire(ThreadContext context) throws InterruptedException {
65
- this.semaphore.acquire(1);
66
- return context.nil;
67
- }
68
-
69
68
  @JRubyMethod(name = "try_acquire")
70
- public IRubyObject tryAcquire(ThreadContext context) throws InterruptedException {
71
- return getRuntime().newBoolean(semaphore.tryAcquire(1));
69
+ public IRubyObject tryAcquire(ThreadContext context, final Block block) throws InterruptedException {
70
+ int permitsInt = 1;
71
+ boolean acquired = semaphore.tryAcquire(permitsInt);
72
+
73
+ return triedAcquire(context, permitsInt, acquired, block);
72
74
  }
73
75
 
74
76
  @JRubyMethod(name = "try_acquire")
75
- public IRubyObject tryAcquire(ThreadContext context, IRubyObject permits) throws InterruptedException {
76
- return getRuntime().newBoolean(semaphore.tryAcquire(rubyFixnumToPositiveInt(permits, "permits")));
77
+ public IRubyObject tryAcquire(ThreadContext context, IRubyObject permits, final Block block) throws InterruptedException {
78
+ int permitsInt = rubyFixnumToPositiveInt(permits, "permits");
79
+ boolean acquired = semaphore.tryAcquire(permitsInt);
80
+
81
+ return triedAcquire(context, permitsInt, acquired, block);
77
82
  }
78
83
 
79
84
  @JRubyMethod(name = "try_acquire")
80
- public IRubyObject tryAcquire(ThreadContext context, IRubyObject permits, IRubyObject timeout) throws InterruptedException {
81
- return getRuntime().newBoolean(
82
- semaphore.tryAcquire(
83
- rubyFixnumToPositiveInt(permits, "permits"),
84
- rubyNumericToLong(timeout, "timeout"),
85
- java.util.concurrent.TimeUnit.SECONDS)
86
- );
85
+ public IRubyObject tryAcquire(ThreadContext context, IRubyObject permits, IRubyObject timeout, final Block block) throws InterruptedException {
86
+ int permitsInt = rubyFixnumToPositiveInt(permits, "permits");
87
+ boolean acquired = semaphore.tryAcquire(
88
+ permitsInt,
89
+ rubyNumericToLong(timeout, "timeout"),
90
+ java.util.concurrent.TimeUnit.SECONDS
91
+ );
92
+
93
+ return triedAcquire(context, permitsInt, acquired, block);
87
94
  }
88
95
 
89
96
  @JRubyMethod
@@ -93,8 +100,8 @@ public class JavaSemaphoreLibrary {
93
100
  }
94
101
 
95
102
  @JRubyMethod
96
- public IRubyObject release(ThreadContext context, IRubyObject value) {
97
- this.semaphore.release(rubyFixnumToPositiveInt(value, "permits"));
103
+ public IRubyObject release(ThreadContext context, IRubyObject permits) {
104
+ this.semaphore.release(rubyFixnumToPositiveInt(permits, "permits"));
98
105
  return getRuntime().newBoolean(true);
99
106
  }
100
107
 
@@ -104,6 +111,29 @@ public class JavaSemaphoreLibrary {
104
111
  return context.nil;
105
112
  }
106
113
 
114
+ private IRubyObject acquire(ThreadContext context, int permits, final Block block) throws InterruptedException {
115
+ this.semaphore.acquire(permits);
116
+
117
+ if (!block.isGiven()) return context.nil;
118
+
119
+ try {
120
+ return block.yieldSpecific(context);
121
+ } finally {
122
+ this.semaphore.release(permits);
123
+ }
124
+ }
125
+
126
+ private IRubyObject triedAcquire(ThreadContext context, int permits, boolean acquired, final Block block) {
127
+ if (!block.isGiven()) return getRuntime().newBoolean(acquired);
128
+ if (!acquired) return context.nil;
129
+
130
+ try {
131
+ return block.yieldSpecific(context);
132
+ } finally {
133
+ this.semaphore.release(permits);
134
+ }
135
+ }
136
+
107
137
  private int rubyFixnumInt(IRubyObject value, String paramName) {
108
138
  if (value instanceof RubyFixnum) {
109
139
  RubyFixnum fixNum = (RubyFixnum) value;