concurrent-ruby 1.1.4 → 1.1.5
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/Gemfile +9 -7
- data/README.md +34 -2
- data/Rakefile +33 -52
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +9 -8
- data/lib/concurrent/array.rb +3 -3
- data/lib/concurrent/async.rb +14 -0
- data/lib/concurrent/atomic/atomic_fixnum.rb +2 -2
- data/lib/concurrent/collection/lock_free_stack.rb +1 -1
- data/lib/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent/executor/timer_set.rb +13 -15
- data/lib/concurrent/hash.rb +3 -3
- data/lib/concurrent/promises.rb +348 -117
- data/lib/concurrent/synchronization/abstract_struct.rb +1 -0
- data/lib/concurrent/synchronization/condition.rb +2 -0
- data/lib/concurrent/synchronization/jruby_object.rb +1 -0
- data/lib/concurrent/synchronization/lock.rb +2 -0
- data/lib/concurrent/synchronization/mri_object.rb +1 -0
- data/lib/concurrent/synchronization/object.rb +46 -20
- data/lib/concurrent/synchronization/rbx_object.rb +1 -0
- data/lib/concurrent/synchronization/truffleruby_object.rb +1 -0
- data/lib/concurrent/version.rb +1 -2
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96f32c31090c8a0547e4ee452739bdc993aad1256e2c89cb9a46d7f7e7b5762a
|
4
|
+
data.tar.gz: 307d26bde3add56b7e2b37fb0b016c7726a3ba0755dcfec8202fb0760e4ac485
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8cff93c6ef396aebbe5cf69734d9a91f0351e24b5c1846ae105b055254f972cd9d6bb99b90ce10d387627ed43c4e21db9ce47d1587e10278e80e33a53f8d4c4
|
7
|
+
data.tar.gz: f367f097759eedb8e18b0117543176c9f30ab29552888fcedab0baaea355cee3d100d2559dd16cf54483778545097f8b3340bebe44b0e3ab2a51c1af3830f5e1
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
## Current
|
2
2
|
|
3
|
+
## Release v1.1.5, edge v0.5.0 (10 mar 2019)
|
4
|
+
|
5
|
+
concurrent-ruby:
|
6
|
+
|
7
|
+
* fix potential leak of context on JRuby and Java 7
|
8
|
+
|
9
|
+
concurrent-ruby-edge:
|
10
|
+
|
11
|
+
* Add finalized Concurrent::Cancellation
|
12
|
+
* Add finalized Concurrent::Throttle
|
13
|
+
* Add finalized Concurrent::Promises::Channel
|
14
|
+
* Add new Concurrent::ErlangActor
|
15
|
+
|
3
16
|
## Release v1.1.4 (14 Dec 2018)
|
4
17
|
|
5
18
|
* (#780) Remove java_alias of 'submit' method of Runnable to let executor service work on java 11
|
data/Gemfile
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
require File.join(File.dirname(__FILE__
|
3
|
+
require File.join(File.dirname(__FILE__), 'lib/concurrent/version')
|
4
|
+
require File.join(File.dirname(__FILE__ ), 'lib-edge/concurrent/edge/version')
|
4
5
|
|
5
6
|
no_path = ENV['NO_PATH']
|
6
7
|
options = no_path ? {} : { path: '.' }
|
@@ -11,26 +12,27 @@ gem 'concurrent-ruby-ext', Concurrent::VERSION, options.merge(platform: :mri)
|
|
11
12
|
|
12
13
|
group :development do
|
13
14
|
gem 'rake', '~> 12.0'
|
14
|
-
gem 'rake-compiler', '~> 1.0'
|
15
|
-
gem 'rake-compiler-dock', '~> 0.
|
15
|
+
gem 'rake-compiler', '~> 1.0', '>= 1.0.7'
|
16
|
+
gem 'rake-compiler-dock', '~> 0.7.0'
|
16
17
|
gem 'pry', '~> 0.11', platforms: :mri
|
17
18
|
end
|
18
19
|
|
19
20
|
group :documentation, optional: true do
|
20
|
-
gem 'yard', '~> 0.9.0', :
|
21
|
+
gem 'yard', '~> 0.9.0', require: false
|
21
22
|
gem 'redcarpet', '~> 3.0', platforms: :mri # understands github markdown
|
22
|
-
gem 'md-ruby-eval', '~> 0.
|
23
|
+
gem 'md-ruby-eval', '~> 0.6'
|
23
24
|
end
|
24
25
|
|
25
26
|
group :testing do
|
26
27
|
gem 'rspec', '~> 3.7'
|
27
28
|
gem 'timecop', '~> 0.7.4'
|
29
|
+
gem 'sigdump', require: false
|
28
30
|
end
|
29
31
|
|
30
32
|
# made opt-in since it will not install on jruby 1.7
|
31
33
|
group :coverage, optional: !ENV['COVERAGE'] do
|
32
|
-
gem 'simplecov', '~> 0.
|
33
|
-
gem 'coveralls', '~> 0.8.2', :
|
34
|
+
gem 'simplecov', '~> 0.16.0', require: false
|
35
|
+
gem 'coveralls', '~> 0.8.2', require: false
|
34
36
|
end
|
35
37
|
|
36
38
|
group :benchmarks, optional: true do
|
data/README.md
CHANGED
@@ -42,7 +42,7 @@ appreciate your help. Would you like to contribute? Great! Have a look at
|
|
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
|
45
|
+
library, providing consistent behavior and guarantees on all four of the main Ruby interpreters
|
46
46
|
(MRI/CRuby, JRuby, Rubinius, TruffleRuby).*
|
47
47
|
|
48
48
|
Every abstraction in this library is thread safe. Specific thread safety guarantees are documented
|
@@ -224,6 +224,35 @@ be obeyed though. Features developed in `concurrent-ruby-edge` are expected to m
|
|
224
224
|
*Status: will be moved to core soon.*
|
225
225
|
* [LockFreeStack](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/LockFreeStack.html)
|
226
226
|
*Status: missing documentation and tests.*
|
227
|
+
* [Promises::Channel](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Promises/Channel.html)
|
228
|
+
A first in first out channel that accepts messages with push family of methods and returns
|
229
|
+
messages with pop family of methods.
|
230
|
+
Pop and push operations can be represented as futures, see `#pop_op` and `#push_op`.
|
231
|
+
The capacity of the channel can be limited to support back pressure, use capacity option in `#initialize`.
|
232
|
+
`#pop` method blocks ans `#pop_op` returns pending future if there is no message in the channel.
|
233
|
+
If the capacity is limited the `#push` method blocks and `#push_op` returns pending future.
|
234
|
+
* [Cancellation](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Cancellation.html)
|
235
|
+
The Cancellation abstraction provides cooperative cancellation.
|
236
|
+
|
237
|
+
The standard methods `Thread#raise` of `Thread#kill` available in Ruby
|
238
|
+
are very dangerous (see linked the blog posts bellow).
|
239
|
+
Therefore concurrent-ruby provides an alternative.
|
240
|
+
|
241
|
+
* <https://jvns.ca/blog/2015/11/27/why-rubys-timeout-is-dangerous-and-thread-dot-raise-is-terrifying/>
|
242
|
+
* <http://www.mikeperham.com/2015/05/08/timeout-rubys-most-dangerous-api/>
|
243
|
+
* <http://blog.headius.com/2008/02/rubys-threadraise-threadkill-timeoutrb.html>
|
244
|
+
|
245
|
+
It provides an object which represents a task which can be executed,
|
246
|
+
the task has to get the reference to the object and periodically cooperatively check that it is not cancelled.
|
247
|
+
Good practices to make tasks cancellable:
|
248
|
+
* check cancellation every cycle of a loop which does significant work,
|
249
|
+
* do all blocking actions in a loop with a timeout then on timeout check cancellation
|
250
|
+
and if ok block again with the timeout
|
251
|
+
* [Throttle](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Throttle.html)
|
252
|
+
A tool managing concurrency level of tasks.
|
253
|
+
* [ErlangActor](http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/ErlangActor.html)
|
254
|
+
Actor implementation which precisely matches Erlang actor behaviour.
|
255
|
+
Requires at least Ruby 2.1 otherwise it's not loaded.
|
227
256
|
|
228
257
|
## Supported Ruby versions
|
229
258
|
|
@@ -339,11 +368,14 @@ and to the past maintainers
|
|
339
368
|
* [Paweł Obrok](https://github.com/obrok)
|
340
369
|
* [Lucas Allan](https://github.com/lucasallan)
|
341
370
|
|
371
|
+
and to [Ruby Association](https://www.ruby.or.jp/en/) for sponsoring a project
|
372
|
+
["Enhancing Ruby’s concurrency tooling"](https://www.ruby.or.jp/en/news/20181106) in 2018.
|
373
|
+
|
342
374
|
## License and Copyright
|
343
375
|
|
344
376
|
*Concurrent Ruby* is free software released under the
|
345
377
|
[MIT License](http://www.opensource.org/licenses/MIT).
|
346
378
|
|
347
|
-
The *Concurrent Ruby* [logo](https://
|
379
|
+
The *Concurrent Ruby* [logo](https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/docs-source/logo/concurrent-ruby-logo-300x300.png) was
|
348
380
|
designed by [David Jones](https://twitter.com/zombyboy). It is Copyright © 2014
|
349
381
|
[Jerry D'Antonio](https://twitter.com/jerrydantonio). All Rights Reserved.
|
data/Rakefile
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
#!/usr/bin/env rake
|
2
|
-
|
3
1
|
require_relative 'lib/concurrent/version'
|
4
2
|
require_relative 'lib/concurrent/utility/engine'
|
5
3
|
|
@@ -18,43 +16,7 @@ edge_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-edge.
|
|
18
16
|
|
19
17
|
require 'rake/javaextensiontask'
|
20
18
|
|
21
|
-
|
22
|
-
def java_classpath_arg(*args)
|
23
|
-
jruby_cpath = nil
|
24
|
-
|
25
|
-
if RUBY_PLATFORM =~ /java/
|
26
|
-
begin
|
27
|
-
cpath = Java::java.lang.System.getProperty('java.class.path').split(File::PATH_SEPARATOR)
|
28
|
-
cpath += Java::java.lang.System.getProperty('sun.boot.class.path').split(File::PATH_SEPARATOR)
|
29
|
-
jruby_cpath = cpath.compact.join(File::PATH_SEPARATOR)
|
30
|
-
rescue => e
|
31
|
-
end
|
32
|
-
|
33
|
-
unless jruby_cpath
|
34
|
-
libdir = RbConfig::CONFIG['libdir']
|
35
|
-
if libdir.start_with? "classpath:"
|
36
|
-
raise 'Cannot build with jruby-complete'
|
37
|
-
end
|
38
|
-
jruby_cpath = File.join(libdir, "jruby.jar")
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
unless jruby_cpath
|
43
|
-
jruby_home = ENV['JRUBY_HOME']
|
44
|
-
if jruby_home
|
45
|
-
candidate = File.join(jruby_home, 'lib', 'jruby.jar')
|
46
|
-
jruby_cpath = candidate if File.exist? candidate
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
raise "jruby.jar path not found" unless jruby_cpath
|
51
|
-
|
52
|
-
jruby_cpath += File::PATH_SEPARATOR + args.join(File::PATH_SEPARATOR) unless args.empty?
|
53
|
-
jruby_cpath ? "-cp \"#{jruby_cpath}\"" : ""
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
ConcurrentRubyJavaExtensionTask.new('concurrent_ruby', core_gemspec) do |ext|
|
19
|
+
Rake::JavaExtensionTask.new('concurrent_ruby', core_gemspec) do |ext|
|
58
20
|
ext.ext_dir = 'ext/concurrent-ruby'
|
59
21
|
ext.lib_dir = 'lib/concurrent'
|
60
22
|
end
|
@@ -80,9 +42,11 @@ namespace :repackage do
|
|
80
42
|
# store gems in vendor cache for docker
|
81
43
|
sh 'bundle package'
|
82
44
|
|
83
|
-
#
|
45
|
+
# build only the jar file not the whole gem for java platform, the jar is part the concurrent-ruby-x.y.z.gem
|
84
46
|
Rake::Task['lib/concurrent/concurrent_ruby.jar'].invoke
|
85
|
-
|
47
|
+
|
48
|
+
# build all gem files
|
49
|
+
RakeCompilerDock.sh 'bundle install --local && bundle exec rake cross native package --trace'
|
86
50
|
end
|
87
51
|
end
|
88
52
|
end
|
@@ -102,15 +66,14 @@ begin
|
|
102
66
|
|
103
67
|
RSpec::Core::RakeTask.new(:spec)
|
104
68
|
|
105
|
-
options = %w[ --color
|
106
|
-
--backtrace
|
107
|
-
--seed 1
|
108
|
-
--format documentation
|
109
|
-
--tag ~notravis ]
|
110
|
-
|
111
69
|
namespace :spec do
|
112
70
|
desc '* Configured for ci'
|
113
71
|
RSpec::Core::RakeTask.new(:ci) do |t|
|
72
|
+
options = %w[ --color
|
73
|
+
--backtrace
|
74
|
+
--order defined
|
75
|
+
--format documentation
|
76
|
+
--tag ~notravis ]
|
114
77
|
t.rspec_opts = [*options].join(' ')
|
115
78
|
end
|
116
79
|
|
@@ -135,7 +98,7 @@ rescue LoadError => e
|
|
135
98
|
puts 'RSpec is not installed, skipping test task definitions: ' + e.message
|
136
99
|
end
|
137
100
|
|
138
|
-
current_yard_version_name =
|
101
|
+
current_yard_version_name = Concurrent::VERSION
|
139
102
|
|
140
103
|
begin
|
141
104
|
require 'yard'
|
@@ -185,10 +148,19 @@ begin
|
|
185
148
|
end
|
186
149
|
|
187
150
|
define_yard_task = -> name do
|
151
|
+
output_dir = "docs/#{name}"
|
152
|
+
|
153
|
+
removal_name = "remove.#{name}"
|
154
|
+
task removal_name do
|
155
|
+
Dir.chdir __dir__ do
|
156
|
+
FileUtils.rm_rf output_dir
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
188
160
|
desc "* of #{name} into subdir #{name}"
|
189
161
|
YARD::Rake::YardocTask.new(name) do |yard|
|
190
162
|
yard.options.push(
|
191
|
-
'--output-dir',
|
163
|
+
'--output-dir', output_dir,
|
192
164
|
'--main', 'tmp/README.md',
|
193
165
|
*common_yard_options)
|
194
166
|
yard.files = ['./lib/**/*.rb',
|
@@ -197,10 +169,11 @@ begin
|
|
197
169
|
'-',
|
198
170
|
'docs-source/thread_pools.md',
|
199
171
|
'docs-source/promises.out.md',
|
172
|
+
'docs-source/medium-example.out.rb',
|
200
173
|
'LICENSE.md',
|
201
174
|
'CHANGELOG.md']
|
202
175
|
end
|
203
|
-
Rake::Task[name].prerequisites.push 'yard:eval_md', 'yard:update_readme'
|
176
|
+
Rake::Task[name].prerequisites.push removal_name, 'yard:eval_md', 'yard:update_readme'
|
204
177
|
end
|
205
178
|
|
206
179
|
define_yard_task.call current_yard_version_name
|
@@ -223,7 +196,15 @@ begin
|
|
223
196
|
begin
|
224
197
|
FileUtils.cp_r 'docs', 'docs-copy', verbose: true
|
225
198
|
Rake::Task["yard:#{name}"].invoke
|
226
|
-
sh 'diff -r docs/ docs-copy/'
|
199
|
+
sh 'diff -r docs/ docs-copy/' do |ok, res|
|
200
|
+
unless ok
|
201
|
+
begin
|
202
|
+
STDOUT.puts 'Command failed. Continue? (y/n)'
|
203
|
+
input = STDIN.gets.strip.downcase
|
204
|
+
end until %w(y n).include?(input)
|
205
|
+
exit 1 if input == 'n'
|
206
|
+
end
|
207
|
+
end
|
227
208
|
ensure
|
228
209
|
FileUtils.rm_rf 'docs-copy', verbose: true
|
229
210
|
end
|
@@ -275,7 +256,7 @@ namespace :release do
|
|
275
256
|
end
|
276
257
|
|
277
258
|
desc '* build all *.gem files necessary for release'
|
278
|
-
task :build => 'repackage:all'
|
259
|
+
task :build => [:clobber, 'repackage:all']
|
279
260
|
|
280
261
|
desc '* test actual installed gems instead of cloned repository on MRI and JRuby'
|
281
262
|
task :test do
|
@@ -23,6 +23,7 @@ import java.lang.reflect.Method;
|
|
23
23
|
public class SynchronizationLibrary implements Library {
|
24
24
|
|
25
25
|
private static final Unsafe UNSAFE = loadUnsafe();
|
26
|
+
private static final boolean FULL_FENCE = supportsFences();
|
26
27
|
|
27
28
|
private static Unsafe loadUnsafe() {
|
28
29
|
try {
|
@@ -140,17 +141,17 @@ public class SynchronizationLibrary implements Library {
|
|
140
141
|
// volatile threadContext is used as a memory barrier per the JVM memory model happens-before semantic
|
141
142
|
// on volatile fields. any volatile field could have been used but using the thread context is an
|
142
143
|
// attempt to avoid code elimination.
|
143
|
-
private static volatile
|
144
|
+
private static volatile int volatileField;
|
144
145
|
|
145
146
|
@JRubyMethod(name = "full_memory_barrier", visibility = Visibility.PUBLIC)
|
146
147
|
public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject self) {
|
147
148
|
// Prevent reordering of ivar writes with publication of this instance
|
148
|
-
if (!
|
149
|
+
if (!FULL_FENCE) {
|
149
150
|
// Assuming that following volatile read and write is not eliminated it simulates fullFence.
|
150
151
|
// If it's eliminated it'll cause problems only on non-x86 platforms.
|
151
152
|
// http://shipilev.net/blog/2014/jmm-pragmatics/#_happens_before_test_your_understanding
|
152
|
-
final
|
153
|
-
|
153
|
+
final int volatileRead = volatileField;
|
154
|
+
volatileField = context.getLine();
|
154
155
|
} else {
|
155
156
|
UNSAFE.fullFence();
|
156
157
|
}
|
@@ -163,9 +164,9 @@ public class SynchronizationLibrary implements Library {
|
|
163
164
|
IRubyObject self,
|
164
165
|
IRubyObject name) {
|
165
166
|
// Ensure we ses latest value with loadFence
|
166
|
-
if (!
|
167
|
+
if (!FULL_FENCE) {
|
167
168
|
// piggybacking on volatile read, simulating loadFence
|
168
|
-
final
|
169
|
+
final int volatileRead = volatileField;
|
169
170
|
return ((RubyBasicObject) self).instance_variable_get(context, name);
|
170
171
|
} else {
|
171
172
|
UNSAFE.loadFence();
|
@@ -180,10 +181,10 @@ public class SynchronizationLibrary implements Library {
|
|
180
181
|
IRubyObject name,
|
181
182
|
IRubyObject value) {
|
182
183
|
// Ensure we make last update visible
|
183
|
-
if (!
|
184
|
+
if (!FULL_FENCE) {
|
184
185
|
// piggybacking on volatile write, simulating storeFence
|
185
186
|
final IRubyObject result = ((RubyBasicObject) self).instance_variable_set(name, value);
|
186
|
-
|
187
|
+
volatileField = context.getLine();
|
187
188
|
return result;
|
188
189
|
} else {
|
189
190
|
// JRuby uses StampedVariableAccessor which calls fullFence
|
data/lib/concurrent/array.rb
CHANGED
@@ -21,8 +21,9 @@ module Concurrent
|
|
21
21
|
# @!macro internal_implementation_note
|
22
22
|
ArrayImplementation = case
|
23
23
|
when Concurrent.on_cruby?
|
24
|
-
#
|
25
|
-
#
|
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.
|
26
27
|
::Array
|
27
28
|
|
28
29
|
when Concurrent.on_jruby?
|
@@ -63,4 +64,3 @@ module Concurrent
|
|
63
64
|
end
|
64
65
|
|
65
66
|
end
|
66
|
-
|
data/lib/concurrent/async.rb
CHANGED
@@ -333,6 +333,13 @@ module Concurrent
|
|
333
333
|
ivar
|
334
334
|
end
|
335
335
|
|
336
|
+
# Check whether the method is responsive
|
337
|
+
#
|
338
|
+
# @param [Symbol] method the method being called
|
339
|
+
def respond_to_missing?(method, include_private = false)
|
340
|
+
@delegate.respond_to?(method) || super
|
341
|
+
end
|
342
|
+
|
336
343
|
# Perform all enqueued tasks.
|
337
344
|
#
|
338
345
|
# This method must be called from within the executor. It must not be
|
@@ -383,6 +390,13 @@ module Concurrent
|
|
383
390
|
ivar.wait
|
384
391
|
ivar
|
385
392
|
end
|
393
|
+
|
394
|
+
# Check whether the method is responsive
|
395
|
+
#
|
396
|
+
# @param [Symbol] method the method being called
|
397
|
+
def respond_to_missing?(method, include_private = false)
|
398
|
+
@delegate.respond_to?(method) || super
|
399
|
+
end
|
386
400
|
end
|
387
401
|
private_constant :AwaitDelegator
|
388
402
|
|
@@ -79,10 +79,10 @@ module Concurrent
|
|
79
79
|
# @!method value=(value)
|
80
80
|
# @!macro atomic_fixnum_method_value_set
|
81
81
|
#
|
82
|
-
# @!method increment(delta)
|
82
|
+
# @!method increment(delta = 1)
|
83
83
|
# @!macro atomic_fixnum_method_increment
|
84
84
|
#
|
85
|
-
# @!method decrement(delta)
|
85
|
+
# @!method decrement(delta = 1)
|
86
86
|
# @!macro atomic_fixnum_method_decrement
|
87
87
|
#
|
88
88
|
# @!method compare_and_set(expect, update)
|
Binary file
|
@@ -48,11 +48,9 @@ module Concurrent
|
|
48
48
|
def post(delay, *args, &task)
|
49
49
|
raise ArgumentError.new('no block given') unless block_given?
|
50
50
|
return false unless running?
|
51
|
-
opts = {
|
52
|
-
|
53
|
-
|
54
|
-
timer_set: self
|
55
|
-
}
|
51
|
+
opts = { executor: @task_executor,
|
52
|
+
args: args,
|
53
|
+
timer_set: self }
|
56
54
|
task = ScheduledTask.execute(delay, opts, &task) # may raise exception
|
57
55
|
task.unscheduled? ? false : task
|
58
56
|
end
|
@@ -74,11 +72,11 @@ module Concurrent
|
|
74
72
|
# @param [Hash] opts the options to create the object with.
|
75
73
|
# @!visibility private
|
76
74
|
def ns_initialize(opts)
|
77
|
-
@queue
|
78
|
-
@task_executor
|
79
|
-
@timer_executor
|
80
|
-
@condition
|
81
|
-
@ruby_pid
|
75
|
+
@queue = Collection::NonConcurrentPriorityQueue.new(order: :min)
|
76
|
+
@task_executor = Options.executor_from_options(opts) || Concurrent.global_io_executor
|
77
|
+
@timer_executor = SingleThreadExecutor.new
|
78
|
+
@condition = Event.new
|
79
|
+
@ruby_pid = $$ # detects if Ruby has forked
|
82
80
|
self.auto_terminate = opts.fetch(:auto_terminate, true)
|
83
81
|
end
|
84
82
|
|
@@ -90,7 +88,7 @@ module Concurrent
|
|
90
88
|
#
|
91
89
|
# @!visibility private
|
92
90
|
def post_task(task)
|
93
|
-
synchronize{ ns_post_task(task) }
|
91
|
+
synchronize { ns_post_task(task) }
|
94
92
|
end
|
95
93
|
|
96
94
|
# @!visibility private
|
@@ -98,7 +96,7 @@ module Concurrent
|
|
98
96
|
return false unless ns_running?
|
99
97
|
ns_reset_if_forked
|
100
98
|
if (task.initial_delay) <= 0.01
|
101
|
-
task.executor.post{ task.process_task }
|
99
|
+
task.executor.post { task.process_task }
|
102
100
|
else
|
103
101
|
@queue.push(task)
|
104
102
|
# only post the process method when the queue is empty
|
@@ -116,7 +114,7 @@ module Concurrent
|
|
116
114
|
#
|
117
115
|
# @!visibility private
|
118
116
|
def remove_task(task)
|
119
|
-
synchronize{ @queue.delete(task) }
|
117
|
+
synchronize { @queue.delete(task) }
|
120
118
|
end
|
121
119
|
|
122
120
|
# `ExecutorService` callback called during shutdown.
|
@@ -148,7 +146,7 @@ module Concurrent
|
|
148
146
|
task = synchronize { @condition.reset; @queue.peek }
|
149
147
|
break unless task
|
150
148
|
|
151
|
-
now
|
149
|
+
now = Concurrent.monotonic_time
|
152
150
|
diff = task.schedule_time - now
|
153
151
|
|
154
152
|
if diff <= 0
|
@@ -165,7 +163,7 @@ module Concurrent
|
|
165
163
|
# queue now must have the same pop time, or a closer one, as
|
166
164
|
# when we peeked).
|
167
165
|
task = synchronize { @queue.pop }
|
168
|
-
task.executor.post{ task.process_task }
|
166
|
+
task.executor.post { task.process_task }
|
169
167
|
else
|
170
168
|
@condition.wait([diff, 60].min)
|
171
169
|
end
|