concurrent-ruby 1.1.8 → 1.1.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/Gemfile +2 -7
- data/README.md +40 -20
- data/Rakefile +26 -31
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +0 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +52 -22
- data/lib/concurrent-ruby/concurrent/async.rb +1 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +1 -0
- data/lib/concurrent-ruby/concurrent/atomic/event.rb +2 -2
- data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +18 -2
- data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +4 -6
- data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +26 -5
- data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
- data/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +11 -1
- data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +16 -13
- data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +13 -3
- data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +1 -1
- data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +4 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +10 -4
- data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +26 -37
- data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +5 -5
- data/lib/concurrent-ruby/concurrent/map.rb +13 -4
- data/lib/concurrent-ruby/concurrent/promise.rb +1 -0
- data/lib/concurrent-ruby/concurrent/scheduled_task.rb +29 -16
- data/lib/concurrent-ruby/concurrent/set.rb +14 -6
- data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +1 -3
- data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +12 -0
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +6 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +26 -1
- data/lib/concurrent-ruby/concurrent/timer_task.rb +11 -33
- data/lib/concurrent-ruby/concurrent/tvar.rb +20 -60
- data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +67 -35
- data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +2 -35
- data/lib/concurrent-ruby/concurrent/version.rb +1 -1
- data/lib/concurrent-ruby/concurrent-ruby.rb +5 -1
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e2508d8671dc3f93a6d41204a69a2444669688ac1e9e7790104162ac5180579e
|
4
|
+
data.tar.gz: 5eba3636194c783d376ed010bd3d6ec8796fe409870e07a84c6b0b0ea2704b41
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c1cbc5311e939aecda5e291bb579a690807de5240bb2fb30600a9d1d9de8c353558de7d6e3e0dff871fcca364bd7caa76b304428e0fdaba323cbe04be300056
|
7
|
+
data.tar.gz: 863635cad877062864813b9ba72685b3afdadabf258a62b36f8d7093a5be9c7115d64aade01c9a98b9e68ef86dff2698e5e0cef7766b9c4dfc740e0e76eccf0c
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,33 @@
|
|
1
1
|
## Current
|
2
2
|
|
3
|
+
## Release v1.1.10
|
4
|
+
|
5
|
+
concurrent-ruby:
|
6
|
+
|
7
|
+
* (#951) Set the Ruby compatibility version at 2.2
|
8
|
+
* (#939, #933) The `caller_runs` fallback policy no longer blocks reads from the job queue by worker threads
|
9
|
+
* (#938, #761, #652) You can now explicitly `prune_pool` a thread pool (Sylvain Joyeux)
|
10
|
+
* (#937, #757, #670) We switched the Yahoo stock API for demos to Alpha Vantage (Gustavo Caso)
|
11
|
+
* (#932, #931) We changed how `SafeTaskExecutor` handles local jump errors (Aaron Jensen)
|
12
|
+
* (#927) You can use keyword arguments in your initialize when using `Async` (Matt Larraz)
|
13
|
+
* (#926, #639) We removed timeout from `TimerTask` because it wasn't sound, and now it's a no-op with a warning (Jacob Atzen)
|
14
|
+
* (#919) If you double-lock a re-entrant read-write lock, we promote to locked for writing (zp yuan)
|
15
|
+
* (#915) `monotonic_time` now accepts an optional unit parameter, as Ruby's `clock_gettime` (Jean Boussier)
|
16
|
+
|
17
|
+
## Release v1.1.9 (5 Jun 2021)
|
18
|
+
|
19
|
+
concurrent-ruby:
|
20
|
+
|
21
|
+
* (#866) Child promise state not set to :pending immediately after #execute when parent has completed
|
22
|
+
* (#905, #872) Fix RubyNonConcurrentPriorityQueue#delete method
|
23
|
+
* (2df0337d) Make sure locks are not shared on shared when objects are dup/cloned
|
24
|
+
* (#900, #906, #796, #847, #911) Fix Concurrent::Set tread-safety issues on CRuby
|
25
|
+
* (#907) Add new ConcurrentMap backend for TruffleRuby
|
26
|
+
|
3
27
|
## Release v1.1.8 (20 January 2021)
|
4
28
|
|
29
|
+
concurrent-ruby:
|
30
|
+
|
5
31
|
* (#885) Fix race condition in TVar for stale reads
|
6
32
|
* (#884) RubyThreadLocalVar: Do not iterate over hash which might conflict with new pair addition
|
7
33
|
|
data/Gemfile
CHANGED
@@ -12,7 +12,7 @@ gem 'concurrent-ruby-edge', Concurrent::EDGE_VERSION, options
|
|
12
12
|
gem 'concurrent-ruby-ext', Concurrent::VERSION, options.merge(platform: :mri)
|
13
13
|
|
14
14
|
group :development do
|
15
|
-
gem 'rake',
|
15
|
+
gem 'rake', '~> 13.0'
|
16
16
|
gem 'rake-compiler', '~> 1.0', '>= 1.0.7'
|
17
17
|
gem 'rake-compiler-dock', '~> 1.0'
|
18
18
|
gem 'pry', '~> 0.11', platforms: :mri
|
@@ -26,7 +26,7 @@ end
|
|
26
26
|
|
27
27
|
group :testing do
|
28
28
|
gem 'rspec', '~> 3.7'
|
29
|
-
gem 'timecop', '~> 0.
|
29
|
+
gem 'timecop', '~> 0.9'
|
30
30
|
gem 'sigdump', require: false
|
31
31
|
end
|
32
32
|
|
@@ -35,8 +35,3 @@ group :coverage, optional: !ENV['COVERAGE'] do
|
|
35
35
|
gem 'simplecov', '~> 0.16.0', require: false
|
36
36
|
gem 'coveralls', '~> 0.8.2', require: false
|
37
37
|
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,6 +37,8 @@ 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
|
@@ -259,15 +259,11 @@ 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.
|
263
|
-
* JRuby 9000
|
264
|
-
* TruffleRuby
|
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.
|
262
|
+
* MRI 2.2 and above
|
263
|
+
* Latest JRuby 9000
|
264
|
+
* Latest TruffleRuby
|
269
265
|
|
270
|
-
The legacy support for Rubinius is kept but it is no longer maintained
|
266
|
+
The legacy support for Rubinius is kept for the moment but it is no longer maintained and is liable to be removed. If you would like to help
|
271
267
|
please respond to [#739](https://github.com/ruby-concurrency/concurrent-ruby/issues/739).
|
272
268
|
|
273
269
|
## Usage
|
@@ -353,23 +349,47 @@ and load the appropriate C extensions.
|
|
353
349
|
No gems should depend on `concurrent-ruby-ext`. Doing so will force C extensions on your users. The
|
354
350
|
best practice is to depend on `concurrent-ruby` and let users to decide if they want C extensions.
|
355
351
|
|
352
|
+
## Building the gem
|
353
|
+
|
354
|
+
### Requirements
|
355
|
+
|
356
|
+
* Recent CRuby
|
357
|
+
* JRuby, `rbenv install jruby-9.2.17.0`
|
358
|
+
* Set env variable `CONCURRENT_JRUBY_HOME` to point to it, e.g. `/usr/local/opt/rbenv/versions/jruby-9.2.17.0`
|
359
|
+
* Install Docker, required for Windows builds
|
360
|
+
|
361
|
+
### Publishing the Gem
|
362
|
+
|
363
|
+
* Update `version.rb`
|
364
|
+
* Update the CHANGELOG
|
365
|
+
* Update the Yard documentation
|
366
|
+
- Add the new version to `docs-source/signpost.md`. Needs to be done only if there are visible changes in the
|
367
|
+
documentation.
|
368
|
+
- Run `bundle exec rake yard` to update the master documentation and signpost.
|
369
|
+
- Run `bundle exec rake yard:<new-version>` to add or update the documentation of the new version.
|
370
|
+
* Commit (and push) the changes.
|
371
|
+
* Use `be rake release` to release the gem. It consists
|
372
|
+
of `['release:checks', 'release:build', 'release:test', 'release:publish']` steps. It will ask at the end before
|
373
|
+
publishing anything. Steps can also be executed individually.
|
374
|
+
|
356
375
|
## Maintainers
|
357
376
|
|
358
|
-
*
|
359
|
-
*
|
360
|
-
* [Chris Seaton](https://github.com/chrisseaton)
|
377
|
+
* [Chris Seaton](https://github.com/chrisseaton) — Lead maintainer, point-of-contact.
|
378
|
+
* [Benoit Daloze](https://github.com/eregon) — If Chris is not available Benoit can help.
|
361
379
|
|
362
380
|
### Special Thanks to
|
363
381
|
|
364
|
-
*
|
365
|
-
*
|
366
|
-
*
|
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
|
-
|
387
|
+
to the past maintainers
|
369
388
|
|
370
|
-
*
|
371
|
-
*
|
372
|
-
*
|
389
|
+
* [Petr Chalupa](https://github.com/pitr-ch)
|
390
|
+
* [Michele Della Torre](https://github.com/mighe)
|
391
|
+
* [Paweł Obrok](https://github.com/obrok)
|
392
|
+
* [Lucas Allan](https://github.com/lucasallan)
|
373
393
|
|
374
394
|
and to [Ruby Association](https://www.ruby.or.jp/en/) for sponsoring a project
|
375
395
|
["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|
|
@@ -77,8 +68,7 @@ begin
|
|
77
68
|
options = %w[ --color
|
78
69
|
--backtrace
|
79
70
|
--order defined
|
80
|
-
--format documentation
|
81
|
-
--tag ~notravis ]
|
71
|
+
--format documentation ]
|
82
72
|
t.rspec_opts = [*options].join(' ')
|
83
73
|
end
|
84
74
|
|
@@ -135,7 +125,7 @@ begin
|
|
135
125
|
task :update_readme do
|
136
126
|
Dir.chdir __dir__ do
|
137
127
|
content = File.read(File.join('README.md')).
|
138
|
-
|
128
|
+
gsub(/\[([\w ]+)\]\(http:\/\/ruby-concurrency\.github\.io\/concurrent-ruby\/master\/.*\)/) do |_|
|
139
129
|
case $1
|
140
130
|
when 'LockFreeLinkedSet'
|
141
131
|
"{Concurrent::Edge::#{$1} #{$1}}"
|
@@ -165,9 +155,9 @@ begin
|
|
165
155
|
desc "* of #{name} into subdir #{name}"
|
166
156
|
YARD::Rake::YardocTask.new(name) do |yard|
|
167
157
|
yard.options.push(
|
168
|
-
|
169
|
-
|
170
|
-
|
158
|
+
'--output-dir', output_dir,
|
159
|
+
'--main', 'tmp/README.md',
|
160
|
+
*common_yard_options)
|
171
161
|
yard.files = ['./lib/concurrent-ruby/**/*.rb',
|
172
162
|
'./lib/concurrent-ruby-edge/**/*.rb',
|
173
163
|
'./ext/concurrent_ruby_ext/**/*.c',
|
@@ -189,9 +179,9 @@ begin
|
|
189
179
|
desc "* signpost for versions"
|
190
180
|
YARD::Rake::YardocTask.new(:signpost) do |yard|
|
191
181
|
yard.options.push(
|
192
|
-
|
193
|
-
|
194
|
-
|
182
|
+
'--output-dir', 'docs',
|
183
|
+
'--main', 'docs-source/signpost.md',
|
184
|
+
*common_yard_options)
|
195
185
|
yard.files = ['no-lib']
|
196
186
|
end
|
197
187
|
|
@@ -206,7 +196,7 @@ begin
|
|
206
196
|
sh 'diff -r docs/ docs-copy/' do |ok, res|
|
207
197
|
unless ok
|
208
198
|
begin
|
209
|
-
STDOUT.puts
|
199
|
+
STDOUT.puts "yard:#{name} is not properly generated and committed.", "Continue? (y/n)"
|
210
200
|
input = STDIN.gets.strip.downcase
|
211
201
|
end until %w(y n).include?(input)
|
212
202
|
exit 1 if input == 'n'
|
@@ -234,15 +224,13 @@ task :release => ['release:checks', 'release:build', 'release:test', 'release:pu
|
|
234
224
|
namespace :release do
|
235
225
|
# Depends on environment of @pitr-ch
|
236
226
|
|
237
|
-
mri_version = '2.6.5'
|
238
|
-
jruby_version = 'jruby-9.2.9.0'
|
239
|
-
|
240
227
|
task :checks => "yard:#{current_yard_version_name}:uptodate" do
|
241
228
|
Dir.chdir(__dir__) do
|
242
229
|
sh 'test -z "$(git status --porcelain)"' do |ok, res|
|
243
230
|
unless ok
|
244
231
|
begin
|
245
|
-
|
232
|
+
status = `git status --porcelain`
|
233
|
+
STDOUT.puts 'There are local changes that you might want to commit.', status, 'Continue? (y/n)'
|
246
234
|
input = STDIN.gets.strip.downcase
|
247
235
|
end until %w(y n).include?(input)
|
248
236
|
exit 1 if input == 'n'
|
@@ -250,10 +238,10 @@ namespace :release do
|
|
250
238
|
end
|
251
239
|
sh 'git fetch'
|
252
240
|
sh 'test $(git show-ref --verify --hash refs/heads/master) = ' +
|
253
|
-
|
241
|
+
'$(git show-ref --verify --hash refs/remotes/origin/master)' do |ok, res|
|
254
242
|
unless ok
|
255
243
|
begin
|
256
|
-
STDOUT.puts '
|
244
|
+
STDOUT.puts 'Local master branch is not pushed to origin.', 'Continue? (y/n)'
|
257
245
|
input = STDIN.gets.strip.downcase
|
258
246
|
end until %w(y n).include?(input)
|
259
247
|
exit 1 if input == 'n'
|
@@ -270,6 +258,12 @@ namespace :release do
|
|
270
258
|
Dir.chdir(__dir__) do
|
271
259
|
old = ENV['RBENV_VERSION']
|
272
260
|
|
261
|
+
mri_version = `ruby -e 'puts RUBY_VERSION'`.chomp
|
262
|
+
jruby_version = File.basename(ENV['CONCURRENT_JRUBY_HOME'])
|
263
|
+
|
264
|
+
puts "Using following version:"
|
265
|
+
pp mri_version: mri_version, jruby_version: jruby_version
|
266
|
+
|
273
267
|
ENV['RBENV_VERSION'] = mri_version
|
274
268
|
sh 'rbenv version'
|
275
269
|
sh 'bundle exec rake spec:installed'
|
@@ -292,12 +286,12 @@ namespace :release do
|
|
292
286
|
|
293
287
|
task :ask do
|
294
288
|
begin
|
295
|
-
STDOUT.puts 'Do you want to publish anything? (y/n)'
|
289
|
+
STDOUT.puts 'Do you want to publish anything now? (y/n)'
|
296
290
|
input = STDIN.gets.strip.downcase
|
297
291
|
end until %w(y n).include?(input)
|
298
292
|
exit 1 if input == 'n'
|
299
293
|
begin
|
300
|
-
STDOUT.puts 'Do you want to publish edge
|
294
|
+
STDOUT.puts 'It will publish `concurrent-ruby`. Do you want to publish `concurrent-ruby-edge`? (y/n)'
|
301
295
|
input = STDIN.gets.strip.downcase
|
302
296
|
end until %w(y n).include?(input)
|
303
297
|
publish_edge = input == 'y'
|
@@ -326,9 +320,10 @@ namespace :release do
|
|
326
320
|
|
327
321
|
desc '** print post release steps'
|
328
322
|
task :post_steps do
|
329
|
-
|
330
|
-
puts 'Manually:
|
331
|
-
puts 'Manually:
|
323
|
+
# TODO: (petr 05-Jun-2021) automate and renew the process
|
324
|
+
# puts 'Manually: create a release on GitHub with relevant changelog part'
|
325
|
+
# puts 'Manually: send email same as release with relevant changelog part'
|
326
|
+
# puts 'Manually: tweet'
|
332
327
|
end
|
333
328
|
end
|
334
329
|
end
|
File without changes
|
@@ -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,
|
49
|
-
this.
|
50
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
97
|
-
this.semaphore.release(rubyFixnumToPositiveInt(
|
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;
|
@@ -170,6 +170,7 @@ module Concurrent
|
|
170
170
|
alias_method :compare_and_swap, :compare_and_set
|
171
171
|
alias_method :swap, :get_and_set
|
172
172
|
end
|
173
|
+
TruffleRubyAtomicReference
|
173
174
|
when Concurrent.on_rbx?
|
174
175
|
# @note Extends `Rubinius::AtomicReference` version adding aliases
|
175
176
|
# and numeric logic.
|
@@ -19,7 +19,7 @@ module Concurrent
|
|
19
19
|
# t1 = Thread.new do
|
20
20
|
# puts "t1 is waiting"
|
21
21
|
# event.wait(1)
|
22
|
-
# puts "event
|
22
|
+
# puts "event occurred"
|
23
23
|
# end
|
24
24
|
#
|
25
25
|
# t2 = Thread.new do
|
@@ -30,8 +30,8 @@ module Concurrent
|
|
30
30
|
# [t1, t2].each(&:join)
|
31
31
|
#
|
32
32
|
# # prints:
|
33
|
-
# # t2 calling set
|
34
33
|
# # t1 is waiting
|
34
|
+
# # t2 calling set
|
35
35
|
# # event occurred
|
36
36
|
class Event < Synchronization::LockableObject
|
37
37
|
|
@@ -23,7 +23,14 @@ module Concurrent
|
|
23
23
|
|
24
24
|
synchronize do
|
25
25
|
try_acquire_timed(permits, nil)
|
26
|
-
|
26
|
+
end
|
27
|
+
|
28
|
+
return unless block_given?
|
29
|
+
|
30
|
+
begin
|
31
|
+
yield
|
32
|
+
ensure
|
33
|
+
release(permits)
|
27
34
|
end
|
28
35
|
end
|
29
36
|
|
@@ -48,13 +55,22 @@ module Concurrent
|
|
48
55
|
Utility::NativeInteger.ensure_integer_and_bounds permits
|
49
56
|
Utility::NativeInteger.ensure_positive permits
|
50
57
|
|
51
|
-
synchronize do
|
58
|
+
acquired = synchronize do
|
52
59
|
if timeout.nil?
|
53
60
|
try_acquire_now(permits)
|
54
61
|
else
|
55
62
|
try_acquire_timed(permits, timeout)
|
56
63
|
end
|
57
64
|
end
|
65
|
+
|
66
|
+
return acquired unless block_given?
|
67
|
+
return unless acquired
|
68
|
+
|
69
|
+
begin
|
70
|
+
yield
|
71
|
+
ensure
|
72
|
+
release(permits)
|
73
|
+
end
|
58
74
|
end
|
59
75
|
|
60
76
|
# @!macro semaphore_method_release
|
@@ -267,12 +267,10 @@ module Concurrent
|
|
267
267
|
# running right now, AND no writers who came before us still waiting to
|
268
268
|
# acquire the lock
|
269
269
|
# Additionally, if any read locks have been taken, we must hold all of them
|
270
|
-
if
|
271
|
-
# If we successfully swap the RUNNING_WRITER bit on, then we can go ahead
|
272
|
-
|
273
|
-
|
274
|
-
return true
|
275
|
-
end
|
270
|
+
if held > 0 && @Counter.compare_and_set(1, c+RUNNING_WRITER)
|
271
|
+
# If we are the only one reader and successfully swap the RUNNING_WRITER bit on, then we can go ahead
|
272
|
+
@HeldCount.value = held + WRITE_LOCK_HELD
|
273
|
+
return true
|
276
274
|
elsif @Counter.compare_and_set(c, c+WAITING_WRITER)
|
277
275
|
while true
|
278
276
|
# Now we have successfully incremented, so no more readers will be able to increment
|
@@ -16,14 +16,16 @@ module Concurrent
|
|
16
16
|
# @!macro semaphore_method_acquire
|
17
17
|
#
|
18
18
|
# Acquires the given number of permits from this semaphore,
|
19
|
-
# blocking until all are available.
|
19
|
+
# blocking until all are available. If a block is given,
|
20
|
+
# yields to it and releases the permits afterwards.
|
20
21
|
#
|
21
22
|
# @param [Fixnum] permits Number of permits to acquire
|
22
23
|
#
|
23
24
|
# @raise [ArgumentError] if `permits` is not an integer or is less than
|
24
25
|
# one
|
25
26
|
#
|
26
|
-
# @return [nil]
|
27
|
+
# @return [nil, BasicObject] Without a block, `nil` is returned. If a block
|
28
|
+
# is given, its return value is returned.
|
27
29
|
|
28
30
|
# @!macro semaphore_method_available_permits
|
29
31
|
#
|
@@ -41,7 +43,9 @@ module Concurrent
|
|
41
43
|
#
|
42
44
|
# Acquires the given number of permits from this semaphore,
|
43
45
|
# only if all are available at the time of invocation or within
|
44
|
-
# `timeout` interval
|
46
|
+
# `timeout` interval. If a block is given, yields to it if the permits
|
47
|
+
# were successfully acquired, and releases them afterward, returning the
|
48
|
+
# block's return value.
|
45
49
|
#
|
46
50
|
# @param [Fixnum] permits the number of permits to acquire
|
47
51
|
#
|
@@ -51,8 +55,10 @@ module Concurrent
|
|
51
55
|
# @raise [ArgumentError] if `permits` is not an integer or is less than
|
52
56
|
# one
|
53
57
|
#
|
54
|
-
# @return [
|
55
|
-
# acquired a permit
|
58
|
+
# @return [true, false, nil, BasicObject] `false` if no permits are
|
59
|
+
# available, `true` when acquired a permit. If a block is given, the
|
60
|
+
# block's return value is returned if the permits were acquired; if not,
|
61
|
+
# `nil` is returned.
|
56
62
|
|
57
63
|
# @!macro semaphore_method_release
|
58
64
|
#
|
@@ -106,6 +112,8 @@ module Concurrent
|
|
106
112
|
# releasing a blocking acquirer.
|
107
113
|
# However, no actual permit objects are used; the Semaphore just keeps a
|
108
114
|
# count of the number available and acts accordingly.
|
115
|
+
# Alternatively, permits may be acquired within a block, and automatically
|
116
|
+
# released after the block finishes executing.
|
109
117
|
#
|
110
118
|
# @!macro semaphore_public_api
|
111
119
|
# @example
|
@@ -140,6 +148,19 @@ module Concurrent
|
|
140
148
|
# # Thread 4 releasing semaphore
|
141
149
|
# # Thread 1 acquired semaphore
|
142
150
|
#
|
151
|
+
# @example
|
152
|
+
# semaphore = Concurrent::Semaphore.new(1)
|
153
|
+
#
|
154
|
+
# puts semaphore.available_permits
|
155
|
+
# semaphore.acquire do
|
156
|
+
# puts semaphore.available_permits
|
157
|
+
# end
|
158
|
+
# puts semaphore.available_permits
|
159
|
+
#
|
160
|
+
# # prints:
|
161
|
+
# # 1
|
162
|
+
# # 0
|
163
|
+
# # 1
|
143
164
|
class Semaphore < SemaphoreImplementation
|
144
165
|
end
|
145
166
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Concurrent
|
2
|
+
|
3
|
+
# @!visibility private
|
4
|
+
module Collection
|
5
|
+
|
6
|
+
# @!visibility private
|
7
|
+
class TruffleRubyMapBackend < TruffleRuby::ConcurrentMap
|
8
|
+
def initialize(options = nil)
|
9
|
+
options ||= {}
|
10
|
+
super(initial_capacity: options[:initial_capacity], load_factor: options[:load_factor])
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -30,7 +30,7 @@ module Concurrent
|
|
30
30
|
if @queue[k] == item
|
31
31
|
swap(k, @length)
|
32
32
|
@length -= 1
|
33
|
-
sink(k)
|
33
|
+
sink(k) || swim(k)
|
34
34
|
@queue.pop
|
35
35
|
else
|
36
36
|
k += 1
|
@@ -126,12 +126,17 @@ module Concurrent
|
|
126
126
|
#
|
127
127
|
# @!visibility private
|
128
128
|
def sink(k)
|
129
|
+
success = false
|
130
|
+
|
129
131
|
while (j = (2 * k)) <= @length do
|
130
132
|
j += 1 if j < @length && ! ordered?(j, j+1)
|
131
133
|
break if ordered?(k, j)
|
132
134
|
swap(k, j)
|
135
|
+
success = true
|
133
136
|
k = j
|
134
137
|
end
|
138
|
+
|
139
|
+
success
|
135
140
|
end
|
136
141
|
|
137
142
|
# Percolate up to maintain heap invariant.
|
@@ -140,10 +145,15 @@ module Concurrent
|
|
140
145
|
#
|
141
146
|
# @!visibility private
|
142
147
|
def swim(k)
|
148
|
+
success = false
|
149
|
+
|
143
150
|
while k > 1 && ! ordered?(k/2, k) do
|
144
151
|
swap(k, k/2)
|
145
152
|
k = k/2
|
153
|
+
success = true
|
146
154
|
end
|
155
|
+
|
156
|
+
success
|
147
157
|
end
|
148
158
|
end
|
149
159
|
end
|
Binary file
|