concurrent-ruby 1.1.8 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -0
  3. data/Gemfile +2 -8
  4. data/README.md +49 -28
  5. data/Rakefile +66 -81
  6. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +0 -0
  7. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +52 -22
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +10 -25
  9. data/lib/concurrent-ruby/concurrent/agent.rb +2 -1
  10. data/lib/concurrent-ruby/concurrent/array.rb +0 -10
  11. data/lib/concurrent-ruby/concurrent/async.rb +1 -0
  12. data/lib/concurrent-ruby/concurrent/atom.rb +1 -1
  13. data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +5 -4
  14. data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +5 -4
  15. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +3 -0
  16. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +82 -151
  17. data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +1 -1
  18. data/lib/concurrent-ruby/concurrent/atomic/event.rb +3 -3
  19. data/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb +109 -0
  20. data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +1 -0
  21. data/lib/concurrent-ruby/concurrent/atomic/locals.rb +189 -0
  22. data/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb +28 -0
  23. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +11 -5
  24. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +11 -5
  25. data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +1 -1
  26. data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +19 -3
  27. data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +2 -1
  28. data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +9 -9
  29. data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +32 -14
  30. data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +96 -89
  31. data/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb +37 -0
  32. data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +15 -4
  33. data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +1 -1
  34. data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +1 -1
  35. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +2 -0
  36. data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +2 -2
  37. data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +16 -8
  38. data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
  39. data/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +11 -1
  40. data/lib/concurrent-ruby/concurrent/concern/logging.rb +86 -2
  41. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  42. data/lib/concurrent-ruby/concurrent/configuration.rb +4 -87
  43. data/lib/concurrent-ruby/concurrent/delay.rb +2 -2
  44. data/lib/concurrent-ruby/concurrent/errors.rb +5 -0
  45. data/lib/concurrent-ruby/concurrent/exchanger.rb +1 -0
  46. data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +17 -14
  47. data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +13 -3
  48. data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +3 -3
  49. data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +4 -0
  50. data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +10 -4
  51. data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +26 -37
  52. data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +6 -6
  53. data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +1 -1
  54. data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +4 -1
  55. data/lib/concurrent-ruby/concurrent/hash.rb +0 -9
  56. data/lib/concurrent-ruby/concurrent/immutable_struct.rb +1 -1
  57. data/lib/concurrent-ruby/concurrent/ivar.rb +2 -1
  58. data/lib/concurrent-ruby/concurrent/map.rb +43 -30
  59. data/lib/concurrent-ruby/concurrent/maybe.rb +1 -1
  60. data/lib/concurrent-ruby/concurrent/mutable_struct.rb +1 -1
  61. data/lib/concurrent-ruby/concurrent/mvar.rb +1 -1
  62. data/lib/concurrent-ruby/concurrent/promise.rb +2 -1
  63. data/lib/concurrent-ruby/concurrent/promises.rb +7 -6
  64. data/lib/concurrent-ruby/concurrent/re_include.rb +2 -0
  65. data/lib/concurrent-ruby/concurrent/scheduled_task.rb +30 -17
  66. data/lib/concurrent-ruby/concurrent/set.rb +12 -14
  67. data/lib/concurrent-ruby/concurrent/settable_struct.rb +2 -2
  68. data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +5 -1
  69. data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +1 -3
  70. data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +2 -0
  71. data/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb +29 -0
  72. data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +3 -1
  73. data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +2 -0
  74. data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +6 -5
  75. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +18 -5
  76. data/lib/concurrent-ruby/concurrent/synchronization/object.rb +12 -44
  77. data/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb +36 -0
  78. data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +77 -12
  79. data/lib/concurrent-ruby/concurrent/synchronization.rb +1 -18
  80. data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +36 -39
  81. data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +2 -39
  82. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +16 -27
  83. data/lib/concurrent-ruby/concurrent/timer_task.rb +11 -33
  84. data/lib/concurrent-ruby/concurrent/tuple.rb +1 -5
  85. data/lib/concurrent-ruby/concurrent/tvar.rb +22 -61
  86. data/lib/concurrent-ruby/concurrent/utility/engine.rb +5 -16
  87. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +7 -46
  88. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +8 -10
  89. data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +1 -0
  90. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +36 -89
  91. data/lib/concurrent-ruby/concurrent/version.rb +1 -1
  92. data/lib/concurrent-ruby/concurrent-ruby.rb +5 -1
  93. metadata +11 -12
  94. data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +0 -66
  95. data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +0 -37
  96. data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +0 -181
  97. data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +0 -45
  98. data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +0 -44
  99. data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +0 -65
  100. data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +0 -49
  101. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +0 -47
@@ -1,104 +1,111 @@
1
- require 'concurrent/utility/engine'
2
- require 'concurrent/atomic/ruby_thread_local_var'
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
- # @!macro thread_local_var_method_initialize
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
- # Creates a thread local variable.
36
+ # t2 = Thread.new do
37
+ # v.value #=> 14
38
+ # v.value = 2
39
+ # v.value #=> 2
40
+ # end
12
41
  #
13
- # @param [Object] default the default value when otherwise unset
14
- # @param [Proc] default_block Optional block that gets called to obtain the
15
- # default value for each thread
42
+ # v.value #=> 14
43
+ class ThreadLocalVar
44
+ LOCALS = ThreadLocals.new
16
45
 
17
- # @!macro thread_local_var_method_get
18
- #
19
- # Returns the value in the current thread's copy of this thread-local variable.
20
- #
21
- # @return [Object] the current value
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
- # @!macro thread_local_var_method_set
24
- #
25
- # Sets the current thread's copy of this thread-local variable to the specified value.
26
- #
27
- # @param [Object] value the value to set
28
- # @return [Object] the new value
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
- # @!macro thread_local_var_method_bind
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
- # @!macro thread_local_var_public_api
43
- #
44
- # @!method initialize(default = nil, &default_block)
45
- # @!macro thread_local_var_method_initialize
46
- #
47
- # @!method value
48
- # @!macro thread_local_var_method_get
49
- #
50
- # @!method value=(value)
51
- # @!macro thread_local_var_method_set
52
- #
53
- # @!method bind(value, &block)
54
- # @!macro thread_local_var_method_bind
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
- # @!visibility private
59
- # @!macro internal_implementation_note
60
- ThreadLocalVarImplementation = case
61
- when Concurrent.on_jruby?
62
- JavaThreadLocalVar
63
- else
64
- RubyThreadLocalVar
65
- end
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 < Synchronization::LockableObject
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
- synchronize { ns_initialize(value) }
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
- def ns_initialize(value)
53
- @value = value
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,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
 
@@ -0,0 +1,14 @@
1
+ module Concurrent
2
+
3
+ # @!visibility private
4
+ module Collection
5
+
6
+ # @!visibility private
7
+ class TruffleRubyMapBackend < TruffleRuby::ConcurrentMap
8
+ def initialize(options = nil)
9
+ options ||= {}
10
+ super(initial_capacity: options[:initial_capacity], load_factor: options[:load_factor])
11
+ end
12
+ end
13
+ end
14
+ end
@@ -30,7 +30,7 @@ module Concurrent
30
30
  if @queue[k] == item
31
31
  swap(k, @length)
32
32
  @length -= 1
33
- sink(k)
33
+ sink(k) || swim(k)
34
34
  @queue.pop
35
35
  else
36
36
  k += 1
@@ -126,12 +126,17 @@ module Concurrent
126
126
  #
127
127
  # @!visibility private
128
128
  def sink(k)
129
+ success = false
130
+
129
131
  while (j = (2 * k)) <= @length do
130
132
  j += 1 if j < @length && ! ordered?(j, j+1)
131
133
  break if ordered?(k, j)
132
134
  swap(k, j)
135
+ success = true
133
136
  k = j
134
137
  end
138
+
139
+ success
135
140
  end
136
141
 
137
142
  # Percolate up to maintain heap invariant.
@@ -140,10 +145,15 @@ module Concurrent
140
145
  #
141
146
  # @!visibility private
142
147
  def swim(k)
148
+ success = false
149
+
143
150
  while k > 1 && ! ordered?(k/2, k) do
144
151
  swap(k, k/2)
145
152
  k = k/2
153
+ success = true
146
154
  end
155
+
156
+ success
147
157
  end
148
158
  end
149
159
  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
@@ -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 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