concurrent-ruby 1.1.5

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 (143) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +478 -0
  3. data/Gemfile +41 -0
  4. data/LICENSE.md +23 -0
  5. data/README.md +381 -0
  6. data/Rakefile +327 -0
  7. data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
  9. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
  10. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
  11. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
  12. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +159 -0
  13. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +307 -0
  14. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
  15. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
  16. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
  17. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
  18. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
  19. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
  20. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
  21. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
  22. data/lib/concurrent-ruby.rb +1 -0
  23. data/lib/concurrent.rb +134 -0
  24. data/lib/concurrent/agent.rb +587 -0
  25. data/lib/concurrent/array.rb +66 -0
  26. data/lib/concurrent/async.rb +459 -0
  27. data/lib/concurrent/atom.rb +222 -0
  28. data/lib/concurrent/atomic/abstract_thread_local_var.rb +66 -0
  29. data/lib/concurrent/atomic/atomic_boolean.rb +126 -0
  30. data/lib/concurrent/atomic/atomic_fixnum.rb +143 -0
  31. data/lib/concurrent/atomic/atomic_markable_reference.rb +164 -0
  32. data/lib/concurrent/atomic/atomic_reference.rb +204 -0
  33. data/lib/concurrent/atomic/count_down_latch.rb +100 -0
  34. data/lib/concurrent/atomic/cyclic_barrier.rb +128 -0
  35. data/lib/concurrent/atomic/event.rb +109 -0
  36. data/lib/concurrent/atomic/java_count_down_latch.rb +42 -0
  37. data/lib/concurrent/atomic/java_thread_local_var.rb +37 -0
  38. data/lib/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
  39. data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
  40. data/lib/concurrent/atomic/mutex_count_down_latch.rb +44 -0
  41. data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
  42. data/lib/concurrent/atomic/read_write_lock.rb +254 -0
  43. data/lib/concurrent/atomic/reentrant_read_write_lock.rb +379 -0
  44. data/lib/concurrent/atomic/ruby_thread_local_var.rb +161 -0
  45. data/lib/concurrent/atomic/semaphore.rb +145 -0
  46. data/lib/concurrent/atomic/thread_local_var.rb +104 -0
  47. data/lib/concurrent/atomic_reference/mutex_atomic.rb +56 -0
  48. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
  49. data/lib/concurrent/atomics.rb +10 -0
  50. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
  51. data/lib/concurrent/collection/copy_on_write_observer_set.rb +111 -0
  52. data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
  53. data/lib/concurrent/collection/lock_free_stack.rb +158 -0
  54. data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
  55. data/lib/concurrent/collection/map/mri_map_backend.rb +66 -0
  56. data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +140 -0
  57. data/lib/concurrent/collection/map/synchronized_map_backend.rb +82 -0
  58. data/lib/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
  59. data/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb +150 -0
  60. data/lib/concurrent/concern/deprecation.rb +34 -0
  61. data/lib/concurrent/concern/dereferenceable.rb +73 -0
  62. data/lib/concurrent/concern/logging.rb +32 -0
  63. data/lib/concurrent/concern/obligation.rb +220 -0
  64. data/lib/concurrent/concern/observable.rb +110 -0
  65. data/lib/concurrent/concurrent_ruby.jar +0 -0
  66. data/lib/concurrent/configuration.rb +184 -0
  67. data/lib/concurrent/constants.rb +8 -0
  68. data/lib/concurrent/dataflow.rb +81 -0
  69. data/lib/concurrent/delay.rb +199 -0
  70. data/lib/concurrent/errors.rb +69 -0
  71. data/lib/concurrent/exchanger.rb +352 -0
  72. data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
  73. data/lib/concurrent/executor/cached_thread_pool.rb +62 -0
  74. data/lib/concurrent/executor/executor_service.rb +185 -0
  75. data/lib/concurrent/executor/fixed_thread_pool.rb +206 -0
  76. data/lib/concurrent/executor/immediate_executor.rb +66 -0
  77. data/lib/concurrent/executor/indirect_immediate_executor.rb +44 -0
  78. data/lib/concurrent/executor/java_executor_service.rb +91 -0
  79. data/lib/concurrent/executor/java_single_thread_executor.rb +29 -0
  80. data/lib/concurrent/executor/java_thread_pool_executor.rb +123 -0
  81. data/lib/concurrent/executor/ruby_executor_service.rb +78 -0
  82. data/lib/concurrent/executor/ruby_single_thread_executor.rb +22 -0
  83. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +362 -0
  84. data/lib/concurrent/executor/safe_task_executor.rb +35 -0
  85. data/lib/concurrent/executor/serial_executor_service.rb +34 -0
  86. data/lib/concurrent/executor/serialized_execution.rb +107 -0
  87. data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
  88. data/lib/concurrent/executor/simple_executor_service.rb +100 -0
  89. data/lib/concurrent/executor/single_thread_executor.rb +56 -0
  90. data/lib/concurrent/executor/thread_pool_executor.rb +87 -0
  91. data/lib/concurrent/executor/timer_set.rb +173 -0
  92. data/lib/concurrent/executors.rb +20 -0
  93. data/lib/concurrent/future.rb +141 -0
  94. data/lib/concurrent/hash.rb +59 -0
  95. data/lib/concurrent/immutable_struct.rb +93 -0
  96. data/lib/concurrent/ivar.rb +207 -0
  97. data/lib/concurrent/map.rb +337 -0
  98. data/lib/concurrent/maybe.rb +229 -0
  99. data/lib/concurrent/mutable_struct.rb +229 -0
  100. data/lib/concurrent/mvar.rb +242 -0
  101. data/lib/concurrent/options.rb +42 -0
  102. data/lib/concurrent/promise.rb +579 -0
  103. data/lib/concurrent/promises.rb +2167 -0
  104. data/lib/concurrent/re_include.rb +58 -0
  105. data/lib/concurrent/scheduled_task.rb +318 -0
  106. data/lib/concurrent/set.rb +66 -0
  107. data/lib/concurrent/settable_struct.rb +129 -0
  108. data/lib/concurrent/synchronization.rb +30 -0
  109. data/lib/concurrent/synchronization/abstract_lockable_object.rb +98 -0
  110. data/lib/concurrent/synchronization/abstract_object.rb +24 -0
  111. data/lib/concurrent/synchronization/abstract_struct.rb +160 -0
  112. data/lib/concurrent/synchronization/condition.rb +60 -0
  113. data/lib/concurrent/synchronization/jruby_lockable_object.rb +13 -0
  114. data/lib/concurrent/synchronization/jruby_object.rb +45 -0
  115. data/lib/concurrent/synchronization/lock.rb +36 -0
  116. data/lib/concurrent/synchronization/lockable_object.rb +74 -0
  117. data/lib/concurrent/synchronization/mri_object.rb +44 -0
  118. data/lib/concurrent/synchronization/mutex_lockable_object.rb +76 -0
  119. data/lib/concurrent/synchronization/object.rb +183 -0
  120. data/lib/concurrent/synchronization/rbx_lockable_object.rb +65 -0
  121. data/lib/concurrent/synchronization/rbx_object.rb +49 -0
  122. data/lib/concurrent/synchronization/truffleruby_object.rb +47 -0
  123. data/lib/concurrent/synchronization/volatile.rb +36 -0
  124. data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
  125. data/lib/concurrent/thread_safe/util.rb +16 -0
  126. data/lib/concurrent/thread_safe/util/adder.rb +74 -0
  127. data/lib/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
  128. data/lib/concurrent/thread_safe/util/data_structures.rb +63 -0
  129. data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
  130. data/lib/concurrent/thread_safe/util/striped64.rb +246 -0
  131. data/lib/concurrent/thread_safe/util/volatile.rb +75 -0
  132. data/lib/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
  133. data/lib/concurrent/timer_task.rb +334 -0
  134. data/lib/concurrent/tuple.rb +86 -0
  135. data/lib/concurrent/tvar.rb +258 -0
  136. data/lib/concurrent/utility/at_exit.rb +97 -0
  137. data/lib/concurrent/utility/engine.rb +56 -0
  138. data/lib/concurrent/utility/monotonic_time.rb +58 -0
  139. data/lib/concurrent/utility/native_extension_loader.rb +79 -0
  140. data/lib/concurrent/utility/native_integer.rb +53 -0
  141. data/lib/concurrent/utility/processor_counter.rb +158 -0
  142. data/lib/concurrent/version.rb +3 -0
  143. metadata +193 -0
@@ -0,0 +1,86 @@
1
+ require 'concurrent/atomic/atomic_reference'
2
+
3
+ module Concurrent
4
+
5
+ # A fixed size array with volatile (synchronized, thread safe) getters/setters.
6
+ # Mixes in Ruby's `Enumerable` module for enhanced search, sort, and traversal.
7
+ #
8
+ # @example
9
+ # tuple = Concurrent::Tuple.new(16)
10
+ #
11
+ # tuple.set(0, :foo) #=> :foo | volatile write
12
+ # tuple.get(0) #=> :foo | volatile read
13
+ # tuple.compare_and_set(0, :foo, :bar) #=> true | strong CAS
14
+ # tuple.cas(0, :foo, :baz) #=> false | strong CAS
15
+ # tuple.get(0) #=> :bar | volatile read
16
+ #
17
+ # @see https://en.wikipedia.org/wiki/Tuple Tuple entry at Wikipedia
18
+ # @see http://www.erlang.org/doc/reference_manual/data_types.html#id70396 Erlang Tuple
19
+ # @see http://ruby-doc.org/core-2.2.2/Enumerable.html Enumerable
20
+ class Tuple
21
+ include Enumerable
22
+
23
+ # The (fixed) size of the tuple.
24
+ attr_reader :size
25
+
26
+ # @!visibility private
27
+ Tuple = defined?(Rubinius::Tuple) ? Rubinius::Tuple : ::Array
28
+ private_constant :Tuple
29
+
30
+ # Create a new tuple of the given size.
31
+ #
32
+ # @param [Integer] size the number of elements in the tuple
33
+ def initialize(size)
34
+ @size = size
35
+ @tuple = tuple = Tuple.new(size)
36
+ i = 0
37
+ while i < size
38
+ tuple[i] = Concurrent::AtomicReference.new
39
+ i += 1
40
+ end
41
+ end
42
+
43
+ # Get the value of the element at the given index.
44
+ #
45
+ # @param [Integer] i the index from which to retrieve the value
46
+ # @return [Object] the value at the given index or nil if the index is out of bounds
47
+ def get(i)
48
+ return nil if i >= @size || i < 0
49
+ @tuple[i].get
50
+ end
51
+ alias_method :volatile_get, :get
52
+
53
+ # Set the element at the given index to the given value
54
+ #
55
+ # @param [Integer] i the index for the element to set
56
+ # @param [Object] value the value to set at the given index
57
+ #
58
+ # @return [Object] the new value of the element at the given index or nil if the index is out of bounds
59
+ def set(i, value)
60
+ return nil if i >= @size || i < 0
61
+ @tuple[i].set(value)
62
+ end
63
+ alias_method :volatile_set, :set
64
+
65
+ # Set the value at the given index to the new value if and only if the current
66
+ # value matches the given old value.
67
+ #
68
+ # @param [Integer] i the index for the element to set
69
+ # @param [Object] old_value the value to compare against the current value
70
+ # @param [Object] new_value the value to set at the given index
71
+ #
72
+ # @return [Boolean] true if the value at the given element was set else false
73
+ def compare_and_set(i, old_value, new_value)
74
+ return false if i >= @size || i < 0
75
+ @tuple[i].compare_and_set(old_value, new_value)
76
+ end
77
+ alias_method :cas, :compare_and_set
78
+
79
+ # Calls the given block once for each element in self, passing that element as a parameter.
80
+ #
81
+ # @yieldparam [Object] ref the `Concurrent::AtomicReference` object at the current index
82
+ def each
83
+ @tuple.each {|ref| yield ref.get}
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,258 @@
1
+ require 'set'
2
+ require 'concurrent/synchronization'
3
+
4
+ module Concurrent
5
+
6
+ # A `TVar` is a transactional variable - a single-element container that
7
+ # is used as part of a transaction - see `Concurrent::atomically`.
8
+ #
9
+ # @!macro thread_safe_variable_comparison
10
+ #
11
+ # {include:file:docs-source/tvar.md}
12
+ class TVar < Synchronization::Object
13
+ safe_initialization!
14
+
15
+ # Create a new `TVar` with an initial value.
16
+ def initialize(value)
17
+ @value = value
18
+ @version = 0
19
+ @lock = Mutex.new
20
+ end
21
+
22
+ # Get the value of a `TVar`.
23
+ def value
24
+ Concurrent::atomically do
25
+ Transaction::current.read(self)
26
+ end
27
+ end
28
+
29
+ # Set the value of a `TVar`.
30
+ def value=(value)
31
+ Concurrent::atomically do
32
+ Transaction::current.write(self, value)
33
+ end
34
+ end
35
+
36
+ # @!visibility private
37
+ def unsafe_value # :nodoc:
38
+ @value
39
+ end
40
+
41
+ # @!visibility private
42
+ def unsafe_value=(value) # :nodoc:
43
+ @value = value
44
+ end
45
+
46
+ # @!visibility private
47
+ def unsafe_version # :nodoc:
48
+ @version
49
+ end
50
+
51
+ # @!visibility private
52
+ def unsafe_increment_version # :nodoc:
53
+ @version += 1
54
+ end
55
+
56
+ # @!visibility private
57
+ def unsafe_lock # :nodoc:
58
+ @lock
59
+ end
60
+
61
+ end
62
+
63
+ # Run a block that reads and writes `TVar`s as a single atomic transaction.
64
+ # With respect to the value of `TVar` objects, the transaction is atomic, in
65
+ # that it either happens or it does not, consistent, in that the `TVar`
66
+ # objects involved will never enter an illegal state, and isolated, in that
67
+ # transactions never interfere with each other. You may recognise these
68
+ # properties from database transactions.
69
+ #
70
+ # There are some very important and unusual semantics that you must be aware of:
71
+ #
72
+ # * Most importantly, the block that you pass to atomically may be executed
73
+ # more than once. In most cases your code should be free of
74
+ # side-effects, except for via TVar.
75
+ #
76
+ # * If an exception escapes an atomically block it will abort the transaction.
77
+ #
78
+ # * It is undefined behaviour to use callcc or Fiber with atomically.
79
+ #
80
+ # * If you create a new thread within an atomically, it will not be part of
81
+ # the transaction. Creating a thread counts as a side-effect.
82
+ #
83
+ # Transactions within transactions are flattened to a single transaction.
84
+ #
85
+ # @example
86
+ # a = new TVar(100_000)
87
+ # b = new TVar(100)
88
+ #
89
+ # Concurrent::atomically do
90
+ # a.value -= 10
91
+ # b.value += 10
92
+ # end
93
+ def atomically
94
+ raise ArgumentError.new('no block given') unless block_given?
95
+
96
+ # Get the current transaction
97
+
98
+ transaction = Transaction::current
99
+
100
+ # Are we not already in a transaction (not nested)?
101
+
102
+ if transaction.nil?
103
+ # New transaction
104
+
105
+ begin
106
+ # Retry loop
107
+
108
+ loop do
109
+
110
+ # Create a new transaction
111
+
112
+ transaction = Transaction.new
113
+ Transaction::current = transaction
114
+
115
+ # Run the block, aborting on exceptions
116
+
117
+ begin
118
+ result = yield
119
+ rescue Transaction::AbortError => e
120
+ transaction.abort
121
+ result = Transaction::ABORTED
122
+ rescue Transaction::LeaveError => e
123
+ transaction.abort
124
+ break result
125
+ rescue => e
126
+ transaction.abort
127
+ raise e
128
+ end
129
+ # If we can commit, break out of the loop
130
+
131
+ if result != Transaction::ABORTED
132
+ if transaction.commit
133
+ break result
134
+ end
135
+ end
136
+ end
137
+ ensure
138
+ # Clear the current transaction
139
+
140
+ Transaction::current = nil
141
+ end
142
+ else
143
+ # Nested transaction - flatten it and just run the block
144
+
145
+ yield
146
+ end
147
+ end
148
+
149
+ # Abort a currently running transaction - see `Concurrent::atomically`.
150
+ def abort_transaction
151
+ raise Transaction::AbortError.new
152
+ end
153
+
154
+ # Leave a transaction without committing or aborting - see `Concurrent::atomically`.
155
+ def leave_transaction
156
+ raise Transaction::LeaveError.new
157
+ end
158
+
159
+ module_function :atomically, :abort_transaction, :leave_transaction
160
+
161
+ private
162
+
163
+ class Transaction
164
+
165
+ ABORTED = ::Object.new
166
+
167
+ ReadLogEntry = Struct.new(:tvar, :version)
168
+
169
+ AbortError = Class.new(StandardError)
170
+ LeaveError = Class.new(StandardError)
171
+
172
+ def initialize
173
+ @read_log = []
174
+ @write_log = {}
175
+ end
176
+
177
+ def read(tvar)
178
+ Concurrent::abort_transaction unless valid?
179
+
180
+ if @write_log.has_key? tvar
181
+ @write_log[tvar]
182
+ else
183
+ @read_log.push(ReadLogEntry.new(tvar, tvar.unsafe_version))
184
+ tvar.unsafe_value
185
+ end
186
+ end
187
+
188
+ def write(tvar, value)
189
+ # Have we already written to this TVar?
190
+
191
+ unless @write_log.has_key? tvar
192
+ # Try to lock the TVar
193
+
194
+ unless tvar.unsafe_lock.try_lock
195
+ # Someone else is writing to this TVar - abort
196
+ Concurrent::abort_transaction
197
+ end
198
+
199
+ # If we previously wrote to it, check the version hasn't changed
200
+
201
+ @read_log.each do |log_entry|
202
+ if log_entry.tvar == tvar and tvar.unsafe_version > log_entry.version
203
+ Concurrent::abort_transaction
204
+ end
205
+ end
206
+ end
207
+
208
+ # Record the value written
209
+
210
+ @write_log[tvar] = value
211
+ end
212
+
213
+ def abort
214
+ unlock
215
+ end
216
+
217
+ def commit
218
+ return false unless valid?
219
+
220
+ @write_log.each_pair do |tvar, value|
221
+ tvar.unsafe_value = value
222
+ tvar.unsafe_increment_version
223
+ end
224
+
225
+ unlock
226
+
227
+ true
228
+ end
229
+
230
+ def valid?
231
+ @read_log.each do |log_entry|
232
+ unless @write_log.has_key? log_entry.tvar
233
+ if log_entry.tvar.unsafe_version > log_entry.version
234
+ return false
235
+ end
236
+ end
237
+ end
238
+
239
+ true
240
+ end
241
+
242
+ def unlock
243
+ @write_log.each_key do |tvar|
244
+ tvar.unsafe_lock.unlock
245
+ end
246
+ end
247
+
248
+ def self.current
249
+ Thread.current[:current_tvar_transaction]
250
+ end
251
+
252
+ def self.current=(transaction)
253
+ Thread.current[:current_tvar_transaction] = transaction
254
+ end
255
+
256
+ end
257
+
258
+ end
@@ -0,0 +1,97 @@
1
+ require 'logger'
2
+ require 'concurrent/synchronization'
3
+
4
+ module Concurrent
5
+
6
+ # Provides ability to add and remove handlers to be run at `Kernel#at_exit`, order is undefined.
7
+ # Each handler is executed at most once.
8
+ #
9
+ # @!visibility private
10
+ class AtExitImplementation < Synchronization::LockableObject
11
+ include Logger::Severity
12
+
13
+ def initialize(*args)
14
+ super()
15
+ synchronize { ns_initialize(*args) }
16
+ end
17
+
18
+ # Add a handler to be run at `Kernel#at_exit`
19
+ # @param [Object] handler_id optionally provide an id, if already present, handler is replaced
20
+ # @yield the handler
21
+ # @return id of the handler
22
+ def add(handler_id = nil, &handler)
23
+ id = handler_id || handler.object_id
24
+ synchronize { @handlers[id] = handler }
25
+ id
26
+ end
27
+
28
+ # Delete a handler by handler_id
29
+ # @return [true, false]
30
+ def delete(handler_id)
31
+ !!synchronize { @handlers.delete handler_id }
32
+ end
33
+
34
+ # Is handler with handler_id rpesent?
35
+ # @return [true, false]
36
+ def handler?(handler_id)
37
+ synchronize { @handlers.key? handler_id }
38
+ end
39
+
40
+ # @return copy of the handlers
41
+ def handlers
42
+ synchronize { @handlers }.clone
43
+ end
44
+
45
+ # install `Kernel#at_exit` callback to execute added handlers
46
+ def install
47
+ synchronize do
48
+ @installed ||= begin
49
+ at_exit { runner }
50
+ true
51
+ end
52
+ self
53
+ end
54
+ end
55
+
56
+ # Will it run during `Kernel#at_exit`
57
+ def enabled?
58
+ synchronize { @enabled }
59
+ end
60
+
61
+ # Configure if it runs during `Kernel#at_exit`
62
+ def enabled=(value)
63
+ synchronize { @enabled = value }
64
+ end
65
+
66
+ # run the handlers manually
67
+ # @return ids of the handlers
68
+ def run
69
+ handlers, _ = synchronize { handlers, @handlers = @handlers, {} }
70
+ handlers.each do |_, handler|
71
+ begin
72
+ handler.call
73
+ rescue => error
74
+ Concurrent.global_logger.call(ERROR, error)
75
+ end
76
+ end
77
+ handlers.keys
78
+ end
79
+
80
+ private
81
+
82
+ def ns_initialize(enabled = true)
83
+ @handlers = {}
84
+ @enabled = enabled
85
+ end
86
+
87
+ def runner
88
+ run if synchronize { @enabled }
89
+ end
90
+ end
91
+
92
+ private_constant :AtExitImplementation
93
+
94
+ # @see AtExitImplementation
95
+ # @!visibility private
96
+ AtExit = AtExitImplementation.new.install
97
+ end
@@ -0,0 +1,56 @@
1
+ module Concurrent
2
+ module Utility
3
+
4
+ # @!visibility private
5
+ module EngineDetector
6
+ def on_jruby?
7
+ ruby_engine == 'jruby'
8
+ end
9
+
10
+ def on_jruby_9000?
11
+ on_jruby? && ruby_version(JRUBY_VERSION, :>=, 9, 0, 0)
12
+ end
13
+
14
+ def on_cruby?
15
+ ruby_engine == 'ruby'
16
+ end
17
+
18
+ def on_rbx?
19
+ ruby_engine == 'rbx'
20
+ end
21
+
22
+ def on_truffleruby?
23
+ ruby_engine == 'truffleruby'
24
+ end
25
+
26
+ def on_windows?
27
+ !(RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/).nil?
28
+ end
29
+
30
+ def on_osx?
31
+ !(RbConfig::CONFIG['host_os'] =~ /darwin|mac os/).nil?
32
+ end
33
+
34
+ def on_linux?
35
+ !(RbConfig::CONFIG['host_os'] =~ /linux/).nil?
36
+ end
37
+
38
+ def ruby_engine
39
+ defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
40
+ end
41
+
42
+ def ruby_version(version = RUBY_VERSION, comparison, major, minor, patch)
43
+ result = (version.split('.').map(&:to_i) <=> [major, minor, patch])
44
+ comparisons = { :== => [0],
45
+ :>= => [1, 0],
46
+ :<= => [-1, 0],
47
+ :> => [1],
48
+ :< => [-1] }
49
+ comparisons.fetch(comparison).include? result
50
+ end
51
+ end
52
+ end
53
+
54
+ # @!visibility private
55
+ extend Utility::EngineDetector
56
+ end