concurrent-ruby 1.3.3 → 1.3.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ca6244c1124d507f5422c42cc9376e46cb2a46f7ad07363731ee0957c410e98
4
- data.tar.gz: 4c03cbe71e12804bf8d9b0c707895313206a9932be3e182f1674faa70568ca1f
3
+ metadata.gz: 14d5a264c6fdc7b6087131a0f0a2fc1ce661d18029440e426e094443eb359ca6
4
+ data.tar.gz: 42e7b1b8fb885aec9b7b08488c6682af2743e65ad6dcd731f8c86d34f7768981
5
5
  SHA512:
6
- metadata.gz: ceaab8640927f5f0bf5ecde7727705248d5dd5d0a5fe9b4baa8b8d259a2cf0ef9a5e8d636cfacd47588d358ea8c51cd1650f0939be6e3188647553e7158d536f
7
- data.tar.gz: 216aed72a0d32b40a7e34303751d9c544594b4a51e38e9fd449f3922fcc30fd9a7549d22d7e3d1552b307806ede6c638acffdaded8cd016980a0ae0683b5495e
6
+ metadata.gz: 31b6cf4fcc533349681610e74f6261c95e5c664583014d86101578f0380a6889288b29a89314a5da59e92cd422bcd97783c34d99c3e5c21a90db0f0d3fcc57e1
7
+ data.tar.gz: 4438de87d8ec3ff1cc6d7d246821002bbb76d5a9ddd8b77ebf4a15c0449f1509d694c4f57936b1e1a69e19f32736f21518fd8e82b8cdfbb99d5e2948976c230e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  ## Current
2
2
 
3
+ ## Release v1.3.5, edge v0.7.2 (15 January 2025)
4
+
5
+ concurrent-ruby:
6
+
7
+ * (#1062) Remove dependency on logger.
8
+
9
+ concurrent-ruby-edge:
10
+
11
+ * (#1062) Remove dependency on logger.
12
+
13
+ ## Release v1.3.4 (10 August 2024)
14
+
15
+ * (#1060) Fix bug with return value of `Concurrent.available_processor_count` when `cpu.cfs_quota_us` is -1.
16
+ * (#1058) Add `Concurrent.cpu_shares` that is cgroups aware.
17
+
3
18
  ## Release v1.3.3 (9 June 2024)
4
19
 
5
20
  * (#1053) Improve the speed of `Concurrent.physical_processor_count` on Windows.
@@ -291,7 +306,7 @@ concurrent-ruby-edge:
291
306
  * Simplification of `RubySingleThreadExecutor`
292
307
  * `Async` improvements
293
308
  - Each object uses its own `SingleThreadExecutor` instead of the global thread pool.
294
- - No longers supports executor injection
309
+ - No longer supports executor injection
295
310
  - Much better documentation
296
311
  * `Atom` updates
297
312
  - No longer `Dereferenceable`
@@ -466,7 +481,7 @@ Please see the [roadmap](https://github.com/ruby-concurrency/concurrent-ruby/iss
466
481
  * Fixed bug with return value of `Concurrent::Actor::Utils::Pool#ask`
467
482
  * Fixed timing bug in `TimerTask`
468
483
  * Fixed bug when creating a `JavaThreadPoolExecutor` with minimum pool size of zero
469
- * Removed confusing warning when not using native extenstions
484
+ * Removed confusing warning when not using native extensions
470
485
  * Improved documentation
471
486
 
472
487
  ## Release v0.7.0 (13 August 2014)
data/Gemfile CHANGED
@@ -1,14 +1,14 @@
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'
data/README.md CHANGED
@@ -284,7 +284,7 @@ To use the tools in the Edge gem it must be required separately:
284
284
  require 'concurrent-edge'
285
285
  ```
286
286
 
287
- If the library does not behave as expected, `Concurrent.use_stdlib_logger(Logger::DEBUG)` could
287
+ If the library does not behave as expected, `Concurrent.use_simple_logger(:DEBUG)` could
288
288
  help to reveal the problem.
289
289
 
290
290
  ## Installation
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,16 @@ 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'
15
+ ext.source_version = '8'
16
+ ext.target_version = '8'
16
17
  end
17
18
 
18
- unless Concurrent.on_jruby? || Concurrent.on_truffleruby?
19
+ if RUBY_ENGINE == 'ruby'
19
20
  require 'rake/extensiontask'
20
21
 
21
22
  Rake::ExtensionTask.new('concurrent_ruby_ext', ext_gemspec) do |ext|
@@ -68,7 +69,7 @@ require 'rubygems'
68
69
  require 'rubygems/package_task'
69
70
 
70
71
  Gem::PackageTask.new(core_gemspec) {} if core_gemspec
71
- Gem::PackageTask.new(ext_gemspec) {} if ext_gemspec && !Concurrent.on_jruby?
72
+ Gem::PackageTask.new(ext_gemspec) {} if ext_gemspec && RUBY_ENGINE != 'jruby'
72
73
  Gem::PackageTask.new(edge_gemspec) {} if edge_gemspec
73
74
 
74
75
  CLEAN.include(
@@ -96,9 +97,9 @@ begin
96
97
  task :installed do
97
98
  Bundler.with_original_env do
98
99
  Dir.chdir(__dir__) do
99
- sh "gem install pkg/concurrent-ruby-#{Concurrent::VERSION}.gem"
100
- sh "gem install pkg/concurrent-ruby-ext-#{Concurrent::VERSION}.gem" if Concurrent.on_cruby?
101
- sh "gem install pkg/concurrent-ruby-edge-#{Concurrent::EDGE_VERSION}.gem"
100
+ sh "gem install pkg/concurrent-ruby-#{version}.gem"
101
+ sh "gem install pkg/concurrent-ruby-ext-#{version}.gem" if RUBY_ENGINE == 'ruby'
102
+ sh "gem install pkg/concurrent-ruby-edge-#{edge_version}.gem"
102
103
  ENV['NO_PATH'] = 'true'
103
104
  sh 'bundle update'
104
105
  sh 'bundle exec rake spec:ci'
@@ -128,7 +129,7 @@ rescue LoadError => e
128
129
  puts 'RSpec is not installed, skipping test task definitions: ' + e.message
129
130
  end
130
131
 
131
- current_yard_version_name = Concurrent::VERSION
132
+ current_yard_version_name = version
132
133
 
133
134
  begin
134
135
  require 'yard'
@@ -232,6 +233,8 @@ namespace :release do
232
233
  # Depends on environment of @pitr-ch
233
234
 
234
235
  task :checks do
236
+ raise '$CONCURRENT_JRUBY_HOME must be set' unless ENV['CONCURRENT_JRUBY_HOME']
237
+
235
238
  Dir.chdir(__dir__) do
236
239
  sh 'test -z "$(git status --porcelain)"' do |ok, res|
237
240
  unless ok
@@ -262,6 +265,8 @@ namespace :release do
262
265
 
263
266
  desc '* test actual installed gems instead of cloned repository on MRI and JRuby'
264
267
  task :test do
268
+ raise '$CONCURRENT_JRUBY_HOME must be set' unless ENV['CONCURRENT_JRUBY_HOME']
269
+
265
270
  Dir.chdir(__dir__) do
266
271
  puts "Testing with the installed gem"
267
272
 
@@ -310,21 +315,21 @@ namespace :release do
310
315
  desc '** tag HEAD with current version and push to github'
311
316
  task :tag => :ask do
312
317
  Dir.chdir(__dir__) do
313
- sh "git tag v#{Concurrent::VERSION}" if publish_base
314
- sh "git push origin v#{Concurrent::VERSION}" if publish_base
315
- sh "git tag edge-v#{Concurrent::EDGE_VERSION}" if publish_edge
316
- sh "git push origin edge-v#{Concurrent::EDGE_VERSION}" if publish_edge
318
+ sh "git tag v#{version}" if publish_base
319
+ sh "git push origin v#{version}" if publish_base
320
+ sh "git tag edge-v#{edge_version}" if publish_edge
321
+ sh "git push origin edge-v#{edge_version}" if publish_edge
317
322
  end
318
323
  end
319
324
 
320
325
  desc '** push all *.gem files to rubygems'
321
326
  task :rubygems => :ask do
322
327
  Dir.chdir(__dir__) do
323
- sh "gem push pkg/concurrent-ruby-#{Concurrent::VERSION}.gem" if publish_base
324
- sh "gem push pkg/concurrent-ruby-edge-#{Concurrent::EDGE_VERSION}.gem" if publish_edge
325
- sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}.gem" if publish_base
326
- sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}-x64-mingw32.gem" if publish_base
327
- sh "gem push pkg/concurrent-ruby-ext-#{Concurrent::VERSION}-x86-mingw32.gem" if publish_base
328
+ sh "gem push pkg/concurrent-ruby-#{version}.gem" if publish_base
329
+ sh "gem push pkg/concurrent-ruby-edge-#{edge_version}.gem" if publish_edge
330
+ sh "gem push pkg/concurrent-ruby-ext-#{version}.gem" if publish_base
331
+ sh "gem push pkg/concurrent-ruby-ext-#{version}-x64-mingw32.gem" if publish_base
332
+ sh "gem push pkg/concurrent-ruby-ext-#{version}-x86-mingw32.gem" if publish_base
328
333
  end
329
334
  end
330
335
 
@@ -481,7 +481,7 @@ public class ConcurrentHashMapV8<K, V>
481
481
  *
482
482
  * Maintaining API and serialization compatibility with previous
483
483
  * versions of this class introduces several oddities. Mainly: We
484
- * leave untouched but unused constructor arguments refering to
484
+ * leave untouched but unused constructor arguments referring to
485
485
  * concurrencyLevel. We accept a loadFactor constructor argument,
486
486
  * but apply it only to initial table capacity (which is the only
487
487
  * time that we can guarantee to honor it.) We also declare an
@@ -484,7 +484,7 @@ public class ConcurrentHashMapV8<K, V>
484
484
  *
485
485
  * Maintaining API and serialization compatibility with previous
486
486
  * versions of this class introduces several oddities. Mainly: We
487
- * leave untouched but unused constructor arguments refering to
487
+ * leave untouched but unused constructor arguments referring to
488
488
  * concurrencyLevel. We accept a loadFactor constructor argument,
489
489
  * but apply it only to initial table capacity (which is the only
490
490
  * time that we can guarantee to honor it.) We also declare an
@@ -371,7 +371,7 @@ module Concurrent
371
371
  # @param [Float] timeout the maximum number of seconds to wait
372
372
  # @return [Boolean] true if all actions complete before timeout
373
373
  #
374
- # @raise [Concurrent::TimeoutError] when timout is reached
374
+ # @raise [Concurrent::TimeoutError] when timeout is reached
375
375
  #
376
376
  # @!macro agent_await_warning
377
377
  def await_for!(timeout)
@@ -477,7 +477,7 @@ module Concurrent
477
477
  # @param [Array<Concurrent::Agent>] agents the Agents on which to wait
478
478
  # @return [Boolean] true if all actions complete before timeout
479
479
  #
480
- # @raise [Concurrent::TimeoutError] when timout is reached
480
+ # @raise [Concurrent::TimeoutError] when timeout is reached
481
481
  # @!macro agent_await_warning
482
482
  def await_for!(timeout, *agents)
483
483
  raise Concurrent::TimeoutError unless await_for(timeout, *agents)
@@ -218,7 +218,7 @@ module Concurrent
218
218
 
219
219
  # @!method self.new(*args, &block)
220
220
  #
221
- # Instanciate a new object and ensure proper initialization of the
221
+ # Instantiate a new object and ensure proper initialization of the
222
222
  # synchronization mechanisms.
223
223
  #
224
224
  # @param [Array<Object>] args Zero or more arguments to be passed to the
@@ -113,7 +113,7 @@ module Concurrent
113
113
  # @option opts [Proc] :validator (nil) Optional proc used to validate new
114
114
  # values. It must accept one and only one argument which will be the
115
115
  # intended new value. The validator will return true if the new value
116
- # is acceptable else return false (preferrably) or raise an exception.
116
+ # is acceptable else return false (preferably) or raise an exception.
117
117
  #
118
118
  # @!macro deref_options
119
119
  #
@@ -1,4 +1,3 @@
1
- require 'logger'
2
1
  require 'concurrent/atomic/atomic_reference'
3
2
 
4
3
  module Concurrent
@@ -8,10 +7,12 @@ module Concurrent
8
7
  #
9
8
  # @!visibility private
10
9
  module Logging
11
- include Logger::Severity
10
+ # The same as Logger::Severity but we copy it here to avoid a dependency on the logger gem just for these 7 constants
11
+ DEBUG, INFO, WARN, ERROR, FATAL, UNKNOWN = 0, 1, 2, 3, 4, 5
12
+ SEV_LABEL = %w[DEBUG INFO WARN ERROR FATAL ANY].freeze
12
13
 
13
14
  # Logs through {Concurrent.global_logger}, it can be overridden by setting @logger
14
- # @param [Integer] level one of Logger::Severity constants
15
+ # @param [Integer] level one of Concurrent::Concern::Logging constants
15
16
  # @param [String] progname e.g. a path of an Actor
16
17
  # @param [String, nil] message when nil block is used to generate the message
17
18
  # @yieldreturn [String] a message
@@ -23,7 +24,7 @@ module Concurrent
23
24
  end
24
25
  logger.call level, progname, message, &block
25
26
  rescue => error
26
- $stderr.puts "`Concurrent.configuration.logger` failed to log #{[level, progname, message, block]}\n" +
27
+ $stderr.puts "`Concurrent.global_logger` failed to log #{[level, progname, message, block]}\n" +
27
28
  "#{error.message} (#{error.class})\n#{error.backtrace.join "\n"}"
28
29
  end
29
30
  end
@@ -33,8 +34,10 @@ end
33
34
  module Concurrent
34
35
  extend Concern::Logging
35
36
 
36
- # @return [Logger] Logger with provided level and output.
37
- def self.create_simple_logger(level = Logger::FATAL, output = $stderr)
37
+ # Create a simple logger with provided level and output.
38
+ def self.create_simple_logger(level = :FATAL, output = $stderr)
39
+ level = Concern::Logging.const_get(level) unless level.is_a?(Integer)
40
+
38
41
  # TODO (pitr-ch 24-Dec-2016): figure out why it had to be replaced, stdlogger was deadlocking
39
42
  lambda do |severity, progname, message = nil, &block|
40
43
  return false if severity < level
@@ -52,7 +55,7 @@ module Concurrent
52
55
 
53
56
  output.print format "[%s] %5s -- %s: %s\n",
54
57
  Time.now.strftime('%Y-%m-%d %H:%M:%S.%L'),
55
- Logger::SEV_LABEL[severity],
58
+ Concern::Logging::SEV_LABEL[severity],
56
59
  progname,
57
60
  formatted_message
58
61
  true
@@ -60,13 +63,15 @@ module Concurrent
60
63
  end
61
64
 
62
65
  # Use logger created by #create_simple_logger to log concurrent-ruby messages.
63
- def self.use_simple_logger(level = Logger::FATAL, output = $stderr)
66
+ def self.use_simple_logger(level = :FATAL, output = $stderr)
64
67
  Concurrent.global_logger = create_simple_logger level, output
65
68
  end
66
69
 
67
- # @return [Logger] Logger with provided level and output.
70
+ # Create a stdlib logger with provided level and output.
71
+ # If you use this deprecated method you might need to add logger to your Gemfile to avoid warnings from Ruby 3.3.5+.
68
72
  # @deprecated
69
- def self.create_stdlib_logger(level = Logger::FATAL, output = $stderr)
73
+ def self.create_stdlib_logger(level = :FATAL, output = $stderr)
74
+ require 'logger'
70
75
  logger = Logger.new(output)
71
76
  logger.level = level
72
77
  logger.formatter = lambda do |severity, datetime, progname, msg|
@@ -93,7 +98,7 @@ module Concurrent
93
98
 
94
99
  # Use logger created by #create_stdlib_logger to log concurrent-ruby messages.
95
100
  # @deprecated
96
- def self.use_stdlib_logger(level = Logger::FATAL, output = $stderr)
101
+ def self.use_stdlib_logger(level = :FATAL, output = $stderr)
97
102
  Concurrent.global_logger = create_stdlib_logger level, output
98
103
  end
99
104
 
@@ -103,7 +108,7 @@ module Concurrent
103
108
  NULL_LOGGER = lambda { |level, progname, message = nil, &block| }
104
109
 
105
110
  # @!visibility private
106
- GLOBAL_LOGGER = AtomicReference.new(create_simple_logger(Logger::WARN))
111
+ GLOBAL_LOGGER = AtomicReference.new(create_simple_logger(:WARN))
107
112
  private_constant :GLOBAL_LOGGER
108
113
 
109
114
  def self.global_logger
@@ -19,7 +19,7 @@ module Concurrent
19
19
  #
20
20
  # When a `Delay` is created its state is set to `pending`. The value and
21
21
  # reason are both `nil`. The first time the `#value` method is called the
22
- # enclosed opration will be run and the calling thread will block. Other
22
+ # enclosed operation will be run and the calling thread will block. Other
23
23
  # threads attempting to call `#value` will block as well. Once the operation
24
24
  # is complete the *value* will be set to the result of the operation or the
25
25
  # *reason* will be set to the raised exception, as appropriate. All threads
@@ -83,7 +83,7 @@ module Concurrent
83
83
  #
84
84
  # This is a no-op on some pool implementation (e.g. the Java one). The Ruby
85
85
  # pool will auto-prune each time a new job is posted. You will need to call
86
- # this method explicitely in case your application post jobs in bursts (a
86
+ # this method explicitly in case your application post jobs in bursts (a
87
87
  # lot of jobs and then nothing for long periods)
88
88
 
89
89
  # @!macro thread_pool_executor_public_api
@@ -27,7 +27,7 @@ module Concurrent
27
27
  # is received. This pattern has several issues. The thread itself is highly
28
28
  # susceptible to errors during processing. Also, the thread itself must be
29
29
  # constantly monitored and restarted should it die. `SingleThreadExecutor`
30
- # encapsulates all these bahaviors. The task processor is highly resilient
30
+ # encapsulates all these behaviors. The task processor is highly resilient
31
31
  # to errors from within tasks. Also, should the thread die it will
32
32
  # automatically be restarted.
33
33
  #
@@ -148,7 +148,7 @@ module Concurrent
148
148
  if value = super # non-falsy value is an existing mapping, return it right away
149
149
  value
150
150
  # re-check is done with get_or_default(key, NULL) instead of a simple !key?(key) in order to avoid a race condition, whereby by the time the current thread gets to the key?(key) call
151
- # a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an incorrent +nil+ value
151
+ # a key => value mapping might have already been created by a different thread (key?(key) would then return true, this elsif branch wouldn't be taken and an incorrect +nil+ value
152
152
  # would be returned)
153
153
  # note: nil == value check is not technically necessary
154
154
  elsif @default_proc && nil == value && NULL == (value = get_or_default(key, NULL))
@@ -103,7 +103,7 @@ module Concurrent
103
103
  # - if parent is *rejected* the child will be *pending* (but will ultimately be *rejected*)
104
104
  #
105
105
  # Promises are executed asynchronously from the main thread. By the time a
106
- # child Promise finishes intialization it may be in a different state than its
106
+ # child Promise finishes initialization it may be in a different state than its
107
107
  # parent (by the time a child is created its parent may have completed
108
108
  # execution and changed state). Despite being asynchronous, however, the order
109
109
  # of execution of Promise objects in a chain (or tree) is strictly defined.
@@ -193,7 +193,7 @@ module Concurrent
193
193
  end
194
194
  end
195
195
 
196
- # The `delay` value given at instanciation.
196
+ # The `delay` value given at instantiation.
197
197
  #
198
198
  # @return [Float] the initial delay.
199
199
  def initial_delay
@@ -157,7 +157,7 @@ module Concurrent
157
157
  end
158
158
  end
159
159
  members.each_with_index do |member, index|
160
- clazz.send :remove_method, member if clazz.instance_methods.include? member
160
+ clazz.send :remove_method, member if clazz.instance_methods(false).include? member
161
161
  clazz.send(:define_method, member) do
162
162
  @values[index]
163
163
  end
@@ -58,7 +58,7 @@ module Concurrent
58
58
 
59
59
  # Creates methods for reading and writing to a instance variable with
60
60
  # volatile (Java) semantic as {.attr_volatile} does.
61
- # The instance variable should be accessed oly through generated methods.
61
+ # The instance variable should be accessed only through generated methods.
62
62
  # This method generates following methods: `value`, `value=(new_value) #=> new_value`,
63
63
  # `swap_value(new_value) #=> old_value`,
64
64
  # `compare_and_set_value(expected, value) #=> true || false`, `update_value(&block)`.
@@ -9,7 +9,7 @@ module Concurrent
9
9
  # @!visibility private
10
10
  module Util
11
11
 
12
- # A Ruby port of the Doug Lea's jsr166e.LondAdder class version 1.8
12
+ # A Ruby port of the Doug Lea's jsr166e.LongAdder class version 1.8
13
13
  # available in public domain.
14
14
  #
15
15
  # Original source code available here:
@@ -15,7 +15,7 @@ module Concurrent
15
15
  # Usage:
16
16
  # x = XorShiftRandom.get # uses Kernel.rand to generate an initial seed
17
17
  # while true
18
- # if (x = XorShiftRandom.xorshift).odd? # thread-localy generate a next random number
18
+ # if (x = XorShiftRandom.xorshift).odd? # thread-locally generate a next random number
19
19
  # do_something_at_random
20
20
  # end
21
21
  # end
@@ -12,6 +12,7 @@ module Concurrent
12
12
  @processor_count = Delay.new { compute_processor_count }
13
13
  @physical_processor_count = Delay.new { compute_physical_processor_count }
14
14
  @cpu_quota = Delay.new { compute_cpu_quota }
15
+ @cpu_shares = Delay.new { compute_cpu_shares }
15
16
  end
16
17
 
17
18
  def processor_count
@@ -41,6 +42,10 @@ module Concurrent
41
42
  @cpu_quota.value
42
43
  end
43
44
 
45
+ def cpu_shares
46
+ @cpu_shares.value
47
+ end
48
+
44
49
  private
45
50
 
46
51
  def compute_processor_count
@@ -78,7 +83,7 @@ module Concurrent
78
83
  # Bail out if both commands returned something unexpected
79
84
  processor_count
80
85
  else
81
- # powershell: "\nNumberOfCores\n-------------\n 4\n\n\n"
86
+ # powershell: "\nNumberOfCores\n-------------\n 4\n\n\n"
82
87
  # wmic: "NumberOfCores \n\n4 \n\n\n\n"
83
88
  result.scan(/\d+/).map(&:to_i).reduce(:+)
84
89
  end
@@ -107,12 +112,28 @@ module Concurrent
107
112
  elsif File.exist?("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us")
108
113
  # cgroups v1: https://kernel.googlesource.com/pub/scm/linux/kernel/git/glommer/memcg/+/cpu_stat/Documentation/cgroups/cpu.txt
109
114
  max = File.read("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us").to_i
110
- return nil if max == 0
115
+ # If the cpu.cfs_quota_us is -1, cgroup does not adhere to any CPU time restrictions
116
+ # https://docs.kernel.org/scheduler/sched-bwc.html#management
117
+ return nil if max <= 0
111
118
  period = File.read("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us").to_f
112
119
  max / period
113
120
  end
114
121
  end
115
122
  end
123
+
124
+ def compute_cpu_shares
125
+ if RbConfig::CONFIG["target_os"].include?("linux")
126
+ if File.exist?("/sys/fs/cgroup/cpu.weight")
127
+ # cgroups v2: https://docs.kernel.org/admin-guide/cgroup-v2.html#cpu-interface-files
128
+ # Ref: https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2254-cgroup-v2#phase-1-convert-from-cgroups-v1-settings-to-v2
129
+ weight = File.read("/sys/fs/cgroup/cpu.weight").to_f
130
+ ((((weight - 1) * 262142) / 9999) + 2) / 1024
131
+ elsif File.exist?("/sys/fs/cgroup/cpu/cpu.shares")
132
+ # cgroups v1: https://kernel.googlesource.com/pub/scm/linux/kernel/git/glommer/memcg/+/cpu_stat/Documentation/cgroups/cpu.txt
133
+ File.read("/sys/fs/cgroup/cpu/cpu.shares").to_f / 1024
134
+ end
135
+ end
136
+ end
116
137
  end
117
138
  end
118
139
 
@@ -128,8 +149,8 @@ module Concurrent
128
149
  # `java.lang.Runtime.getRuntime.availableProcessors` will be used. According
129
150
  # to the Java documentation this "value may change during a particular
130
151
  # invocation of the virtual machine... [applications] should therefore
131
- # occasionally poll this property." Subsequently the result will NOT be
132
- # memoized under JRuby.
152
+ # occasionally poll this property." We still memoize this value once under
153
+ # JRuby.
133
154
  #
134
155
  # Otherwise Ruby's Etc.nprocessors will be used.
135
156
  #
@@ -162,13 +183,14 @@ module Concurrent
162
183
  end
163
184
 
164
185
  # Number of processors cores available for process scheduling.
165
- # Returns `nil` if there is no #cpu_quota, or a `Float` if the
166
- # process is inside a cgroup with a dedicated CPU quota (typically Docker).
186
+ # This method takes in account the CPU quota if the process is inside a cgroup with a
187
+ # dedicated CPU quota (typically Docker).
188
+ # Otherwise it returns the same value as #processor_count but as a Float.
167
189
  #
168
190
  # For performance reasons the calculated value will be memoized on the first
169
191
  # call.
170
192
  #
171
- # @return [nil, Float] number of available processors
193
+ # @return [Float] number of available processors
172
194
  def self.available_processor_count
173
195
  processor_counter.available_processor_count
174
196
  end
@@ -187,4 +209,12 @@ module Concurrent
187
209
  def self.cpu_quota
188
210
  processor_counter.cpu_quota
189
211
  end
212
+
213
+ # The CPU shares requested by the process. For performance reasons the calculated
214
+ # value will be memoized on the first call.
215
+ #
216
+ # @return [Float, nil] CPU shares requested by the process, or nil if not set
217
+ def self.cpu_shares
218
+ processor_counter.cpu_shares
219
+ end
190
220
  end
@@ -1,3 +1,3 @@
1
1
  module Concurrent
2
- VERSION = '1.3.3'
2
+ VERSION = '1.3.5'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: concurrent-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.3
4
+ version: 1.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jerry D'Antonio
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2024-06-09 00:00:00.000000000 Z
13
+ date: 2025-01-15 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.