concurrent-ruby 1.2.2 → 1.3.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1cad803df2c0fe187f3208dce2972feaa94daefcbd3749770abe3abfc0642fe9
4
- data.tar.gz: 216b0196496fde70f53cc82b83cd593ec5267a53dcac9a312f254ae627f7761e
3
+ metadata.gz: 01c9677c137013ec86d98778a4aa6a9e69bca9b0ae29e923a37254c9cdc515fe
4
+ data.tar.gz: 3be169b6d0a11914f85e4a0e1221cd5c122bd59035abe9718892e1a3b4bc690b
5
5
  SHA512:
6
- metadata.gz: 605762fd9c26a5a783dcb834f9db5d818ba2b52431b382a7abd33aaddfcc0df8c5005abf0e1a7ebacf3aced9ebb61ee7080fd59050805422f4fc5593925ae935
7
- data.tar.gz: ae916f03459f583497ab268aa82cc79d24dcddb2c51a86abf86313ad77faf975d10d22048ca03179c6583832fc0e25f3f3c1618de0668f9a2774486d7e15e41c
6
+ metadata.gz: 89544dfc5575906cac0f5c57ce5348b944a70a6f77154fb70d0f185b9cc79344a5bb5147a7cf22808e071b4213c80c94e3036b98a2f4102018daf8ba16492db8
7
+ data.tar.gz: f084a5a9aa8c6e2ad305fe360f1e8e3b264ad0b45f7add6c04561ff4945cbf0b7c30b2c0d6801be46bc61b3f22f60975e8397973a321268bbf302f4bcb65ab24
data/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  ## Current
2
2
 
3
+ ## Release v1.3.4 (10 August 2024)
4
+
5
+ * (#1060) Fix bug with return value of `Concurrent.available_processor_count` when `cpu.cfs_quota_us` is -1.
6
+ * (#1058) Add `Concurrent.cpu_shares` that is cgroups aware.
7
+
8
+ ## Release v1.3.3 (9 June 2024)
9
+
10
+ * (#1053) Improve the speed of `Concurrent.physical_processor_count` on Windows.
11
+
12
+ ## Release v1.3.2, edge v0.7.1 (7 June 2024)
13
+
14
+ concurrent-ruby:
15
+
16
+ * (#1051) Remove dependency on `win32ole`.
17
+
18
+ concurrent-ruby-edge:
19
+
20
+ * (#1052) Fix dependency on `concurrent-ruby` to allow the latest release.
21
+
22
+ ## Release v1.3.1 (29 May 2024)
23
+
24
+ * Release 1.3.0 was broken when pushed to RubyGems. 1.3.1 is a packaging fix.
25
+
26
+ ## Release v1.3.0 (28 May 2024)
27
+
28
+ * (#1042) Align Java Executor Service behavior for `shuttingdown?`, `shutdown?`
29
+ * (#1038) Add `Concurrent.available_processor_count` that is cgroups aware.
30
+
31
+ ## Release v1.2.3 (16 Jan 2024)
32
+
33
+ * See [the GitHub release](https://github.com/ruby-concurrency/concurrent-ruby/releases/tag/v1.2.3) for details.
34
+
3
35
  ## Release v1.2.2 (24 Feb 2023)
4
36
 
5
37
  * (#993) Fix arguments passed to `Concurrent::Map`'s `default_proc`.
data/Gemfile CHANGED
@@ -1,18 +1,18 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- require File.join(File.dirname(__FILE__), 'lib/concurrent-ruby/concurrent/version')
4
- require File.join(File.dirname(__FILE__ ), 'lib/concurrent-ruby-edge/concurrent/edge/version')
3
+ version = File.read("#{__dir__}/lib/concurrent-ruby/concurrent/version.rb")[/'(.+)'/, 1] or raise
4
+ edge_version = File.read("#{__dir__}/lib/concurrent-ruby-edge/concurrent/edge/version.rb")[/'(.+)'/, 1] or raise
5
5
 
6
6
  no_path = ENV['NO_PATH']
7
7
  options = no_path ? {} : { path: '.' }
8
8
 
9
- gem 'concurrent-ruby', Concurrent::VERSION, options
10
- gem 'concurrent-ruby-edge', Concurrent::EDGE_VERSION, options
11
- gem 'concurrent-ruby-ext', Concurrent::VERSION, options.merge(platform: :mri)
9
+ gem 'concurrent-ruby', version, options
10
+ gem 'concurrent-ruby-edge', edge_version, options
11
+ gem 'concurrent-ruby-ext', version, options.merge(platform: :mri)
12
12
 
13
13
  group :development do
14
14
  gem 'rake', '~> 13.0'
15
- gem 'rake-compiler', '~> 1.0', '>= 1.0.7'
15
+ gem 'rake-compiler', '~> 1.0', '>= 1.0.7', '!= 1.2.4'
16
16
  gem 'rake-compiler-dock', '~> 1.0'
17
17
  gem 'pry', '~> 0.11', platforms: :mri
18
18
  end
data/README.md CHANGED
@@ -375,6 +375,8 @@ best practice is to depend on `concurrent-ruby` and let users to decide if they
375
375
  * [Benoit Daloze](https://github.com/eregon)
376
376
  * [Matthew Draper](https://github.com/matthewd)
377
377
  * [Rafael França](https://github.com/rafaelfranca)
378
+ * [Charles Oliver Nutter](https://github.com/headius)
379
+ * [Ben Sheldon](https://github.com/bensheldon)
378
380
  * [Samuel Williams](https://github.com/ioquatix)
379
381
 
380
382
  ### Special Thanks to
data/Rakefile CHANGED
@@ -1,6 +1,5 @@
1
- require_relative 'lib/concurrent-ruby/concurrent/version'
2
- require_relative 'lib/concurrent-ruby-edge/concurrent/edge/version'
3
- require_relative 'lib/concurrent-ruby/concurrent/utility/engine'
1
+ version = File.read("#{__dir__}/lib/concurrent-ruby/concurrent/version.rb")[/'(.+)'/, 1] or raise
2
+ edge_version = File.read("#{__dir__}/lib/concurrent-ruby-edge/concurrent/edge/version.rb")[/'(.+)'/, 1] or raise
4
3
 
5
4
  core_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby.gemspec')
6
5
  ext_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-ext.gemspec')
@@ -8,14 +7,14 @@ edge_gemspec = Gem::Specification.load File.join(__dir__, 'concurrent-ruby-edge.
8
7
 
9
8
  require 'rake/javaextensiontask'
10
9
 
11
- ENV['JRUBY_HOME'] = ENV['CONCURRENT_JRUBY_HOME'] if ENV['CONCURRENT_JRUBY_HOME'] && !Concurrent.on_jruby?
10
+ ENV['JRUBY_HOME'] = ENV['CONCURRENT_JRUBY_HOME'] if ENV['CONCURRENT_JRUBY_HOME'] && RUBY_ENGINE != 'jruby'
12
11
 
13
12
  Rake::JavaExtensionTask.new('concurrent_ruby', core_gemspec) do |ext|
14
13
  ext.ext_dir = 'ext/concurrent-ruby'
15
14
  ext.lib_dir = 'lib/concurrent-ruby/concurrent'
16
15
  end
17
16
 
18
- unless Concurrent.on_jruby? || Concurrent.on_truffleruby?
17
+ if RUBY_ENGINE == 'ruby'
19
18
  require 'rake/extensiontask'
20
19
 
21
20
  Rake::ExtensionTask.new('concurrent_ruby_ext', ext_gemspec) do |ext|
@@ -28,6 +27,10 @@ unless Concurrent.on_jruby? || Concurrent.on_truffleruby?
28
27
  end
29
28
  end
30
29
 
30
+ def which?(executable)
31
+ !`which #{executable} 2>/dev/null`.empty?
32
+ end
33
+
31
34
  require 'rake_compiler_dock'
32
35
  namespace :repackage do
33
36
  desc '* with Windows fat distributions'
@@ -42,12 +45,19 @@ namespace :repackage do
42
45
  Rake::Task['lib/concurrent-ruby/concurrent/concurrent_ruby.jar'].invoke
43
46
 
44
47
  # build all gem files
48
+ rack_compiler_dock_kwargs = {}
49
+ if which?('podman') and (!which?('docker') || `docker --version`.include?('podman'))
50
+ # podman and only podman available, so RakeCompilerDock will use podman, otherwise it uses docker
51
+ rack_compiler_dock_kwargs = {
52
+ options: ['--privileged'], # otherwise the directory in the image is empty
53
+ runas: false
54
+ }
55
+ end
45
56
  %w[x86-mingw32 x64-mingw32].each do |plat|
46
57
  RakeCompilerDock.sh(
47
58
  "bundle install --local && bundle exec rake native:#{plat} gem --trace",
48
59
  platform: plat,
49
- options: ['--privileged'], # otherwise the directory in the image is empty
50
- runas: false)
60
+ **rack_compiler_dock_kwargs)
51
61
  end
52
62
  end
53
63
  end
@@ -57,7 +67,7 @@ require 'rubygems'
57
67
  require 'rubygems/package_task'
58
68
 
59
69
  Gem::PackageTask.new(core_gemspec) {} if core_gemspec
60
- Gem::PackageTask.new(ext_gemspec) {} if ext_gemspec && !Concurrent.on_jruby?
70
+ Gem::PackageTask.new(ext_gemspec) {} if ext_gemspec && RUBY_ENGINE != 'jruby'
61
71
  Gem::PackageTask.new(edge_gemspec) {} if edge_gemspec
62
72
 
63
73
  CLEAN.include(
@@ -85,9 +95,9 @@ begin
85
95
  task :installed do
86
96
  Bundler.with_original_env do
87
97
  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"
98
+ sh "gem install pkg/concurrent-ruby-#{version}.gem"
99
+ sh "gem install pkg/concurrent-ruby-ext-#{version}.gem" if RUBY_ENGINE == 'ruby'
100
+ sh "gem install pkg/concurrent-ruby-edge-#{edge_version}.gem"
91
101
  ENV['NO_PATH'] = 'true'
92
102
  sh 'bundle update'
93
103
  sh 'bundle exec rake spec:ci'
@@ -117,7 +127,7 @@ rescue LoadError => e
117
127
  puts 'RSpec is not installed, skipping test task definitions: ' + e.message
118
128
  end
119
129
 
120
- current_yard_version_name = Concurrent::VERSION
130
+ current_yard_version_name = version
121
131
 
122
132
  begin
123
133
  require 'yard'
@@ -221,6 +231,8 @@ namespace :release do
221
231
  # Depends on environment of @pitr-ch
222
232
 
223
233
  task :checks do
234
+ raise '$CONCURRENT_JRUBY_HOME must be set' unless ENV['CONCURRENT_JRUBY_HOME']
235
+
224
236
  Dir.chdir(__dir__) do
225
237
  sh 'test -z "$(git status --porcelain)"' do |ok, res|
226
238
  unless ok
@@ -251,15 +263,19 @@ namespace :release do
251
263
 
252
264
  desc '* test actual installed gems instead of cloned repository on MRI and JRuby'
253
265
  task :test do
266
+ raise '$CONCURRENT_JRUBY_HOME must be set' unless ENV['CONCURRENT_JRUBY_HOME']
267
+
254
268
  Dir.chdir(__dir__) do
255
269
  puts "Testing with the installed gem"
256
270
 
257
271
  Bundler.with_original_env do
258
272
  sh 'ruby -v'
273
+ sh 'bundle install'
259
274
  sh 'bundle exec rake spec:installed'
260
275
 
261
- env = { "PATH" => "#{ENV['CONCURRENT_JRUBY_HOME']}/bin:#{ENV['PATH']}" }
276
+ env = { "PATH" => "#{ENV.fetch('CONCURRENT_JRUBY_HOME')}/bin:#{ENV['PATH']}" }
262
277
  sh env, 'ruby -v'
278
+ sh env, 'bundle install'
263
279
  sh env, 'bundle exec rake spec:installed'
264
280
  end
265
281
 
@@ -271,8 +287,8 @@ namespace :release do
271
287
  task :publish => ['publish:ask', 'publish:tag', 'publish:rubygems', 'publish:post_steps']
272
288
 
273
289
  namespace :publish do
274
- publish_base = true
275
- publish_edge = false
290
+ publish_base = nil
291
+ publish_edge = nil
276
292
 
277
293
  task :ask do
278
294
  begin
@@ -280,8 +296,15 @@ namespace :release do
280
296
  input = STDIN.gets.strip.downcase
281
297
  end until %w(y n).include?(input)
282
298
  exit 1 if input == 'n'
299
+
300
+ begin
301
+ STDOUT.puts 'Do you want to publish `concurrent-ruby`? (y/n)'
302
+ input = STDIN.gets.strip.downcase
303
+ end until %w(y n).include?(input)
304
+ publish_base = input == 'y'
305
+
283
306
  begin
284
- STDOUT.puts 'It will publish `concurrent-ruby`. Do you want to publish `concurrent-ruby-edge`? (y/n)'
307
+ STDOUT.puts 'Do you want to publish `concurrent-ruby-edge`? (y/n)'
285
308
  input = STDIN.gets.strip.downcase
286
309
  end until %w(y n).include?(input)
287
310
  publish_edge = input == 'y'
@@ -290,21 +313,21 @@ namespace :release do
290
313
  desc '** tag HEAD with current version and push to github'
291
314
  task :tag => :ask do
292
315
  Dir.chdir(__dir__) do
293
- sh "git tag v#{Concurrent::VERSION}" if publish_base
294
- sh "git push origin v#{Concurrent::VERSION}" if publish_base
295
- sh "git tag edge-v#{Concurrent::EDGE_VERSION}" if publish_edge
296
- sh "git push origin edge-v#{Concurrent::EDGE_VERSION}" if publish_edge
316
+ sh "git tag v#{version}" if publish_base
317
+ sh "git push origin v#{version}" if publish_base
318
+ sh "git tag edge-v#{edge_version}" if publish_edge
319
+ sh "git push origin edge-v#{edge_version}" if publish_edge
297
320
  end
298
321
  end
299
322
 
300
323
  desc '** push all *.gem files to rubygems'
301
324
  task :rubygems => :ask do
302
325
  Dir.chdir(__dir__) do
303
- sh "gem push pkg/concurrent-ruby-#{Concurrent::VERSION}.gem" if publish_base
304
- sh "gem push pkg/concurrent-ruby-edge-#{Concurrent::EDGE_VERSION}.gem" if publish_edge
305
- sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}.gem" if publish_base
306
- sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}-x64-mingw32.gem" if publish_base
307
- sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}-x86-mingw32.gem" if publish_base
326
+ sh "gem push pkg/concurrent-ruby-#{version}.gem" if publish_base
327
+ sh "gem push pkg/concurrent-ruby-edge-#{edge_version}.gem" if publish_edge
328
+ sh "gem push pkg/concurrent-ruby-ext-#{version}.gem" if publish_base
329
+ sh "gem push pkg/concurrent-ruby-ext-#{version}-x64-mingw32.gem" if publish_base
330
+ sh "gem push pkg/concurrent-ruby-ext-#{version}-x86-mingw32.gem" if publish_base
308
331
  end
309
332
  end
310
333
 
@@ -21,9 +21,9 @@ module Concurrent
21
21
  # @!macro internal_implementation_note
22
22
  ArrayImplementation = case
23
23
  when Concurrent.on_cruby?
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.
24
+ # Array is not fully thread-safe on CRuby, see
25
+ # https://github.com/ruby-concurrency/concurrent-ruby/issues/929
26
+ # So we will need to add synchronization here
27
27
  ::Array
28
28
 
29
29
  when Concurrent.on_jruby?
@@ -8,74 +8,77 @@ module Concurrent
8
8
  # @!visibility private
9
9
  class SynchronizedMapBackend < NonConcurrentMapBackend
10
10
 
11
- require 'mutex_m'
12
- include Mutex_m
13
- # WARNING: Mutex_m is a non-reentrant lock, so the synchronized methods are
14
- # not allowed to call each other.
11
+ def initialize(*args, &block)
12
+ super
13
+
14
+ # WARNING: Mutex is a non-reentrant lock, so the synchronized methods are
15
+ # not allowed to call each other.
16
+ @mutex = Mutex.new
17
+ end
15
18
 
16
19
  def [](key)
17
- synchronize { super }
20
+ @mutex.synchronize { super }
18
21
  end
19
22
 
20
23
  def []=(key, value)
21
- synchronize { super }
24
+ @mutex.synchronize { super }
22
25
  end
23
26
 
24
27
  def compute_if_absent(key)
25
- synchronize { super }
28
+ @mutex.synchronize { super }
26
29
  end
27
30
 
28
31
  def compute_if_present(key)
29
- synchronize { super }
32
+ @mutex.synchronize { super }
30
33
  end
31
34
 
32
35
  def compute(key)
33
- synchronize { super }
36
+ @mutex.synchronize { super }
34
37
  end
35
38
 
36
39
  def merge_pair(key, value)
37
- synchronize { super }
40
+ @mutex.synchronize { super }
38
41
  end
39
42
 
40
43
  def replace_pair(key, old_value, new_value)
41
- synchronize { super }
44
+ @mutex.synchronize { super }
42
45
  end
43
46
 
44
47
  def replace_if_exists(key, new_value)
45
- synchronize { super }
48
+ @mutex.synchronize { super }
46
49
  end
47
50
 
48
51
  def get_and_set(key, value)
49
- synchronize { super }
52
+ @mutex.synchronize { super }
50
53
  end
51
54
 
52
55
  def key?(key)
53
- synchronize { super }
56
+ @mutex.synchronize { super }
54
57
  end
55
58
 
56
59
  def delete(key)
57
- synchronize { super }
60
+ @mutex.synchronize { super }
58
61
  end
59
62
 
60
63
  def delete_pair(key, value)
61
- synchronize { super }
64
+ @mutex.synchronize { super }
62
65
  end
63
66
 
64
67
  def clear
65
- synchronize { super }
68
+ @mutex.synchronize { super }
66
69
  end
67
70
 
68
71
  def size
69
- synchronize { super }
72
+ @mutex.synchronize { super }
70
73
  end
71
74
 
72
75
  def get_or_default(key, default_value)
73
- synchronize { super }
76
+ @mutex.synchronize { super }
74
77
  end
75
78
 
76
79
  private
77
80
  def dupped_backend
78
- synchronize { super }
81
+ @mutex.synchronize { super }
79
82
  end
80
83
  end
81
84
  end
@@ -39,6 +39,10 @@ module Concurrent
39
39
  # The number of tasks that have been completed by the pool since construction.
40
40
  # @return [Integer] The number of tasks that have been completed by the pool since construction.
41
41
 
42
+ # @!macro thread_pool_executor_method_active_count
43
+ # The number of threads that are actively executing tasks.
44
+ # @return [Integer] The number of threads that are actively executing tasks.
45
+
42
46
  # @!macro thread_pool_executor_attr_reader_idletime
43
47
  # The number of seconds that a thread may be idle before being reclaimed.
44
48
  # @return [Integer] The number of seconds that a thread may be idle before being reclaimed.
@@ -57,15 +57,11 @@ if Concurrent.on_jruby?
57
57
  end
58
58
 
59
59
  def ns_shuttingdown?
60
- if @executor.respond_to? :isTerminating
61
- @executor.isTerminating
62
- else
63
- false
64
- end
60
+ @executor.isShutdown && !@executor.isTerminated
65
61
  end
66
62
 
67
63
  def ns_shutdown?
68
- @executor.isShutdown || @executor.isTerminated
64
+ @executor.isTerminated
69
65
  end
70
66
 
71
67
  class Job
@@ -88,10 +84,11 @@ if Concurrent.on_jruby?
88
84
 
89
85
  def initialize(daemonize = true)
90
86
  @daemonize = daemonize
87
+ @java_thread_factory = java.util.concurrent.Executors.defaultThreadFactory
91
88
  end
92
89
 
93
90
  def newThread(runnable)
94
- thread = java.util.concurrent.Executors.defaultThreadFactory().newThread(runnable)
91
+ thread = @java_thread_factory.newThread(runnable)
95
92
  thread.setDaemon(@daemonize)
96
93
  return thread
97
94
  end
@@ -73,6 +73,11 @@ if Concurrent.on_jruby?
73
73
  @executor.getCompletedTaskCount
74
74
  end
75
75
 
76
+ # @!macro thread_pool_executor_method_active_count
77
+ def active_count
78
+ @executor.getActiveCount
79
+ end
80
+
76
81
  # @!macro thread_pool_executor_attr_reader_idletime
77
82
  def idletime
78
83
  @executor.getKeepAliveTime(java.util.concurrent.TimeUnit::SECONDS)
@@ -61,6 +61,13 @@ module Concurrent
61
61
  synchronize { @completed_task_count }
62
62
  end
63
63
 
64
+ # @!macro thread_pool_executor_method_active_count
65
+ def active_count
66
+ synchronize do
67
+ @pool.length - @ready.length
68
+ end
69
+ end
70
+
64
71
  # @!macro executor_service_method_can_overflow_question
65
72
  def can_overflow?
66
73
  synchronize { ns_limited_queue? }
@@ -3,7 +3,7 @@ require 'concurrent/atomic/event'
3
3
  require 'concurrent/collection/non_concurrent_priority_queue'
4
4
  require 'concurrent/executor/executor_service'
5
5
  require 'concurrent/executor/single_thread_executor'
6
-
6
+ require 'concurrent/errors'
7
7
  require 'concurrent/options'
8
8
 
9
9
  module Concurrent
@@ -162,7 +162,11 @@ module Concurrent
162
162
  # queue now must have the same pop time, or a closer one, as
163
163
  # when we peeked).
164
164
  task = synchronize { @queue.pop }
165
- task.executor.post { task.process_task }
165
+ begin
166
+ task.executor.post { task.process_task }
167
+ rescue RejectedExecutionError
168
+ # ignore and continue
169
+ end
166
170
  else
167
171
  @condition.wait([diff, 60].min)
168
172
  end
@@ -15,9 +15,11 @@ module Concurrent
15
15
  # @!macro internal_implementation_note
16
16
  HashImplementation = case
17
17
  when Concurrent.on_cruby?
18
- # Hash is thread-safe in practice because CRuby runs
19
- # threads one at a time and does not do context
20
- # switching during the execution of C functions.
18
+ # Hash is not fully thread-safe on CRuby, see
19
+ # https://bugs.ruby-lang.org/issues/19237
20
+ # https://github.com/ruby/ruby/commit/ffd52412ab
21
+ # https://github.com/ruby-concurrency/concurrent-ruby/issues/929
22
+ # So we will need to add synchronization here (similar to Concurrent::Map).
21
23
  ::Hash
22
24
 
23
25
  when Concurrent.on_jruby?
@@ -20,8 +20,8 @@ module Concurrent
20
20
  require 'concurrent/collection/map/truffleruby_map_backend'
21
21
  TruffleRubyMapBackend
22
22
  else
23
- require 'concurrent/collection/map/atomic_reference_map_backend'
24
- AtomicReferenceMapBackend
23
+ require 'concurrent/collection/map/synchronized_map_backend'
24
+ SynchronizedMapBackend
25
25
  end
26
26
  else
27
27
  warn 'Concurrent::Map: unsupported Ruby engine, using a fully synchronized Concurrent::Map implementation'