concurrent-ruby 1.1.8 → 1.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/Gemfile +2 -7
  4. data/README.md +40 -20
  5. data/Rakefile +26 -31
  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/lib/concurrent-ruby/concurrent/async.rb +1 -0
  9. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +1 -0
  10. data/lib/concurrent-ruby/concurrent/atomic/event.rb +2 -2
  11. data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +18 -2
  12. data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +4 -6
  13. data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +26 -5
  14. data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
  15. data/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +11 -1
  16. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  17. data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +16 -13
  18. data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +13 -3
  19. data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +1 -1
  20. data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +4 -0
  21. data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +10 -4
  22. data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +26 -37
  23. data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +5 -5
  24. data/lib/concurrent-ruby/concurrent/map.rb +13 -4
  25. data/lib/concurrent-ruby/concurrent/promise.rb +1 -0
  26. data/lib/concurrent-ruby/concurrent/scheduled_task.rb +29 -16
  27. data/lib/concurrent-ruby/concurrent/set.rb +14 -6
  28. data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +1 -3
  29. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +12 -0
  30. data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +6 -0
  31. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +26 -1
  32. data/lib/concurrent-ruby/concurrent/timer_task.rb +11 -33
  33. data/lib/concurrent-ruby/concurrent/tvar.rb +20 -60
  34. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +67 -35
  35. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +2 -35
  36. data/lib/concurrent-ruby/concurrent/version.rb +1 -1
  37. data/lib/concurrent-ruby/concurrent-ruby.rb +5 -1
  38. metadata +8 -7
@@ -15,7 +15,6 @@ module Concurrent
15
15
  # Create a new `TVar` with an initial value.
16
16
  def initialize(value)
17
17
  @value = value
18
- @version = 0
19
18
  @lock = Mutex.new
20
19
  end
21
20
 
@@ -43,16 +42,6 @@ module Concurrent
43
42
  @value = value
44
43
  end
45
44
 
46
- # @!visibility private
47
- def unsafe_version # :nodoc:
48
- @version
49
- end
50
-
51
- # @!visibility private
52
- def unsafe_increment_version # :nodoc:
53
- @version += 1
54
- end
55
-
56
45
  # @!visibility private
57
46
  def unsafe_lock # :nodoc:
58
47
  @lock
@@ -164,53 +153,39 @@ module Concurrent
164
153
 
165
154
  ABORTED = ::Object.new
166
155
 
167
- ReadLogEntry = Struct.new(:tvar, :version)
156
+ OpenEntry = Struct.new(:value, :modified)
168
157
 
169
158
  AbortError = Class.new(StandardError)
170
159
  LeaveError = Class.new(StandardError)
171
160
 
172
161
  def initialize
173
- @read_log = []
174
- @write_log = {}
162
+ @open_tvars = {}
175
163
  end
176
164
 
177
165
  def read(tvar)
178
- Concurrent::abort_transaction unless valid?
179
-
180
- if @write_log.has_key? tvar
181
- @write_log[tvar]
182
- else
183
- @read_log.push(ReadLogEntry.new(tvar, tvar.unsafe_version))
184
- tvar.unsafe_value
185
- end
166
+ entry = open(tvar)
167
+ entry.value
186
168
  end
187
169
 
188
170
  def write(tvar, value)
189
- # Have we already written to this TVar?
171
+ entry = open(tvar)
172
+ entry.modified = true
173
+ entry.value = value
174
+ end
190
175
 
191
- if @write_log.has_key? tvar
192
- # Record the value written
193
- @write_log[tvar] = value
194
- else
195
- # Try to lock the TVar
176
+ def open(tvar)
177
+ entry = @open_tvars[tvar]
196
178
 
179
+ unless entry
197
180
  unless tvar.unsafe_lock.try_lock
198
- # Someone else is writing to this TVar - abort
199
181
  Concurrent::abort_transaction
200
182
  end
201
183
 
202
- # Record the value written
203
-
204
- @write_log[tvar] = value
205
-
206
- # If we previously read from it, check the version hasn't changed
207
-
208
- @read_log.each do |log_entry|
209
- if log_entry.tvar == tvar and tvar.unsafe_version > log_entry.version
210
- Concurrent::abort_transaction
211
- end
212
- end
184
+ entry = OpenEntry.new(tvar.unsafe_value, false)
185
+ @open_tvars[tvar] = entry
213
186
  end
187
+
188
+ entry
214
189
  end
215
190
 
216
191
  def abort
@@ -218,32 +193,17 @@ module Concurrent
218
193
  end
219
194
 
220
195
  def commit
221
- return false unless valid?
222
-
223
- @write_log.each_pair do |tvar, value|
224
- tvar.unsafe_value = value
225
- tvar.unsafe_increment_version
226
- end
227
-
228
- unlock
229
-
230
- true
231
- end
232
-
233
- def valid?
234
- @read_log.each do |log_entry|
235
- unless @write_log.has_key? log_entry.tvar
236
- if log_entry.tvar.unsafe_version > log_entry.version
237
- return false
238
- end
196
+ @open_tvars.each do |tvar, entry|
197
+ if entry.modified
198
+ tvar.unsafe_value = entry.value
239
199
  end
240
200
  end
241
201
 
242
- true
202
+ unlock
243
203
  end
244
204
 
245
205
  def unlock
246
- @write_log.each_key do |tvar|
206
+ @open_tvars.each_key do |tvar|
247
207
  tvar.unsafe_lock.unlock
248
208
  end
249
209
  end
@@ -2,26 +2,64 @@ require 'concurrent/synchronization'
2
2
 
3
3
  module Concurrent
4
4
 
5
- class_definition = Class.new(Synchronization::LockableObject) do
6
- def initialize
7
- @last_time = Time.now.to_f
8
- super()
5
+ # @!macro monotonic_get_time
6
+ #
7
+ # Returns the current time a tracked by the application monotonic clock.
8
+ #
9
+ # @param [Symbol] unit the time unit to be returned, can be either
10
+ # :float_second, :float_millisecond, :float_microsecond, :second,
11
+ # :millisecond, :microsecond, or :nanosecond default to :float_second.
12
+ #
13
+ # @return [Float] The current monotonic time since some unspecified
14
+ # starting point
15
+ #
16
+ # @!macro monotonic_clock_warning
17
+ if defined?(Process::CLOCK_MONOTONIC)
18
+
19
+ def monotonic_time(unit = :float_second)
20
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, unit)
9
21
  end
10
22
 
11
- if defined?(Process::CLOCK_MONOTONIC)
12
- # @!visibility private
13
- def get_time
14
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
15
- end
16
- elsif Concurrent.on_jruby?
17
- # @!visibility private
18
- def get_time
19
- java.lang.System.nanoTime() / 1_000_000_000.0
23
+ elsif Concurrent.on_jruby?
24
+
25
+ # @!visibility private
26
+ TIME_UNITS = Hash.new { |_hash, key| raise ArgumentError, "unexpected unit: #{key}" }.compare_by_identity
27
+ TIME_UNITS.merge!(
28
+ second: 1_000_000_000,
29
+ millisecond: 1_000_000,
30
+ microsecond: 1_000,
31
+ nanosecond: 1,
32
+ float_second: 1_000_000_000.0,
33
+ float_millisecond: 1_000_000.0,
34
+ float_microsecond: 1_000.0,
35
+ )
36
+ TIME_UNITS.freeze
37
+ private_constant :TIME_UNITS
38
+
39
+ def monotonic_time(unit = :float_second)
40
+ java.lang.System.nanoTime() / TIME_UNITS[unit]
41
+ end
42
+
43
+ else
44
+
45
+ class_definition = Class.new(Synchronization::LockableObject) do
46
+ def initialize
47
+ @last_time = Time.now.to_f
48
+ @time_units = Hash.new { |_hash, key| raise ArgumentError, "unexpected unit: #{key}" }.compare_by_identity
49
+ @time_units.merge!(
50
+ second: [nil, true],
51
+ millisecond: [1_000, true],
52
+ microsecond: [1_000_000, true],
53
+ nanosecond: [1_000_000_000, true],
54
+ float_second: [nil, false],
55
+ float_millisecond: [1_000.0, false],
56
+ float_microsecond: [1_000_000.0, false],
57
+ )
58
+ super()
20
59
  end
21
- else
22
60
 
23
61
  # @!visibility private
24
- def get_time
62
+ def get_time(unit)
25
63
  synchronize do
26
64
  now = Time.now.to_f
27
65
  if @last_time < now
@@ -29,30 +67,24 @@ module Concurrent
29
67
  else # clock has moved back in time
30
68
  @last_time += 0.000_001
31
69
  end
70
+ scale, to_int = @time_units[unit]
71
+ now *= scale if scale
72
+ now = now.to_i if to_int
73
+ now
32
74
  end
33
75
  end
34
-
35
76
  end
36
- end
37
77
 
38
- # Clock that cannot be set and represents monotonic time since
39
- # some unspecified starting point.
40
- #
41
- # @!visibility private
42
- GLOBAL_MONOTONIC_CLOCK = class_definition.new
43
- private_constant :GLOBAL_MONOTONIC_CLOCK
44
-
45
- # @!macro monotonic_get_time
46
- #
47
- # Returns the current time a tracked by the application monotonic clock.
48
- #
49
- # @return [Float] The current monotonic time since some unspecified
50
- # starting point
51
- #
52
- # @!macro monotonic_clock_warning
53
- def monotonic_time
54
- GLOBAL_MONOTONIC_CLOCK.get_time
78
+ # Clock that cannot be set and represents monotonic time since
79
+ # some unspecified starting point.
80
+ #
81
+ # @!visibility private
82
+ GLOBAL_MONOTONIC_CLOCK = class_definition.new
83
+ private_constant :GLOBAL_MONOTONIC_CLOCK
84
+
85
+ def monotonic_time(unit = :float_second)
86
+ GLOBAL_MONOTONIC_CLOCK.get_time(unit)
87
+ end
55
88
  end
56
-
57
89
  module_function :monotonic_time
58
90
  end
@@ -79,47 +79,14 @@ module Concurrent
79
79
  def compute_processor_count
80
80
  if Concurrent.on_jruby?
81
81
  java.lang.Runtime.getRuntime.availableProcessors
82
- elsif Etc.respond_to?(:nprocessors) && (nprocessor = Etc.nprocessors rescue nil)
83
- nprocessor
84
82
  else
85
- os_name = RbConfig::CONFIG["target_os"]
86
- if os_name =~ /mingw|mswin/
87
- require 'win32ole'
88
- result = WIN32OLE.connect("winmgmts://").ExecQuery(
89
- "select NumberOfLogicalProcessors from Win32_Processor")
90
- result.to_enum.collect(&:NumberOfLogicalProcessors).reduce(:+)
91
- elsif File.readable?("/proc/cpuinfo") && (cpuinfo_count = IO.read("/proc/cpuinfo").scan(/^processor/).size) > 0
92
- cpuinfo_count
93
- elsif File.executable?("/usr/bin/nproc")
94
- IO.popen("/usr/bin/nproc --all", &:read).to_i
95
- elsif File.executable?("/usr/bin/hwprefs")
96
- IO.popen("/usr/bin/hwprefs thread_count", &:read).to_i
97
- elsif File.executable?("/usr/sbin/psrinfo")
98
- IO.popen("/usr/sbin/psrinfo", &:read).scan(/^.*on-*line/).size
99
- elsif File.executable?("/usr/sbin/ioscan")
100
- IO.popen("/usr/sbin/ioscan -kC processor", &:read).scan(/^.*processor/).size
101
- elsif File.executable?("/usr/sbin/pmcycles")
102
- IO.popen("/usr/sbin/pmcycles -m", &:read).count("\n")
103
- elsif File.executable?("/usr/sbin/lsdev")
104
- IO.popen("/usr/sbin/lsdev -Cc processor -S 1", &:read).count("\n")
105
- elsif File.executable?("/usr/sbin/sysconf") and os_name =~ /irix/i
106
- IO.popen("/usr/sbin/sysconf NPROC_ONLN", &:read).to_i
107
- elsif File.executable?("/usr/sbin/sysctl")
108
- IO.popen("/usr/sbin/sysctl -n hw.ncpu", &:read).to_i
109
- elsif File.executable?("/sbin/sysctl")
110
- IO.popen("/sbin/sysctl -n hw.ncpu", &:read).to_i
111
- else
112
- # TODO (pitr-ch 05-Nov-2016): warn about failures
113
- 1
114
- end
83
+ Etc.nprocessors
115
84
  end
116
- rescue
117
- return 1
118
85
  end
119
86
 
120
87
  def compute_physical_processor_count
121
88
  ppc = case RbConfig::CONFIG["target_os"]
122
- when /darwin1/
89
+ when /darwin\d\d/
123
90
  IO.popen("/usr/sbin/sysctl -n hw.physicalcpu", &:read).to_i
124
91
  when /linux/
125
92
  cores = {} # unique physical ID / core ID combinations
@@ -1,3 +1,3 @@
1
1
  module Concurrent
2
- VERSION = '1.1.8'
2
+ VERSION = '1.1.10'
3
3
  end
@@ -1 +1,5 @@
1
- require_relative "./concurrent"
1
+ # This file is here so that there is a file with the same name as the gem that
2
+ # can be required by Bundler.require. Applications should normally
3
+ # require 'concurrent'.
4
+
5
+ require_relative "concurrent"
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: concurrent-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.8
4
+ version: 1.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jerry D'Antonio
8
8
  - Petr Chalupa
9
9
  - The Ruby Concurrency Team
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-01-20 00:00:00.000000000 Z
13
+ date: 2022-03-22 00:00:00.000000000 Z
14
14
  dependencies: []
15
15
  description: |
16
16
  Modern concurrency tools including agents, futures, promises, thread pools, actors, supervisors, and more.
@@ -79,6 +79,7 @@ files:
79
79
  - lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb
80
80
  - lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb
81
81
  - lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb
82
+ - lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb
82
83
  - lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb
83
84
  - lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb
84
85
  - lib/concurrent-ruby/concurrent/concern/deprecation.rb
@@ -169,7 +170,7 @@ licenses:
169
170
  metadata:
170
171
  source_code_uri: https://github.com/ruby-concurrency/concurrent-ruby
171
172
  changelog_uri: https://github.com/ruby-concurrency/concurrent-ruby/blob/master/CHANGELOG.md
172
- post_install_message:
173
+ post_install_message:
173
174
  rdoc_options: []
174
175
  require_paths:
175
176
  - lib/concurrent-ruby
@@ -177,15 +178,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
177
178
  requirements:
178
179
  - - ">="
179
180
  - !ruby/object:Gem::Version
180
- version: 1.9.3
181
+ version: '2.2'
181
182
  required_rubygems_version: !ruby/object:Gem::Requirement
182
183
  requirements:
183
184
  - - ">="
184
185
  - !ruby/object:Gem::Version
185
186
  version: '0'
186
187
  requirements: []
187
- rubygems_version: 3.2.3
188
- signing_key:
188
+ rubygems_version: 3.3.4
189
+ signing_key:
189
190
  specification_version: 4
190
191
  summary: Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell,
191
192
  F#, C#, Java, and classic concurrency patterns.