concurrent-ruby 1.1.10 → 1.2.0
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 +11 -1
- data/Gemfile +0 -1
- data/README.md +21 -20
- data/Rakefile +46 -57
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +10 -25
- data/lib/concurrent-ruby/concurrent/agent.rb +2 -1
- data/lib/concurrent-ruby/concurrent/array.rb +0 -10
- data/lib/concurrent-ruby/concurrent/atom.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +5 -4
- data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +5 -4
- data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +3 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +81 -151
- data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/event.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb +109 -0
- data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +1 -0
- data/lib/concurrent-ruby/concurrent/atomic/locals.rb +188 -0
- data/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb +28 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +11 -5
- data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +11 -5
- data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +2 -1
- data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +5 -3
- data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +6 -9
- data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +96 -89
- data/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb +37 -0
- data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +15 -4
- data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +1 -1
- data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +1 -1
- data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +2 -0
- data/lib/concurrent-ruby/concurrent/concern/logging.rb +86 -2
- data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent-ruby/concurrent/configuration.rb +4 -87
- data/lib/concurrent-ruby/concurrent/delay.rb +2 -2
- data/lib/concurrent-ruby/concurrent/errors.rb +5 -0
- data/lib/concurrent-ruby/concurrent/exchanger.rb +1 -0
- data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +1 -1
- data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +2 -2
- data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +1 -1
- data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +1 -1
- data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +4 -1
- data/lib/concurrent-ruby/concurrent/hash.rb +0 -9
- data/lib/concurrent-ruby/concurrent/immutable_struct.rb +1 -1
- data/lib/concurrent-ruby/concurrent/ivar.rb +2 -1
- data/lib/concurrent-ruby/concurrent/map.rb +9 -8
- data/lib/concurrent-ruby/concurrent/maybe.rb +1 -1
- data/lib/concurrent-ruby/concurrent/mutable_struct.rb +1 -1
- data/lib/concurrent-ruby/concurrent/mvar.rb +1 -1
- data/lib/concurrent-ruby/concurrent/promise.rb +1 -1
- data/lib/concurrent-ruby/concurrent/promises.rb +7 -6
- data/lib/concurrent-ruby/concurrent/re_include.rb +2 -0
- data/lib/concurrent-ruby/concurrent/scheduled_task.rb +1 -1
- data/lib/concurrent-ruby/concurrent/set.rb +0 -10
- data/lib/concurrent-ruby/concurrent/settable_struct.rb +2 -2
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +5 -1
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +1 -3
- data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +2 -0
- data/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb +29 -0
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +3 -1
- data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +2 -0
- data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +5 -2
- data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +6 -5
- data/lib/concurrent-ruby/concurrent/synchronization/object.rb +12 -44
- data/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb +36 -0
- data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +77 -12
- data/lib/concurrent-ruby/concurrent/synchronization.rb +1 -18
- data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +36 -39
- data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +2 -39
- data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +1 -37
- data/lib/concurrent-ruby/concurrent/tuple.rb +1 -5
- data/lib/concurrent-ruby/concurrent/tvar.rb +2 -1
- data/lib/concurrent-ruby/concurrent/utility/engine.rb +5 -16
- data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +3 -74
- data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +8 -10
- data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +1 -0
- data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +34 -54
- data/lib/concurrent-ruby/concurrent/version.rb +1 -1
- metadata +13 -15
- data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +0 -66
- data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +0 -37
- data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +0 -181
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +0 -45
- data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +0 -44
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +0 -71
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +0 -49
- data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +0 -47
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'thread'
|
2
2
|
require 'concurrent/atomic/atomic_reference'
|
3
|
+
require 'concurrent/atomic/atomic_fixnum'
|
3
4
|
require 'concurrent/errors'
|
4
|
-
require 'concurrent/synchronization'
|
5
|
-
require 'concurrent/
|
5
|
+
require 'concurrent/synchronization/object'
|
6
|
+
require 'concurrent/synchronization/lock'
|
7
|
+
require 'concurrent/atomic/lock_local_var'
|
6
8
|
|
7
9
|
module Concurrent
|
8
10
|
|
@@ -109,7 +111,7 @@ module Concurrent
|
|
109
111
|
@Counter = AtomicFixnum.new(0) # single integer which represents lock state
|
110
112
|
@ReadQueue = Synchronization::Lock.new # used to queue waiting readers
|
111
113
|
@WriteQueue = Synchronization::Lock.new # used to queue waiting writers
|
112
|
-
@HeldCount =
|
114
|
+
@HeldCount = LockLocalVar.new(0) # indicates # of R & W locks held by this thread
|
113
115
|
end
|
114
116
|
|
115
117
|
# Execute a block operation within a read lock.
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'concurrent/atomic/mutex_semaphore'
|
2
|
-
require 'concurrent/synchronization'
|
3
2
|
|
4
3
|
module Concurrent
|
5
4
|
|
@@ -11,7 +10,7 @@ module Concurrent
|
|
11
10
|
#
|
12
11
|
# @param [Fixnum] count the initial count
|
13
12
|
#
|
14
|
-
# @raise [ArgumentError] if `count` is not an integer
|
13
|
+
# @raise [ArgumentError] if `count` is not an integer
|
15
14
|
|
16
15
|
# @!macro semaphore_method_acquire
|
17
16
|
#
|
@@ -21,8 +20,7 @@ module Concurrent
|
|
21
20
|
#
|
22
21
|
# @param [Fixnum] permits Number of permits to acquire
|
23
22
|
#
|
24
|
-
# @raise [ArgumentError] if `permits` is not an integer or is less than
|
25
|
-
# one
|
23
|
+
# @raise [ArgumentError] if `permits` is not an integer or is less than zero
|
26
24
|
#
|
27
25
|
# @return [nil, BasicObject] Without a block, `nil` is returned. If a block
|
28
26
|
# is given, its return value is returned.
|
@@ -52,8 +50,7 @@ module Concurrent
|
|
52
50
|
# @param [Fixnum] timeout the number of seconds to wait for the counter
|
53
51
|
# or `nil` to return immediately
|
54
52
|
#
|
55
|
-
# @raise [ArgumentError] if `permits` is not an integer or is less than
|
56
|
-
# one
|
53
|
+
# @raise [ArgumentError] if `permits` is not an integer or is less than zero
|
57
54
|
#
|
58
55
|
# @return [true, false, nil, BasicObject] `false` if no permits are
|
59
56
|
# available, `true` when acquired a permit. If a block is given, the
|
@@ -66,7 +63,7 @@ module Concurrent
|
|
66
63
|
#
|
67
64
|
# @param [Fixnum] permits Number of permits to return to the semaphore.
|
68
65
|
#
|
69
|
-
# @raise [ArgumentError] if `permits` is not a number or is less than
|
66
|
+
# @raise [ArgumentError] if `permits` is not a number or is less than zero
|
70
67
|
#
|
71
68
|
# @return [nil]
|
72
69
|
|
@@ -96,8 +93,8 @@ module Concurrent
|
|
96
93
|
|
97
94
|
# @!visibility private
|
98
95
|
# @!macro internal_implementation_note
|
99
|
-
SemaphoreImplementation =
|
100
|
-
|
96
|
+
SemaphoreImplementation = if Concurrent.on_jruby?
|
97
|
+
require 'concurrent/utility/native_extension_loader'
|
101
98
|
JavaSemaphore
|
102
99
|
else
|
103
100
|
MutexSemaphore
|
@@ -1,104 +1,111 @@
|
|
1
|
-
require 'concurrent/
|
2
|
-
|
3
|
-
require 'concurrent/atomic/java_thread_local_var'
|
1
|
+
require 'concurrent/constants'
|
2
|
+
require_relative 'locals'
|
4
3
|
|
5
4
|
module Concurrent
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
#
|
6
|
+
# A `ThreadLocalVar` is a variable where the value is different for each thread.
|
7
|
+
# Each variable may have a default value, but when you modify the variable only
|
8
|
+
# the current thread will ever see that change.
|
9
|
+
#
|
10
|
+
# This is similar to Ruby's built-in thread-local variables (`Thread#thread_variable_get`),
|
11
|
+
# but with these major advantages:
|
12
|
+
# * `ThreadLocalVar` has its own identity, it doesn't need a Symbol.
|
13
|
+
# * Each Ruby's built-in thread-local variable leaks some memory forever (it's a Symbol held forever on the thread),
|
14
|
+
# so it's only OK to create a small amount of them.
|
15
|
+
# `ThreadLocalVar` has no such issue and it is fine to create many of them.
|
16
|
+
# * Ruby's built-in thread-local variables leak forever the value set on each thread (unless set to nil explicitly).
|
17
|
+
# `ThreadLocalVar` automatically removes the mapping for each thread once the `ThreadLocalVar` instance is GC'd.
|
18
|
+
#
|
19
|
+
# @!macro thread_safe_variable_comparison
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# v = ThreadLocalVar.new(14)
|
23
|
+
# v.value #=> 14
|
24
|
+
# v.value = 2
|
25
|
+
# v.value #=> 2
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# v = ThreadLocalVar.new(14)
|
29
|
+
#
|
30
|
+
# t1 = Thread.new do
|
31
|
+
# v.value #=> 14
|
32
|
+
# v.value = 1
|
33
|
+
# v.value #=> 1
|
34
|
+
# end
|
10
35
|
#
|
11
|
-
#
|
36
|
+
# t2 = Thread.new do
|
37
|
+
# v.value #=> 14
|
38
|
+
# v.value = 2
|
39
|
+
# v.value #=> 2
|
40
|
+
# end
|
12
41
|
#
|
13
|
-
#
|
14
|
-
|
15
|
-
|
42
|
+
# v.value #=> 14
|
43
|
+
class ThreadLocalVar
|
44
|
+
LOCALS = ThreadLocals.new
|
16
45
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
46
|
+
# Creates a thread local variable.
|
47
|
+
#
|
48
|
+
# @param [Object] default the default value when otherwise unset
|
49
|
+
# @param [Proc] default_block Optional block that gets called to obtain the
|
50
|
+
# default value for each thread
|
51
|
+
def initialize(default = nil, &default_block)
|
52
|
+
if default && block_given?
|
53
|
+
raise ArgumentError, "Cannot use both value and block as default value"
|
54
|
+
end
|
22
55
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
56
|
+
if block_given?
|
57
|
+
@default_block = default_block
|
58
|
+
@default = nil
|
59
|
+
else
|
60
|
+
@default_block = nil
|
61
|
+
@default = default
|
62
|
+
end
|
29
63
|
|
30
|
-
|
31
|
-
|
32
|
-
# Bind the given value to thread local storage during
|
33
|
-
# execution of the given block.
|
34
|
-
#
|
35
|
-
# @param [Object] value the value to bind
|
36
|
-
# @yield the operation to be performed with the bound variable
|
37
|
-
# @return [Object] the value
|
64
|
+
@index = LOCALS.next_index(self)
|
65
|
+
end
|
38
66
|
|
67
|
+
# Returns the value in the current thread's copy of this thread-local variable.
|
68
|
+
#
|
69
|
+
# @return [Object] the current value
|
70
|
+
def value
|
71
|
+
LOCALS.fetch(@index) { default }
|
72
|
+
end
|
39
73
|
|
40
|
-
|
74
|
+
# Sets the current thread's copy of this thread-local variable to the specified value.
|
75
|
+
#
|
76
|
+
# @param [Object] value the value to set
|
77
|
+
# @return [Object] the new value
|
78
|
+
def value=(value)
|
79
|
+
LOCALS.set(@index, value)
|
80
|
+
end
|
41
81
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
82
|
+
# Bind the given value to thread local storage during
|
83
|
+
# execution of the given block.
|
84
|
+
#
|
85
|
+
# @param [Object] value the value to bind
|
86
|
+
# @yield the operation to be performed with the bound variable
|
87
|
+
# @return [Object] the value
|
88
|
+
def bind(value)
|
89
|
+
if block_given?
|
90
|
+
old_value = self.value
|
91
|
+
self.value = value
|
92
|
+
begin
|
93
|
+
yield
|
94
|
+
ensure
|
95
|
+
self.value = old_value
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
55
99
|
|
56
|
-
|
100
|
+
protected
|
57
101
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
private_constant :ThreadLocalVarImplementation
|
67
|
-
|
68
|
-
# @!macro thread_local_var
|
69
|
-
#
|
70
|
-
# A `ThreadLocalVar` is a variable where the value is different for each thread.
|
71
|
-
# Each variable may have a default value, but when you modify the variable only
|
72
|
-
# the current thread will ever see that change.
|
73
|
-
#
|
74
|
-
# @!macro thread_safe_variable_comparison
|
75
|
-
#
|
76
|
-
# @example
|
77
|
-
# v = ThreadLocalVar.new(14)
|
78
|
-
# v.value #=> 14
|
79
|
-
# v.value = 2
|
80
|
-
# v.value #=> 2
|
81
|
-
#
|
82
|
-
# @example
|
83
|
-
# v = ThreadLocalVar.new(14)
|
84
|
-
#
|
85
|
-
# t1 = Thread.new do
|
86
|
-
# v.value #=> 14
|
87
|
-
# v.value = 1
|
88
|
-
# v.value #=> 1
|
89
|
-
# end
|
90
|
-
#
|
91
|
-
# t2 = Thread.new do
|
92
|
-
# v.value #=> 14
|
93
|
-
# v.value = 2
|
94
|
-
# v.value #=> 2
|
95
|
-
# end
|
96
|
-
#
|
97
|
-
# v.value #=> 14
|
98
|
-
#
|
99
|
-
# @see https://docs.oracle.com/javase/7/docs/api/java/lang/ThreadLocal.html Java ThreadLocal
|
100
|
-
#
|
101
|
-
# @!macro thread_local_var_public_api
|
102
|
-
class ThreadLocalVar < ThreadLocalVarImplementation
|
102
|
+
# @!visibility private
|
103
|
+
def default
|
104
|
+
if @default_block
|
105
|
+
self.value = @default_block.call
|
106
|
+
else
|
107
|
+
@default
|
108
|
+
end
|
109
|
+
end
|
103
110
|
end
|
104
111
|
end
|
@@ -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,8 +1,13 @@
|
|
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
|
9
|
+
class MutexAtomicReference
|
10
|
+
extend Concurrent::Synchronization::SafeInitialization
|
6
11
|
include AtomicDirectUpdate
|
7
12
|
include AtomicNumericCompareAndSetWrapper
|
8
13
|
alias_method :compare_and_swap, :compare_and_set
|
@@ -10,7 +15,8 @@ module Concurrent
|
|
10
15
|
# @!macro atomic_reference_method_initialize
|
11
16
|
def initialize(value = nil)
|
12
17
|
super()
|
13
|
-
|
18
|
+
@Lock = ::Mutex.new
|
19
|
+
@value = value
|
14
20
|
end
|
15
21
|
|
16
22
|
# @!macro atomic_reference_method_get
|
@@ -49,8 +55,13 @@ module Concurrent
|
|
49
55
|
|
50
56
|
protected
|
51
57
|
|
52
|
-
|
53
|
-
|
58
|
+
# @!visibility private
|
59
|
+
def synchronize
|
60
|
+
if @Lock.owned?
|
61
|
+
yield
|
62
|
+
else
|
63
|
+
@Lock.synchronize { yield }
|
64
|
+
end
|
54
65
|
end
|
55
66
|
end
|
56
67
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'logger'
|
2
|
+
require 'concurrent/atomic/atomic_reference'
|
2
3
|
|
3
4
|
module Concurrent
|
4
5
|
module Concern
|
@@ -15,8 +16,6 @@ module Concurrent
|
|
15
16
|
# @param [String, nil] message when nil block is used to generate the message
|
16
17
|
# @yieldreturn [String] a message
|
17
18
|
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
19
|
logger = if defined?(@logger) && @logger
|
21
20
|
@logger
|
22
21
|
else
|
@@ -30,3 +29,88 @@ module Concurrent
|
|
30
29
|
end
|
31
30
|
end
|
32
31
|
end
|
32
|
+
|
33
|
+
module Concurrent
|
34
|
+
extend Concern::Logging
|
35
|
+
|
36
|
+
# @return [Logger] Logger with provided level and output.
|
37
|
+
def self.create_simple_logger(level = Logger::FATAL, output = $stderr)
|
38
|
+
# TODO (pitr-ch 24-Dec-2016): figure out why it had to be replaced, stdlogger was deadlocking
|
39
|
+
lambda do |severity, progname, message = nil, &block|
|
40
|
+
return false if severity < level
|
41
|
+
|
42
|
+
message = block ? block.call : message
|
43
|
+
formatted_message = case message
|
44
|
+
when String
|
45
|
+
message
|
46
|
+
when Exception
|
47
|
+
format "%s (%s)\n%s",
|
48
|
+
message.message, message.class, (message.backtrace || []).join("\n")
|
49
|
+
else
|
50
|
+
message.inspect
|
51
|
+
end
|
52
|
+
|
53
|
+
output.print format "[%s] %5s -- %s: %s\n",
|
54
|
+
Time.now.strftime('%Y-%m-%d %H:%M:%S.%L'),
|
55
|
+
Logger::SEV_LABEL[severity],
|
56
|
+
progname,
|
57
|
+
formatted_message
|
58
|
+
true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Use logger created by #create_simple_logger to log concurrent-ruby messages.
|
63
|
+
def self.use_simple_logger(level = Logger::FATAL, output = $stderr)
|
64
|
+
Concurrent.global_logger = create_simple_logger level, output
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return [Logger] Logger with provided level and output.
|
68
|
+
# @deprecated
|
69
|
+
def self.create_stdlib_logger(level = Logger::FATAL, output = $stderr)
|
70
|
+
logger = Logger.new(output)
|
71
|
+
logger.level = level
|
72
|
+
logger.formatter = lambda do |severity, datetime, progname, msg|
|
73
|
+
formatted_message = case msg
|
74
|
+
when String
|
75
|
+
msg
|
76
|
+
when Exception
|
77
|
+
format "%s (%s)\n%s",
|
78
|
+
msg.message, msg.class, (msg.backtrace || []).join("\n")
|
79
|
+
else
|
80
|
+
msg.inspect
|
81
|
+
end
|
82
|
+
format "[%s] %5s -- %s: %s\n",
|
83
|
+
datetime.strftime('%Y-%m-%d %H:%M:%S.%L'),
|
84
|
+
severity,
|
85
|
+
progname,
|
86
|
+
formatted_message
|
87
|
+
end
|
88
|
+
|
89
|
+
lambda do |loglevel, progname, message = nil, &block|
|
90
|
+
logger.add loglevel, message, progname, &block
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Use logger created by #create_stdlib_logger to log concurrent-ruby messages.
|
95
|
+
# @deprecated
|
96
|
+
def self.use_stdlib_logger(level = Logger::FATAL, output = $stderr)
|
97
|
+
Concurrent.global_logger = create_stdlib_logger level, output
|
98
|
+
end
|
99
|
+
|
100
|
+
# TODO (pitr-ch 27-Dec-2016): remove deadlocking stdlib_logger methods
|
101
|
+
|
102
|
+
# Suppresses all output when used for logging.
|
103
|
+
NULL_LOGGER = lambda { |level, progname, message = nil, &block| }
|
104
|
+
|
105
|
+
# @!visibility private
|
106
|
+
GLOBAL_LOGGER = AtomicReference.new(create_simple_logger(Logger::WARN))
|
107
|
+
private_constant :GLOBAL_LOGGER
|
108
|
+
|
109
|
+
def self.global_logger
|
110
|
+
GLOBAL_LOGGER.value
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.global_logger=(value)
|
114
|
+
GLOBAL_LOGGER.value = value
|
115
|
+
end
|
116
|
+
end
|
Binary file
|
@@ -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
|
|
@@ -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
|
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
|