concurrent-ruby 1.0.3.pre3-java → 1.0.4-java
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 +40 -12
- data/README.md +29 -39
- data/lib/concurrent.rb +3 -3
- data/lib/concurrent/async.rb +2 -2
- data/lib/concurrent/atom.rb +4 -3
- data/lib/concurrent/atomic/abstract_thread_local_var.rb +29 -3
- data/lib/concurrent/atomic/atomic_fixnum.rb +4 -0
- data/lib/concurrent/atomic/atomic_reference.rb +7 -0
- data/lib/concurrent/atomic/count_down_latch.rb +23 -0
- data/lib/concurrent/atomic/cyclic_barrier.rb +23 -3
- data/lib/concurrent/atomic/java_thread_local_var.rb +1 -14
- data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +2 -18
- data/lib/concurrent/atomic/mutex_count_down_latch.rb +3 -3
- data/lib/concurrent/atomic/mutex_semaphore.rb +15 -15
- data/lib/concurrent/atomic/ruby_thread_local_var.rb +31 -42
- data/lib/concurrent/atomic/thread_local_var.rb +7 -5
- data/lib/concurrent/atomic_reference/jruby+truffle.rb +2 -1
- data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +1 -0
- data/lib/concurrent/concern/obligation.rb +1 -0
- data/lib/concurrent/configuration.rb +56 -21
- data/lib/concurrent/errors.rb +24 -1
- data/lib/concurrent/executor/timer_set.rb +11 -0
- data/lib/concurrent/hash.rb +2 -1
- data/lib/concurrent/map.rb +5 -3
- data/lib/concurrent/promise.rb +10 -6
- data/lib/concurrent/synchronization/object.rb +2 -2
- data/lib/concurrent/synchronization/rbx_object.rb +1 -0
- data/lib/concurrent/synchronization/truffle_object.rb +1 -2
- data/lib/concurrent/thread_safe/util.rb +2 -0
- data/lib/concurrent/timer_task.rb +3 -3
- data/lib/concurrent/tvar.rb +1 -1
- data/lib/concurrent/utility/engine.rb +3 -3
- data/lib/concurrent/utility/native_integer.rb +53 -0
- data/lib/concurrent/utility/processor_counter.rb +15 -13
- data/lib/concurrent/version.rb +2 -2
- data/lib/concurrent_ruby_ext.jar +0 -0
- metadata +8 -6
data/lib/concurrent/errors.rb
CHANGED
@@ -30,7 +30,18 @@ module Concurrent
|
|
30
30
|
|
31
31
|
# Raised when an attempt is made to modify an immutable object
|
32
32
|
# (such as an `IVar`) after its final state has been set.
|
33
|
-
MultipleAssignmentError
|
33
|
+
class MultipleAssignmentError < Error
|
34
|
+
attr_reader :inspection_data
|
35
|
+
|
36
|
+
def initialize(message = nil, inspection_data = nil)
|
37
|
+
@inspection_data = inspection_data
|
38
|
+
super message
|
39
|
+
end
|
40
|
+
|
41
|
+
def inspect
|
42
|
+
format '%s %s>', super[0..-2], @inspection_data.inspect
|
43
|
+
end
|
44
|
+
end
|
34
45
|
|
35
46
|
# Raised by an `Executor` when it is unable to process a given task,
|
36
47
|
# possibly because of a reject policy or other internal error.
|
@@ -43,4 +54,16 @@ module Concurrent
|
|
43
54
|
# Raised when an operation times out.
|
44
55
|
TimeoutError = Class.new(Error)
|
45
56
|
|
57
|
+
# Aggregates multiple exceptions.
|
58
|
+
class MultipleErrors < Error
|
59
|
+
attr_reader :errors
|
60
|
+
|
61
|
+
def initialize(errors, message = "#{errors.size} errors")
|
62
|
+
@errors = errors
|
63
|
+
super [*message,
|
64
|
+
*errors.map { |e| [format('%s (%s)', e.message, e.class), *e.backtrace] }.flatten(1)
|
65
|
+
].join("\n")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
46
69
|
end
|
@@ -78,6 +78,7 @@ module Concurrent
|
|
78
78
|
@task_executor = Options.executor_from_options(opts) || Concurrent.global_io_executor
|
79
79
|
@timer_executor = SingleThreadExecutor.new
|
80
80
|
@condition = Event.new
|
81
|
+
@ruby_pid = $$ # detects if Ruby has forked
|
81
82
|
self.auto_terminate = opts.fetch(:auto_terminate, true)
|
82
83
|
end
|
83
84
|
|
@@ -95,6 +96,7 @@ module Concurrent
|
|
95
96
|
# @!visibility private
|
96
97
|
def ns_post_task(task)
|
97
98
|
return false unless ns_running?
|
99
|
+
ns_reset_if_forked
|
98
100
|
if (task.initial_delay) <= 0.01
|
99
101
|
task.executor.post{ task.process_task }
|
100
102
|
else
|
@@ -121,11 +123,20 @@ module Concurrent
|
|
121
123
|
#
|
122
124
|
# @!visibility private
|
123
125
|
def ns_shutdown_execution
|
126
|
+
ns_reset_if_forked
|
124
127
|
@queue.clear
|
125
128
|
@timer_executor.kill
|
126
129
|
stopped_event.set
|
127
130
|
end
|
128
131
|
|
132
|
+
def ns_reset_if_forked
|
133
|
+
if $$ != @ruby_pid
|
134
|
+
@queue.clear
|
135
|
+
@condition.reset
|
136
|
+
@ruby_pid = $$
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
129
140
|
# Run a loop and execute tasks in the scheduled order and at the approximate
|
130
141
|
# scheduled time. If no tasks remain the thread will exit gracefully so that
|
131
142
|
# garbage collection can occur. If there are no ready tasks it will sleep
|
data/lib/concurrent/hash.rb
CHANGED
@@ -8,7 +8,8 @@ module Concurrent
|
|
8
8
|
#
|
9
9
|
# A thread-safe subclass of Hash. This version locks against the object
|
10
10
|
# itself for every method call, ensuring only one thread can be reading
|
11
|
-
# or writing at a time. This includes iteration methods like `#each
|
11
|
+
# or writing at a time. This includes iteration methods like `#each`,
|
12
|
+
# which takes the lock repeatedly when reading an item.
|
12
13
|
#
|
13
14
|
# @see http://ruby-doc.org/core-2.2.0/Hash.html Ruby standard library `Hash`
|
14
15
|
class Hash < ::Hash;
|
data/lib/concurrent/map.rb
CHANGED
@@ -171,6 +171,8 @@ module Concurrent
|
|
171
171
|
each_pair {|k, v| yield v}
|
172
172
|
end unless method_defined?(:each_value)
|
173
173
|
|
174
|
+
alias_method :each, :each_pair unless method_defined?(:each)
|
175
|
+
|
174
176
|
def key(value)
|
175
177
|
each_pair {|k, v| return k if v == value}
|
176
178
|
nil
|
@@ -203,7 +205,7 @@ module Concurrent
|
|
203
205
|
undef :freeze
|
204
206
|
|
205
207
|
# @!visibility private
|
206
|
-
DEFAULT_OBJ_ID_STR_WIDTH =
|
208
|
+
DEFAULT_OBJ_ID_STR_WIDTH = 0.size == 4 ? 7 : 14 # we want to look "native", 7 for 32-bit, 14 for 64-bit
|
207
209
|
# override default #inspect() method: firstly, we don't want to be spilling our guts (i-vars), secondly, MRI backend's
|
208
210
|
# #inspect() call on its @backend i-var will bump @backend's iter level while possibly yielding GVL
|
209
211
|
def inspect
|
@@ -227,8 +229,8 @@ module Concurrent
|
|
227
229
|
end
|
228
230
|
|
229
231
|
def validate_options_hash!(options)
|
230
|
-
if (initial_capacity = options[:initial_capacity]) && (!initial_capacity.kind_of?(
|
231
|
-
raise ArgumentError, ":initial_capacity must be a positive
|
232
|
+
if (initial_capacity = options[:initial_capacity]) && (!initial_capacity.kind_of?(Integer) || initial_capacity < 0)
|
233
|
+
raise ArgumentError, ":initial_capacity must be a positive Integer"
|
232
234
|
end
|
233
235
|
if (load_factor = options[:load_factor]) && (!load_factor.kind_of?(Numeric) || load_factor <= 0 || load_factor > 1)
|
234
236
|
raise ArgumentError, ":load_factor must be a number between 0 and 1"
|
data/lib/concurrent/promise.rb
CHANGED
@@ -2,6 +2,7 @@ require 'thread'
|
|
2
2
|
require 'concurrent/constants'
|
3
3
|
require 'concurrent/errors'
|
4
4
|
require 'concurrent/ivar'
|
5
|
+
require 'concurrent/executor/safe_task_executor'
|
5
6
|
|
6
7
|
require 'concurrent/options'
|
7
8
|
|
@@ -78,7 +79,7 @@ module Concurrent
|
|
78
79
|
# ```
|
79
80
|
#
|
80
81
|
# Promises can be chained using the `then` method. The `then` method accepts a
|
81
|
-
# block, to be executed on fulfillment, and a callable argument to be executed
|
82
|
+
# block and an executor, to be executed on fulfillment, and a callable argument to be executed
|
82
83
|
# on rejection. The result of the each promise is passed as the block argument
|
83
84
|
# to chained promises.
|
84
85
|
#
|
@@ -92,7 +93,7 @@ module Concurrent
|
|
92
93
|
# p = Concurrent::Promise.fulfill(20).
|
93
94
|
# then{|result| result - 10 }.
|
94
95
|
# then{|result| result * 3 }.
|
95
|
-
# then{|result| result % 5 }.execute
|
96
|
+
# then(executor: different_executor){|result| result % 5 }.execute
|
96
97
|
# ```
|
97
98
|
#
|
98
99
|
# The initial state of a newly created Promise depends on the state of its parent:
|
@@ -102,7 +103,7 @@ module Concurrent
|
|
102
103
|
# - if parent is *rejected* the child will be *pending* (but will ultimately be *rejected*)
|
103
104
|
#
|
104
105
|
# Promises are executed asynchronously from the main thread. By the time a
|
105
|
-
# child Promise finishes
|
106
|
+
# child Promise finishes intialization it may be in a different state than its
|
106
107
|
# parent (by the time a child is created its parent may have completed
|
107
108
|
# execution and changed state). Despite being asynchronous, however, the order
|
108
109
|
# of execution of Promise objects in a chain (or tree) is strictly defined.
|
@@ -300,15 +301,18 @@ module Concurrent
|
|
300
301
|
# @param [Proc] rescuer An optional rescue block to be executed if the
|
301
302
|
# promise is rejected.
|
302
303
|
#
|
304
|
+
# @param [ThreadPool] executor An optional thread pool executor to be used
|
305
|
+
# in the new Promise
|
306
|
+
#
|
303
307
|
# @yield The block operation to be performed asynchronously.
|
304
308
|
#
|
305
309
|
# @return [Promise] the new promise
|
306
|
-
def then(rescuer = nil, &block)
|
310
|
+
def then(rescuer = nil, executor = @executor, &block)
|
307
311
|
raise ArgumentError.new('rescuers and block are both missing') if rescuer.nil? && !block_given?
|
308
312
|
block = Proc.new { |result| result } unless block_given?
|
309
313
|
child = Promise.new(
|
310
314
|
parent: self,
|
311
|
-
executor:
|
315
|
+
executor: executor,
|
312
316
|
on_fulfill: block,
|
313
317
|
on_reject: rescuer
|
314
318
|
)
|
@@ -524,7 +528,7 @@ module Concurrent
|
|
524
528
|
# @!visibility private
|
525
529
|
def realize(task)
|
526
530
|
@executor.post do
|
527
|
-
success, value, reason = SafeTaskExecutor.new(task).execute(*@args)
|
531
|
+
success, value, reason = SafeTaskExecutor.new(task, rescue_exception: true).execute(*@args)
|
528
532
|
complete(success, value, reason)
|
529
533
|
end
|
530
534
|
end
|
@@ -70,8 +70,8 @@ module Concurrent
|
|
70
70
|
# any instance variables with CamelCase names and isn't {.safe_initialization?}.
|
71
71
|
def self.ensure_safe_initialization_when_final_fields_are_present
|
72
72
|
Object.class_eval do
|
73
|
-
def self.new(*)
|
74
|
-
object = super
|
73
|
+
def self.new(*args, &block)
|
74
|
+
object = super(*args, &block)
|
75
75
|
ensure
|
76
76
|
has_final_field = object.instance_variables.any? { |v| v.to_s =~ /^@[A-Z]/ }
|
77
77
|
if has_final_field && !safe_initialization?
|
@@ -6,8 +6,10 @@ module Concurrent
|
|
6
6
|
# @!visibility private
|
7
7
|
module Util
|
8
8
|
|
9
|
+
# TODO (pitr-ch 15-Oct-2016): migrate to Utility::NativeInteger
|
9
10
|
FIXNUM_BIT_SIZE = (0.size * 8) - 2
|
10
11
|
MAX_INT = (2 ** FIXNUM_BIT_SIZE) - 1
|
12
|
+
# TODO (pitr-ch 15-Oct-2016): migrate to Utility::ProcessorCounter
|
11
13
|
CPU_COUNT = 16 # is there a way to determine this?
|
12
14
|
end
|
13
15
|
end
|
@@ -9,7 +9,7 @@ require 'concurrent/scheduled_task'
|
|
9
9
|
|
10
10
|
module Concurrent
|
11
11
|
|
12
|
-
# A very common
|
12
|
+
# A very common concurrency pattern is to run a thread that performs a task at
|
13
13
|
# regular intervals. The thread that performs the task sleeps for the given
|
14
14
|
# interval then wakes up and performs the task. Lather, rinse, repeat... This
|
15
15
|
# pattern causes two problems. First, it is difficult to test the business
|
@@ -23,7 +23,7 @@ module Concurrent
|
|
23
23
|
# execution interval. The `TimerTask` thread does not perform the task,
|
24
24
|
# however. Instead, the TimerTask launches the task on a separate thread.
|
25
25
|
# Should the task experience an unrecoverable crash only the task thread will
|
26
|
-
# crash. This makes the `TimerTask` very fault tolerant Additionally, the
|
26
|
+
# crash. This makes the `TimerTask` very fault tolerant. Additionally, the
|
27
27
|
# `TimerTask` thread can respond to the success or failure of the task,
|
28
28
|
# performing logging or ancillary operations. `TimerTask` can also be
|
29
29
|
# configured with a timeout value allowing it to kill a task that runs too
|
@@ -41,7 +41,7 @@ module Concurrent
|
|
41
41
|
#
|
42
42
|
# The `TimerTask` class includes the `Dereferenceable` mixin module so the
|
43
43
|
# result of the last execution is always available via the `#value` method.
|
44
|
-
#
|
44
|
+
# Dereferencing options can be passed to the `TimerTask` during construction or
|
45
45
|
# at any later time using the `#set_deref_options` method.
|
46
46
|
#
|
47
47
|
# `TimerTask` supports notification through the Ruby standard library
|
data/lib/concurrent/tvar.rb
CHANGED
@@ -151,7 +151,7 @@ module Concurrent
|
|
151
151
|
raise Transaction::AbortError.new
|
152
152
|
end
|
153
153
|
|
154
|
-
# Leave a transaction without
|
154
|
+
# Leave a transaction without committing or aborting - see `Concurrent::atomically`.
|
155
155
|
def leave_transaction
|
156
156
|
raise Transaction::LeaveError.new
|
157
157
|
end
|
@@ -8,7 +8,7 @@ module Concurrent
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def on_jruby_9000?
|
11
|
-
on_jruby? &&
|
11
|
+
on_jruby? && ruby_version(:>=, 9, 0, 0, JRUBY_VERSION)
|
12
12
|
end
|
13
13
|
|
14
14
|
def on_cruby?
|
@@ -39,8 +39,8 @@ module Concurrent
|
|
39
39
|
defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
|
40
40
|
end
|
41
41
|
|
42
|
-
def ruby_version(comparison, major, minor
|
43
|
-
result = (
|
42
|
+
def ruby_version(comparison, major, minor, patch, version = RUBY_VERSION)
|
43
|
+
result = (version.split('.').map(&:to_i) <=> [major, minor, patch])
|
44
44
|
comparisons = { :== => [0],
|
45
45
|
:>= => [1, 0],
|
46
46
|
:<= => [-1, 0],
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Concurrent
|
2
|
+
module Utility
|
3
|
+
# @private
|
4
|
+
module NativeInteger
|
5
|
+
# http://stackoverflow.com/questions/535721/ruby-max-integer
|
6
|
+
MIN_VALUE = -(2**(0.size * 8 - 2))
|
7
|
+
MAX_VALUE = (2**(0.size * 8 - 2) - 1)
|
8
|
+
|
9
|
+
def ensure_upper_bound(value)
|
10
|
+
if value > MAX_VALUE
|
11
|
+
raise RangeError.new("#{value} is greater than the maximum value of #{MAX_VALUE}")
|
12
|
+
end
|
13
|
+
value
|
14
|
+
end
|
15
|
+
|
16
|
+
def ensure_lower_bound(value)
|
17
|
+
if value < MIN_VALUE
|
18
|
+
raise RangeError.new("#{value} is less than the maximum value of #{MIN_VALUE}")
|
19
|
+
end
|
20
|
+
value
|
21
|
+
end
|
22
|
+
|
23
|
+
def ensure_integer(value)
|
24
|
+
unless value.is_a?(Integer)
|
25
|
+
raise ArgumentError.new("#{value} is not an Integer")
|
26
|
+
end
|
27
|
+
value
|
28
|
+
end
|
29
|
+
|
30
|
+
def ensure_integer_and_bounds(value)
|
31
|
+
ensure_integer value
|
32
|
+
ensure_upper_bound value
|
33
|
+
ensure_lower_bound value
|
34
|
+
end
|
35
|
+
|
36
|
+
def ensure_positive(value)
|
37
|
+
if value < 0
|
38
|
+
raise ArgumentError.new("#{value} cannot be negative")
|
39
|
+
end
|
40
|
+
value
|
41
|
+
end
|
42
|
+
|
43
|
+
def ensure_positive_and_no_zero(value)
|
44
|
+
if value < 1
|
45
|
+
raise ArgumentError.new("#{value} cannot be negative or zero")
|
46
|
+
end
|
47
|
+
value
|
48
|
+
end
|
49
|
+
|
50
|
+
extend self
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -28,6 +28,7 @@ module Concurrent
|
|
28
28
|
# processor", which taked into account hyperthreading.
|
29
29
|
#
|
30
30
|
# * AIX: /usr/sbin/pmcycles (AIX 5+), /usr/sbin/lsdev
|
31
|
+
# * Alpha: /usr/bin/nproc (/proc/cpuinfo exists but cannot be used)
|
31
32
|
# * BSD: /sbin/sysctl
|
32
33
|
# * Cygwin: /proc/cpuinfo
|
33
34
|
# * Darwin: /usr/bin/hwprefs, /usr/sbin/sysctl
|
@@ -84,27 +85,28 @@ module Concurrent
|
|
84
85
|
result = WIN32OLE.connect("winmgmts://").ExecQuery(
|
85
86
|
"select NumberOfLogicalProcessors from Win32_Processor")
|
86
87
|
result.to_enum.collect(&:NumberOfLogicalProcessors).reduce(:+)
|
87
|
-
elsif File.readable?("/proc/cpuinfo")
|
88
|
-
|
88
|
+
elsif File.readable?("/proc/cpuinfo") && (cpuinfo_count = IO.read("/proc/cpuinfo").scan(/^processor/).size) > 0
|
89
|
+
cpuinfo_count
|
90
|
+
elsif File.executable?("/usr/bin/nproc")
|
91
|
+
IO.popen("/usr/bin/nproc --all", &:read).to_i
|
89
92
|
elsif File.executable?("/usr/bin/hwprefs")
|
90
|
-
IO.popen("/usr/bin/hwprefs thread_count").
|
93
|
+
IO.popen("/usr/bin/hwprefs thread_count", &:read).to_i
|
91
94
|
elsif File.executable?("/usr/sbin/psrinfo")
|
92
|
-
IO.popen("/usr/sbin/psrinfo").
|
95
|
+
IO.popen("/usr/sbin/psrinfo", &:read).scan(/^.*on-*line/).size
|
93
96
|
elsif File.executable?("/usr/sbin/ioscan")
|
94
|
-
IO.popen("/usr/sbin/ioscan -kC processor")
|
95
|
-
out.read.scan(/^.*processor/).size
|
96
|
-
end
|
97
|
+
IO.popen("/usr/sbin/ioscan -kC processor", &:read).scan(/^.*processor/).size
|
97
98
|
elsif File.executable?("/usr/sbin/pmcycles")
|
98
|
-
IO.popen("/usr/sbin/pmcycles -m").
|
99
|
+
IO.popen("/usr/sbin/pmcycles -m", &:read).count("\n")
|
99
100
|
elsif File.executable?("/usr/sbin/lsdev")
|
100
|
-
IO.popen("/usr/sbin/lsdev -Cc processor -S 1").
|
101
|
+
IO.popen("/usr/sbin/lsdev -Cc processor -S 1", &:read).count("\n")
|
101
102
|
elsif File.executable?("/usr/sbin/sysconf") and os_name =~ /irix/i
|
102
|
-
IO.popen("/usr/sbin/sysconf NPROC_ONLN").
|
103
|
+
IO.popen("/usr/sbin/sysconf NPROC_ONLN", &:read).to_i
|
103
104
|
elsif File.executable?("/usr/sbin/sysctl")
|
104
|
-
IO.popen("/usr/sbin/sysctl -n hw.ncpu").
|
105
|
+
IO.popen("/usr/sbin/sysctl -n hw.ncpu", &:read).to_i
|
105
106
|
elsif File.executable?("/sbin/sysctl")
|
106
|
-
IO.popen("/sbin/sysctl -n hw.ncpu").
|
107
|
+
IO.popen("/sbin/sysctl -n hw.ncpu", &:read).to_i
|
107
108
|
else
|
109
|
+
# TODO (pitr-ch 05-Nov-2016): warn about failures
|
108
110
|
1
|
109
111
|
end
|
110
112
|
end
|
@@ -115,7 +117,7 @@ module Concurrent
|
|
115
117
|
def compute_physical_processor_count
|
116
118
|
ppc = case RbConfig::CONFIG["target_os"]
|
117
119
|
when /darwin1/
|
118
|
-
IO.popen("/usr/sbin/sysctl -n hw.physicalcpu").
|
120
|
+
IO.popen("/usr/sbin/sysctl -n hw.physicalcpu", &:read).to_i
|
119
121
|
when /linux/
|
120
122
|
cores = {} # unique physical ID / core ID combinations
|
121
123
|
phy = 0
|
data/lib/concurrent/version.rb
CHANGED
data/lib/concurrent_ruby_ext.jar
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: concurrent-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Jerry D'Antonio
|
8
|
+
- Petr Chalupa
|
8
9
|
- The Ruby Concurrency Team
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date: 2016-
|
13
|
+
date: 2016-12-27 00:00:00.000000000 Z
|
13
14
|
dependencies: []
|
14
15
|
description: |
|
15
16
|
Modern concurrency tools including agents, futures, promises, thread pools, actors, supervisors, and more.
|
@@ -147,6 +148,7 @@ files:
|
|
147
148
|
- lib/concurrent/utility/engine.rb
|
148
149
|
- lib/concurrent/utility/monotonic_time.rb
|
149
150
|
- lib/concurrent/utility/native_extension_loader.rb
|
151
|
+
- lib/concurrent/utility/native_integer.rb
|
150
152
|
- lib/concurrent/utility/processor_counter.rb
|
151
153
|
- lib/concurrent/version.rb
|
152
154
|
- lib/concurrent_ruby_ext.jar
|
@@ -160,17 +162,17 @@ require_paths:
|
|
160
162
|
- lib
|
161
163
|
required_ruby_version: !ruby/object:Gem::Requirement
|
162
164
|
requirements:
|
163
|
-
- -
|
165
|
+
- - ">="
|
164
166
|
- !ruby/object:Gem::Version
|
165
167
|
version: 1.9.3
|
166
168
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
169
|
requirements:
|
168
|
-
- -
|
170
|
+
- - ">="
|
169
171
|
- !ruby/object:Gem::Version
|
170
|
-
version:
|
172
|
+
version: '0'
|
171
173
|
requirements: []
|
172
174
|
rubyforge_project:
|
173
|
-
rubygems_version: 2.
|
175
|
+
rubygems_version: 2.6.8
|
174
176
|
signing_key:
|
175
177
|
specification_version: 4
|
176
178
|
summary: Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell, F#, C#, Java, and classic concurrency patterns.
|