concurrent-ruby 1.1.10 → 1.3.7

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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +76 -3
  3. data/Gemfile +6 -7
  4. data/README.md +28 -23
  5. data/Rakefile +90 -76
  6. data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +3 -38
  7. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +10 -25
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +1 -1
  9. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +1 -1
  10. data/lib/concurrent-ruby/concurrent/agent.rb +4 -3
  11. data/lib/concurrent-ruby/concurrent/array.rb +3 -13
  12. data/lib/concurrent-ruby/concurrent/async.rb +1 -1
  13. data/lib/concurrent-ruby/concurrent/atom.rb +2 -2
  14. data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +5 -4
  15. data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +5 -4
  16. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +3 -0
  17. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +90 -153
  18. data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +1 -1
  19. data/lib/concurrent-ruby/concurrent/atomic/event.rb +1 -1
  20. data/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb +109 -0
  21. data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +1 -0
  22. data/lib/concurrent-ruby/concurrent/atomic/locals.rb +189 -0
  23. data/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb +29 -0
  24. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +11 -5
  25. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +11 -5
  26. data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +1 -1
  27. data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +1 -1
  28. data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +17 -3
  29. data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +13 -4
  30. data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +6 -9
  31. data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +96 -89
  32. data/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb +37 -0
  33. data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +16 -6
  34. data/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb +9 -1
  35. data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +1 -1
  36. data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +1 -1
  37. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +2 -0
  38. data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +2 -2
  39. data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +16 -8
  40. data/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb +23 -20
  41. data/lib/concurrent-ruby/concurrent/collection/ruby_timeout_queue.rb +55 -0
  42. data/lib/concurrent-ruby/concurrent/collection/timeout_queue.rb +18 -0
  43. data/lib/concurrent-ruby/concurrent/concern/logging.rb +95 -6
  44. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  45. data/lib/concurrent-ruby/concurrent/configuration.rb +4 -87
  46. data/lib/concurrent-ruby/concurrent/delay.rb +3 -3
  47. data/lib/concurrent-ruby/concurrent/errors.rb +5 -0
  48. data/lib/concurrent-ruby/concurrent/exchanger.rb +1 -0
  49. data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +1 -1
  50. data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +6 -4
  51. data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +7 -9
  52. data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +7 -0
  53. data/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb +2 -0
  54. data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +61 -31
  55. data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +1 -1
  56. data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +1 -1
  57. data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +4 -1
  58. data/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb +1 -1
  59. data/lib/concurrent-ruby/concurrent/executor/timer_set.rb +10 -3
  60. data/lib/concurrent-ruby/concurrent/executors.rb +0 -1
  61. data/lib/concurrent-ruby/concurrent/hash.rb +5 -12
  62. data/lib/concurrent-ruby/concurrent/immutable_struct.rb +1 -1
  63. data/lib/concurrent-ruby/concurrent/ivar.rb +2 -1
  64. data/lib/concurrent-ruby/concurrent/map.rb +43 -39
  65. data/lib/concurrent-ruby/concurrent/maybe.rb +1 -1
  66. data/lib/concurrent-ruby/concurrent/mutable_struct.rb +1 -1
  67. data/lib/concurrent-ruby/concurrent/mvar.rb +5 -5
  68. data/lib/concurrent-ruby/concurrent/promise.rb +3 -3
  69. data/lib/concurrent-ruby/concurrent/promises.rb +40 -29
  70. data/lib/concurrent-ruby/concurrent/re_include.rb +2 -0
  71. data/lib/concurrent-ruby/concurrent/scheduled_task.rb +2 -2
  72. data/lib/concurrent-ruby/concurrent/set.rb +0 -10
  73. data/lib/concurrent-ruby/concurrent/settable_struct.rb +2 -2
  74. data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +5 -1
  75. data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +1 -3
  76. data/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb +1 -1
  77. data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +2 -0
  78. data/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb +29 -0
  79. data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +3 -1
  80. data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +2 -0
  81. data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +5 -2
  82. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +6 -5
  83. data/lib/concurrent-ruby/concurrent/synchronization/object.rb +13 -45
  84. data/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb +36 -0
  85. data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +77 -12
  86. data/lib/concurrent-ruby/concurrent/synchronization.rb +1 -18
  87. data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +36 -39
  88. data/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb +1 -1
  89. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +1 -37
  90. data/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb +1 -1
  91. data/lib/concurrent-ruby/concurrent/timer_task.rb +65 -10
  92. data/lib/concurrent-ruby/concurrent/tuple.rb +1 -5
  93. data/lib/concurrent-ruby/concurrent/tvar.rb +2 -1
  94. data/lib/concurrent-ruby/concurrent/utility/engine.rb +5 -16
  95. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +3 -74
  96. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +8 -10
  97. data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +1 -0
  98. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +148 -58
  99. data/lib/concurrent-ruby/concurrent/version.rb +1 -1
  100. metadata +14 -19
  101. data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +0 -66
  102. data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +0 -37
  103. data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +0 -181
  104. data/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb +0 -927
  105. data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +0 -45
  106. data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +0 -44
  107. data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +0 -71
  108. data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +0 -49
  109. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +0 -47
  110. data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +0 -118
@@ -0,0 +1,37 @@
1
+ require 'concurrent/errors'
2
+
3
+ module Concurrent
4
+
5
+ # Define update methods that use direct paths
6
+ #
7
+ # @!visibility private
8
+ # @!macro internal_implementation_note
9
+ module AtomicDirectUpdate
10
+ def update
11
+ true until compare_and_set(old_value = get, new_value = yield(old_value))
12
+ new_value
13
+ end
14
+
15
+ def try_update
16
+ old_value = get
17
+ new_value = yield old_value
18
+
19
+ return unless compare_and_set old_value, new_value
20
+
21
+ new_value
22
+ end
23
+
24
+ def try_update!
25
+ old_value = get
26
+ new_value = yield old_value
27
+ unless compare_and_set(old_value, new_value)
28
+ if $VERBOSE
29
+ raise ConcurrentUpdateError, "Update failed"
30
+ else
31
+ raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE
32
+ end
33
+ end
34
+ new_value
35
+ end
36
+ end
37
+ end
@@ -1,16 +1,21 @@
1
+ require 'concurrent/atomic_reference/atomic_direct_update'
2
+ require 'concurrent/atomic_reference/numeric_cas_wrapper'
3
+ require 'concurrent/synchronization/safe_initialization'
4
+
1
5
  module Concurrent
2
6
 
3
7
  # @!visibility private
4
8
  # @!macro internal_implementation_note
5
- class MutexAtomicReference < Synchronization::LockableObject
9
+ class MutexAtomicReference
10
+ extend Concurrent::Synchronization::SafeInitialization
6
11
  include AtomicDirectUpdate
7
12
  include AtomicNumericCompareAndSetWrapper
8
- alias_method :compare_and_swap, :compare_and_set
9
13
 
10
14
  # @!macro atomic_reference_method_initialize
11
15
  def initialize(value = nil)
12
16
  super()
13
- synchronize { ns_initialize(value) }
17
+ @Lock = ::Mutex.new
18
+ @value = value
14
19
  end
15
20
 
16
21
  # @!macro atomic_reference_method_get
@@ -36,7 +41,7 @@ module Concurrent
36
41
  alias_method :swap, :get_and_set
37
42
 
38
43
  # @!macro atomic_reference_method_compare_and_set
39
- def _compare_and_set(old_value, new_value)
44
+ private def _compare_and_set(old_value, new_value)
40
45
  synchronize do
41
46
  if @value.equal? old_value
42
47
  @value = new_value
@@ -49,8 +54,13 @@ module Concurrent
49
54
 
50
55
  protected
51
56
 
52
- def ns_initialize(value)
53
- @value = value
57
+ # @!visibility private
58
+ def synchronize
59
+ if @Lock.owned?
60
+ yield
61
+ else
62
+ @Lock.synchronize { yield }
63
+ end
54
64
  end
55
65
  end
56
66
  end
@@ -9,12 +9,18 @@ module Concurrent
9
9
  # @!macro atomic_reference_method_compare_and_set
10
10
  def compare_and_set(old_value, new_value)
11
11
  if old_value.kind_of? Numeric
12
+ # NaN is never == to itself; match it explicitly so #update can terminate.
13
+ expected_nan = old_value.respond_to?(:nan?) && old_value.nan?
12
14
  while true
13
15
  old = get
14
16
 
15
17
  return false unless old.kind_of? Numeric
16
18
 
17
- return false unless old == old_value
19
+ if expected_nan
20
+ return false unless old.respond_to?(:nan?) && old.nan?
21
+ else
22
+ return false unless old == old_value
23
+ end
18
24
 
19
25
  result = _compare_and_set(old, new_value)
20
26
  return result if result
@@ -24,5 +30,7 @@ module Concurrent
24
30
  end
25
31
  end
26
32
 
33
+ alias_method :compare_and_swap, :compare_and_set
34
+
27
35
  end
28
36
  end
@@ -1,4 +1,4 @@
1
- require 'concurrent/synchronization'
1
+ require 'concurrent/synchronization/lockable_object'
2
2
 
3
3
  module Concurrent
4
4
  module Collection
@@ -1,4 +1,4 @@
1
- require 'concurrent/synchronization'
1
+ require 'concurrent/synchronization/lockable_object'
2
2
 
3
3
  module Concurrent
4
4
  module Collection
@@ -1,3 +1,5 @@
1
+ require 'concurrent/synchronization/object'
2
+
1
3
  module Concurrent
2
4
 
3
5
  # @!macro warn.edge
@@ -9,8 +9,8 @@ module Concurrent
9
9
  # @!visibility private
10
10
  class MriMapBackend < NonConcurrentMapBackend
11
11
 
12
- def initialize(options = nil)
13
- super(options)
12
+ def initialize(options = nil, &default_proc)
13
+ super(options, &default_proc)
14
14
  @write_lock = Mutex.new
15
15
  end
16
16
 
@@ -12,8 +12,10 @@ module Concurrent
12
12
  # directly without calling each other. This is important because of the
13
13
  # SynchronizedMapBackend which uses a non-reentrant mutex for performance
14
14
  # reasons.
15
- def initialize(options = nil)
16
- @backend = {}
15
+ def initialize(options = nil, &default_proc)
16
+ validate_options_hash!(options) if options.kind_of?(::Hash)
17
+ set_backend(default_proc)
18
+ @default_proc = default_proc
17
19
  end
18
20
 
19
21
  def [](key)
@@ -55,7 +57,7 @@ module Concurrent
55
57
  end
56
58
 
57
59
  def compute(key)
58
- store_computed_value(key, yield(@backend[key]))
60
+ store_computed_value(key, yield(get_or_default(key, nil)))
59
61
  end
60
62
 
61
63
  def merge_pair(key, value)
@@ -67,7 +69,7 @@ module Concurrent
67
69
  end
68
70
 
69
71
  def get_and_set(key, value)
70
- stored_value = @backend[key]
72
+ stored_value = get_or_default(key, nil)
71
73
  @backend[key] = value
72
74
  stored_value
73
75
  end
@@ -109,13 +111,19 @@ module Concurrent
109
111
  @backend.fetch(key, default_value)
110
112
  end
111
113
 
112
- alias_method :_get, :[]
113
- alias_method :_set, :[]=
114
- private :_get, :_set
115
114
  private
115
+
116
+ def set_backend(default_proc)
117
+ if default_proc
118
+ @backend = ::Hash.new { |_h, key| default_proc.call(self, key) }
119
+ else
120
+ @backend = {}
121
+ end
122
+ end
123
+
116
124
  def initialize_copy(other)
117
125
  super
118
- @backend = {}
126
+ set_backend(@default_proc)
119
127
  self
120
128
  end
121
129
 
@@ -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
@@ -0,0 +1,55 @@
1
+ module Concurrent
2
+ module Collection
3
+ # @!visibility private
4
+ # @!macro ruby_timeout_queue
5
+ class RubyTimeoutQueue < ::Queue
6
+ def initialize(*args)
7
+ if RUBY_VERSION >= '3.2'
8
+ raise "#{self.class.name} is not needed on Ruby 3.2 or later, use ::Queue instead"
9
+ end
10
+
11
+ super(*args)
12
+
13
+ @mutex = Mutex.new
14
+ @cond_var = ConditionVariable.new
15
+ end
16
+
17
+ def push(obj)
18
+ @mutex.synchronize do
19
+ super(obj)
20
+ @cond_var.signal
21
+ end
22
+ end
23
+ alias_method :enq, :push
24
+ alias_method :<<, :push
25
+
26
+ def pop(non_block = false, timeout: nil)
27
+ if non_block && timeout
28
+ raise ArgumentError, "can't set a timeout if non_block is enabled"
29
+ end
30
+
31
+ if non_block
32
+ super(true)
33
+ elsif timeout
34
+ @mutex.synchronize do
35
+ deadline = Concurrent.monotonic_time + timeout
36
+ while (now = Concurrent.monotonic_time) < deadline && empty?
37
+ @cond_var.wait(@mutex, deadline - now)
38
+ end
39
+ begin
40
+ return super(true)
41
+ rescue ThreadError
42
+ # still empty
43
+ nil
44
+ end
45
+ end
46
+ else
47
+ super(false)
48
+ end
49
+ end
50
+ alias_method :deq, :pop
51
+ alias_method :shift, :pop
52
+ end
53
+ private_constant :RubyTimeoutQueue
54
+ end
55
+ end
@@ -0,0 +1,18 @@
1
+ module Concurrent
2
+ module Collection
3
+ # @!visibility private
4
+ # @!macro internal_implementation_note
5
+ TimeoutQueueImplementation = if RUBY_VERSION >= '3.2'
6
+ ::Queue
7
+ else
8
+ require 'concurrent/collection/ruby_timeout_queue'
9
+ RubyTimeoutQueue
10
+ end
11
+ private_constant :TimeoutQueueImplementation
12
+
13
+ # @!visibility private
14
+ # @!macro timeout_queue
15
+ class TimeoutQueue < TimeoutQueueImplementation
16
+ end
17
+ end
18
+ end
@@ -1,4 +1,4 @@
1
- require 'logger'
1
+ require 'concurrent/atomic/atomic_reference'
2
2
 
3
3
  module Concurrent
4
4
  module Concern
@@ -7,16 +7,16 @@ module Concurrent
7
7
  #
8
8
  # @!visibility private
9
9
  module Logging
10
- 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
11
13
 
12
14
  # Logs through {Concurrent.global_logger}, it can be overridden by setting @logger
13
- # @param [Integer] level one of Logger::Severity constants
15
+ # @param [Integer] level one of Concurrent::Concern::Logging constants
14
16
  # @param [String] progname e.g. a path of an Actor
15
17
  # @param [String, nil] message when nil block is used to generate the message
16
18
  # @yieldreturn [String] a message
17
19
  def log(level, progname, message = nil, &block)
18
- #NOTE: Cannot require 'concurrent/configuration' above due to circular references.
19
- # Assume that the gem has been initialized if we've gotten this far.
20
20
  logger = if defined?(@logger) && @logger
21
21
  @logger
22
22
  else
@@ -24,9 +24,98 @@ module Concurrent
24
24
  end
25
25
  logger.call level, progname, message, &block
26
26
  rescue => error
27
- $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" +
28
28
  "#{error.message} (#{error.class})\n#{error.backtrace.join "\n"}"
29
29
  end
30
30
  end
31
31
  end
32
32
  end
33
+
34
+ module Concurrent
35
+ extend Concern::Logging
36
+
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
+
41
+ # TODO (pitr-ch 24-Dec-2016): figure out why it had to be replaced, stdlogger was deadlocking
42
+ lambda do |severity, progname, message = nil, &block|
43
+ return false if severity < level
44
+
45
+ message = block ? block.call : message
46
+ formatted_message = case message
47
+ when String
48
+ message
49
+ when Exception
50
+ format "%s (%s)\n%s",
51
+ message.message, message.class, (message.backtrace || []).join("\n")
52
+ else
53
+ message.inspect
54
+ end
55
+
56
+ output.print format "[%s] %5s -- %s: %s\n",
57
+ Time.now.strftime('%Y-%m-%d %H:%M:%S.%L'),
58
+ Concern::Logging::SEV_LABEL[severity],
59
+ progname,
60
+ formatted_message
61
+ true
62
+ end
63
+ end
64
+
65
+ # Use logger created by #create_simple_logger to log concurrent-ruby messages.
66
+ def self.use_simple_logger(level = :FATAL, output = $stderr)
67
+ Concurrent.global_logger = create_simple_logger level, output
68
+ end
69
+
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+.
72
+ # @deprecated
73
+ def self.create_stdlib_logger(level = :FATAL, output = $stderr)
74
+ require 'logger'
75
+ logger = Logger.new(output)
76
+ logger.level = level
77
+ logger.formatter = lambda do |severity, datetime, progname, msg|
78
+ formatted_message = case msg
79
+ when String
80
+ msg
81
+ when Exception
82
+ format "%s (%s)\n%s",
83
+ msg.message, msg.class, (msg.backtrace || []).join("\n")
84
+ else
85
+ msg.inspect
86
+ end
87
+ format "[%s] %5s -- %s: %s\n",
88
+ datetime.strftime('%Y-%m-%d %H:%M:%S.%L'),
89
+ severity,
90
+ progname,
91
+ formatted_message
92
+ end
93
+
94
+ lambda do |loglevel, progname, message = nil, &block|
95
+ logger.add loglevel, message, progname, &block
96
+ end
97
+ end
98
+
99
+ # Use logger created by #create_stdlib_logger to log concurrent-ruby messages.
100
+ # @deprecated
101
+ def self.use_stdlib_logger(level = :FATAL, output = $stderr)
102
+ Concurrent.global_logger = create_stdlib_logger level, output
103
+ end
104
+
105
+ # TODO (pitr-ch 27-Dec-2016): remove deadlocking stdlib_logger methods
106
+
107
+ # Suppresses all output when used for logging.
108
+ NULL_LOGGER = lambda { |level, progname, message = nil, &block| }
109
+
110
+ # @!visibility private
111
+ GLOBAL_LOGGER = AtomicReference.new(create_simple_logger(:WARN))
112
+ private_constant :GLOBAL_LOGGER
113
+
114
+ def self.global_logger
115
+ GLOBAL_LOGGER.value
116
+ end
117
+
118
+ def self.global_logger=(value)
119
+ GLOBAL_LOGGER.value = value
120
+ end
121
+ end
@@ -1,102 +1,19 @@
1
1
  require 'thread'
2
2
  require 'concurrent/delay'
3
3
  require 'concurrent/errors'
4
- require 'concurrent/atomic/atomic_reference'
5
- require 'concurrent/concern/logging'
6
4
  require 'concurrent/concern/deprecation'
7
5
  require 'concurrent/executor/immediate_executor'
6
+ require 'concurrent/executor/fixed_thread_pool'
8
7
  require 'concurrent/executor/cached_thread_pool'
9
8
  require 'concurrent/utility/processor_counter'
10
9
 
11
10
  module Concurrent
12
- extend Concern::Logging
13
11
  extend Concern::Deprecation
14
12
 
15
13
  autoload :Options, 'concurrent/options'
16
14
  autoload :TimerSet, 'concurrent/executor/timer_set'
17
15
  autoload :ThreadPoolExecutor, 'concurrent/executor/thread_pool_executor'
18
16
 
19
- # @return [Logger] Logger with provided level and output.
20
- def self.create_simple_logger(level = Logger::FATAL, output = $stderr)
21
- # TODO (pitr-ch 24-Dec-2016): figure out why it had to be replaced, stdlogger was deadlocking
22
- lambda do |severity, progname, message = nil, &block|
23
- return false if severity < level
24
-
25
- message = block ? block.call : message
26
- formatted_message = case message
27
- when String
28
- message
29
- when Exception
30
- format "%s (%s)\n%s",
31
- message.message, message.class, (message.backtrace || []).join("\n")
32
- else
33
- message.inspect
34
- end
35
-
36
- output.print format "[%s] %5s -- %s: %s\n",
37
- Time.now.strftime('%Y-%m-%d %H:%M:%S.%L'),
38
- Logger::SEV_LABEL[severity],
39
- progname,
40
- formatted_message
41
- true
42
- end
43
- end
44
-
45
- # Use logger created by #create_simple_logger to log concurrent-ruby messages.
46
- def self.use_simple_logger(level = Logger::FATAL, output = $stderr)
47
- Concurrent.global_logger = create_simple_logger level, output
48
- end
49
-
50
- # @return [Logger] Logger with provided level and output.
51
- # @deprecated
52
- def self.create_stdlib_logger(level = Logger::FATAL, output = $stderr)
53
- logger = Logger.new(output)
54
- logger.level = level
55
- logger.formatter = lambda do |severity, datetime, progname, msg|
56
- formatted_message = case msg
57
- when String
58
- msg
59
- when Exception
60
- format "%s (%s)\n%s",
61
- msg.message, msg.class, (msg.backtrace || []).join("\n")
62
- else
63
- msg.inspect
64
- end
65
- format "[%s] %5s -- %s: %s\n",
66
- datetime.strftime('%Y-%m-%d %H:%M:%S.%L'),
67
- severity,
68
- progname,
69
- formatted_message
70
- end
71
-
72
- lambda do |loglevel, progname, message = nil, &block|
73
- logger.add loglevel, message, progname, &block
74
- end
75
- end
76
-
77
- # Use logger created by #create_stdlib_logger to log concurrent-ruby messages.
78
- # @deprecated
79
- def self.use_stdlib_logger(level = Logger::FATAL, output = $stderr)
80
- Concurrent.global_logger = create_stdlib_logger level, output
81
- end
82
-
83
- # TODO (pitr-ch 27-Dec-2016): remove deadlocking stdlib_logger methods
84
-
85
- # Suppresses all output when used for logging.
86
- NULL_LOGGER = lambda { |level, progname, message = nil, &block| }
87
-
88
- # @!visibility private
89
- GLOBAL_LOGGER = AtomicReference.new(create_simple_logger(Logger::WARN))
90
- private_constant :GLOBAL_LOGGER
91
-
92
- def self.global_logger
93
- GLOBAL_LOGGER.value
94
- end
95
-
96
- def self.global_logger=(value)
97
- GLOBAL_LOGGER.value = value
98
- end
99
-
100
17
  # @!visibility private
101
18
  GLOBAL_FAST_EXECUTOR = Delay.new { Concurrent.new_fast_executor }
102
19
  private_constant :GLOBAL_FAST_EXECUTOR
@@ -136,14 +53,14 @@ module Concurrent
136
53
  #
137
54
  # @return [ThreadPoolExecutor] the thread pool
138
55
  def self.global_fast_executor
139
- GLOBAL_FAST_EXECUTOR.value
56
+ GLOBAL_FAST_EXECUTOR.value!
140
57
  end
141
58
 
142
59
  # Global thread pool optimized for long, blocking (IO) *tasks*.
143
60
  #
144
61
  # @return [ThreadPoolExecutor] the thread pool
145
62
  def self.global_io_executor
146
- GLOBAL_IO_EXECUTOR.value
63
+ GLOBAL_IO_EXECUTOR.value!
147
64
  end
148
65
 
149
66
  def self.global_immediate_executor
@@ -154,7 +71,7 @@ module Concurrent
154
71
  #
155
72
  # @return [Concurrent::TimerSet] the thread pool
156
73
  def self.global_timer_set
157
- GLOBAL_TIMER_SET.value
74
+ GLOBAL_TIMER_SET.value!
158
75
  end
159
76
 
160
77
  # General access point to global executors.
@@ -1,7 +1,7 @@
1
1
  require 'thread'
2
2
  require 'concurrent/concern/obligation'
3
3
  require 'concurrent/executor/immediate_executor'
4
- require 'concurrent/synchronization'
4
+ require 'concurrent/synchronization/lockable_object'
5
5
 
6
6
  module Concurrent
7
7
 
@@ -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
@@ -67,7 +67,7 @@ module Concurrent
67
67
 
68
68
  # Return the value this object represents after applying the options
69
69
  # specified by the `#set_deref_options` method. If the delayed operation
70
- # raised an exception this method will return nil. The execption object
70
+ # raised an exception this method will return nil. The exception object
71
71
  # can be accessed via the `#reason` method.
72
72
  #
73
73
  # @param [Numeric] timeout the maximum number of seconds to wait
@@ -66,4 +66,9 @@ module Concurrent
66
66
  end
67
67
  end
68
68
 
69
+ # @!macro internal_implementation_note
70
+ class ConcurrentUpdateError < ThreadError
71
+ # frozen pre-allocated backtrace to speed ConcurrentUpdateError
72
+ CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze
73
+ end
69
74
  end
@@ -289,6 +289,7 @@ module Concurrent
289
289
  end
290
290
 
291
291
  if Concurrent.on_jruby?
292
+ require 'concurrent/utility/native_extension_loader'
292
293
 
293
294
  # @!macro internal_implementation_note
294
295
  # @!visibility private