concurrent-ruby 1.0.0.pre5-java → 1.0.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -16
  3. data/README.md +4 -8
  4. data/lib/concurrent/array.rb +1 -1
  5. data/lib/concurrent/async.rb +2 -2
  6. data/lib/concurrent/atom.rb +1 -1
  7. data/lib/concurrent/atomic_reference/jruby+truffle.rb +1 -1
  8. data/lib/concurrent/atomics.rb +3 -1
  9. data/lib/concurrent/dataflow.rb +5 -3
  10. data/lib/concurrent/delay.rb +1 -0
  11. data/lib/concurrent/exchanger.rb +2 -2
  12. data/lib/concurrent/executor/fixed_thread_pool.rb +5 -5
  13. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +18 -3
  14. data/lib/concurrent/executor/thread_pool_executor.rb +15 -9
  15. data/lib/concurrent/executor/timer_set.rb +3 -3
  16. data/lib/concurrent/future.rb +2 -2
  17. data/lib/concurrent/hash.rb +1 -1
  18. data/lib/concurrent/lazy_register.rb +1 -1
  19. data/lib/concurrent/map.rb +50 -1
  20. data/lib/concurrent/options.rb +0 -2
  21. data/lib/concurrent/promise.rb +2 -2
  22. data/lib/concurrent/scheduled_task.rb +2 -2
  23. data/lib/concurrent/synchronization.rb +2 -0
  24. data/lib/concurrent/synchronization/abstract_lockable_object.rb +1 -1
  25. data/lib/concurrent/synchronization/lockable_object.rb +3 -1
  26. data/lib/concurrent/synchronization/object.rb +9 -7
  27. data/lib/concurrent/synchronization/rbx_object.rb +2 -0
  28. data/lib/concurrent/synchronization/truffle_lockable_object.rb +9 -0
  29. data/lib/concurrent/synchronization/truffle_object.rb +32 -0
  30. data/lib/concurrent/timer_task.rb +2 -0
  31. data/lib/concurrent/utility/engine.rb +8 -0
  32. data/lib/concurrent/utility/processor_counter.rb +2 -0
  33. data/lib/concurrent/version.rb +2 -2
  34. data/lib/concurrent_ruby_ext.jar +0 -0
  35. metadata +6 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7d7b579740ce1202c660c37eb72e05a0097c49ab
4
- data.tar.gz: 37f19da839100f7d8002f64edcbcada96b751ccc
3
+ metadata.gz: 793ecb127939757bfebe945aaf8d0a04abed1ba6
4
+ data.tar.gz: efd7bf4be657e131700a904377e5d7d792c4e1f8
5
5
  SHA512:
6
- metadata.gz: ef72505a341a9a6b984b4946f754540df39fdba7a052c6dbdd6830ce3e9fedd5856b1e7563592557c3044ec6f30a92e845402bae1aa6447a6f7c93fb5ccb458d
7
- data.tar.gz: 29ac27d5f288f2fb6f7fb86894fa83b79a3e837cf3a0623a03d85cc4d00f0076f7fb49ea30ae313fc4d547e935ed2a7eb6903eb0cea1316c280e086631d750c8
6
+ metadata.gz: 01704d17b959dabf4ef3eb38c1d1f83ec5a1008298b344e242d59ae8a9ec64fa0978eabe75e62d4c259f0122a666f3bdf6a6932c31b468571695a02a8bf337f1
7
+ data.tar.gz: b3c7a588c628f74126b0cdec12e64ba7cc283bdae8a31f075e81616bf06d18e0668e1a7f578c573d8e6b1f537ccf21a7d387624f53ae2dc7d91ee58c604e7fa3
@@ -1,7 +1,21 @@
1
- ### Upcoming Release v1.0.0 (TBD)
2
-
3
- ## Current Release v1.0.0.pre5 (04 November 2015)
4
-
1
+ ## Current Release v1.0.1 (27 February 2016)
2
+
3
+ * Fix "uninitialized constant Concurrent::ReentrantReadWriteLock" error.
4
+ * Better handling of `autoload` vs. `require`.
5
+ * Improved API for Edge `Future` zipping.
6
+ * Fix reference leak in Edge `Future` constructor .
7
+ * Fix bug which prevented thread pools from surviving a `fork`.
8
+ * Fix bug in which `TimerTask` did not correctly specify all its dependencies.
9
+ * Improved support for JRuby+Truffle
10
+ * Improved error messages.
11
+ * Improved documentation.
12
+ * Updated README and CONTRIBUTING.
13
+
14
+ ### Release v1.0.0 (13 November 2015)
15
+
16
+ * Rename `attr_volatile_with_cas` to `attr_atomic`
17
+ * Add `clear_each` to `LockFreeStack`
18
+ * Update `AtomicReference` documentation
5
19
  * Further updates and improvements to the synchronization layer.
6
20
  * Performance and memory usage performance with `Actor` logging.
7
21
  * Fixed `ThreadPoolExecutor` task count methods.
@@ -9,9 +23,6 @@
9
23
  * Fixed bug in `LockFreeLinkedSet`.
10
24
  * Fixed bug in which `Agent#await` triggered a validation failure.
11
25
  * Further `Channel` updates.
12
-
13
- ### Release v1.0.0.pre4 (08 October 2015)
14
-
15
26
  * Adopted a project Code of Conduct
16
27
  * Cleared interpreter warnings
17
28
  * Fixed bug in `ThreadPoolExecutor` task count methods
@@ -19,18 +30,12 @@
19
30
  * Improved Java extension loading
20
31
  * Handle Exception children in Edge::Future
21
32
  * Continued improvements to channel
22
-
23
- ### Release v1.0.0.pre3 (29 September 2015)
24
-
25
33
  * Removed interpreter warnings.
26
34
  * Shared constants now in `lib/concurrent/constants.rb`
27
35
  * Refactored many tests.
28
36
  * Improved synchronization layer/memory model documentation.
29
37
  * Bug fix in Edge `Future#flat`
30
38
  * Brand new `Channel` implementation in Edge gem.
31
-
32
- ### Release v1.0.0.pre2 (19 September 2015)
33
-
34
39
  * Simplification of `RubySingleThreadExecutor`
35
40
  * `Async` improvements
36
41
  - Each object uses its own `SingleThreadExecutor` instead of the global thread pool.
@@ -42,9 +47,6 @@
42
47
  - Added a `#reset` method
43
48
  * Brand new `Agent` API and implementation. Now functionally equivalent to Clojure.
44
49
  * Continued improvements to the synchronization layer
45
-
46
- ### Release v1.0.0.pre1 (19 August 2015)
47
-
48
50
  * Merged in the `thread_safe` gem
49
51
  - `Concurrent::Array`
50
52
  - `Concurrent::Hash`
data/README.md CHANGED
@@ -45,9 +45,9 @@
45
45
 
46
46
  ### Supported Ruby versions
47
47
 
48
- MRI 1.9.3, 2.0, 2.1, 2.2, JRuby (1.9 mode), and Rubinius 2.x are supported.
48
+ MRI 1.9.3, 2.0 and above, JRuby 1.7x in 1.9 mode, JRuby 9000, and Rubinius 2.x are supported.
49
49
  This gem should be fully compatible with any interpreter that is compliant with Ruby 1.9.3 or newer.
50
- Java 8 is preferred for JRuby but every Java version on which JRuby 9000 runs will be supported.
50
+ Java 8 is preferred for JRuby but every Java version on which JRuby 9000 runs is supported.
51
51
 
52
52
  ## Thread Safety
53
53
 
@@ -59,14 +59,10 @@ It is critical to remember, however, that Ruby is a language of mutable referenc
59
59
 
60
60
  ## Features & Documentation
61
61
 
62
- We have a roadmap guiding our work toward the [v1.0.0 release](https://github.com/ruby-concurrency/concurrent-ruby/issues/257).
63
-
64
62
  The primary site for documentation is the automatically generated [API documentation](http://ruby-concurrency.github.io/concurrent-ruby/frames.html)
65
63
 
66
64
  We also have a [mailing list](http://groups.google.com/group/concurrent-ruby) and [IRC (gitter)](https://gitter.im/ruby-concurrency/concurrent-ruby).
67
65
 
68
- This library contains a variety of concurrency abstractions at high and low levels. One of the high-level abstractions is likely to meet most common needs.
69
-
70
66
  #### General-purpose Concurrency Abstractions
71
67
 
72
68
  * [Async](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Async.html): A mixin module that provides simple asynchronous behavior to a class. Loosely based on Erlang's [gen_server](http://www.erlang.org/doc/man/gen_server.html).
@@ -182,7 +178,7 @@ gem install concurrent-ruby
182
178
  or add the following line to Gemfile:
183
179
 
184
180
  ```ruby
185
- gem 'concurrent-ruby'
181
+ gem 'concurrent-ruby', require: 'concurrent'
186
182
  ```
187
183
 
188
184
  and run `bundle install` from your shell.
@@ -198,7 +194,7 @@ gem install concurrent-ruby-edge
198
194
  or add the following line to Gemfile:
199
195
 
200
196
  ```ruby
201
- gem 'concurrent-ruby-edge'
197
+ gem 'concurrent-ruby-edge', require: 'concurrent-edge'
202
198
  ```
203
199
 
204
200
  and run `bundle install` from your shell.
@@ -25,7 +25,7 @@ module Concurrent
25
25
  include JRuby::Synchronized
26
26
  end
27
27
 
28
- elsif Concurrent.on_rbx?
28
+ elsif Concurrent.on_rbx? || Concurrent.on_truffle?
29
29
  require 'monitor'
30
30
  require 'concurrent/thread_safe/util/array_hash_rbx'
31
31
 
@@ -58,7 +58,7 @@ module Concurrent
58
58
  # end
59
59
  # ```
60
60
  #
61
- # When defining a constructor it is critica that the first line be a call to
61
+ # When defining a constructor it is critical that the first line be a call to
62
62
  # `super` with no arguments. The `super` method initializes the background
63
63
  # thread and other asynchronous components.
64
64
  #
@@ -153,7 +153,7 @@ module Concurrent
153
153
  # subtly different.
154
154
  #
155
155
  # When internal state is accessed via the `async` and `await` proxy methods,
156
- # the returned value represents the object's sate *at the time the call is
156
+ # the returned value represents the object's state *at the time the call is
157
157
  # processed*, which may *not* be the state of the object at the time the call
158
158
  # is made.
159
159
  #
@@ -95,7 +95,7 @@ module Concurrent
95
95
  include Concern::Observable
96
96
 
97
97
  safe_initialization!
98
- private(*attr_volatile_with_cas(:value))
98
+ private(*attr_atomic(:value))
99
99
  public :value
100
100
 
101
101
  # Create a new atom with the given initial value.
@@ -1 +1 @@
1
- require 'concurrent/atomic_reference/rbx'
1
+ require 'concurrent/atomic_reference/mutex_atomic'
@@ -1,6 +1,7 @@
1
1
  # @!macro [new] atomic_reference
2
2
  #
3
- # An object reference that may be updated atomically.
3
+ # An object reference that may be updated atomically. All read and write
4
+ # operations have java volatile semantic.
4
5
  #
5
6
  # @!macro thread_safe_variable_comparison
6
7
  #
@@ -47,5 +48,6 @@ require 'concurrent/atomic/cyclic_barrier'
47
48
  require 'concurrent/atomic/count_down_latch'
48
49
  require 'concurrent/atomic/event'
49
50
  require 'concurrent/atomic/read_write_lock'
51
+ require 'concurrent/atomic/reentrant_read_write_lock'
50
52
  require 'concurrent/atomic/semaphore'
51
53
  require 'concurrent/atomic/thread_local_var'
@@ -39,7 +39,7 @@ module Concurrent
39
39
  call_dataflow(:value, executor, *inputs, &block)
40
40
  end
41
41
  module_function :dataflow_with
42
-
42
+
43
43
  def dataflow!(*inputs, &block)
44
44
  dataflow_with!(Concurrent.global_io_executor, *inputs, &block)
45
45
  end
@@ -50,12 +50,14 @@ module Concurrent
50
50
  end
51
51
  module_function :dataflow_with!
52
52
 
53
- private
53
+ private
54
54
 
55
55
  def call_dataflow(method, executor, *inputs, &block)
56
56
  raise ArgumentError.new('an executor must be provided') if executor.nil?
57
57
  raise ArgumentError.new('no block given') unless block_given?
58
- raise ArgumentError.new('not all dependencies are IVars') unless inputs.all? { |input| input.is_a? IVar }
58
+ unless inputs.all? { |input| input.is_a? IVar }
59
+ raise ArgumentError.new("Not all dependencies are IVars.\nDependencies: #{ inputs.inspect }")
60
+ end
59
61
 
60
62
  result = Future.new(executor: executor) do
61
63
  values = inputs.map { |input| input.send(method) }
@@ -5,6 +5,7 @@ require 'concurrent/synchronization'
5
5
 
6
6
  module Concurrent
7
7
 
8
+ # This file has circular require issues. It must be autoloaded here.
8
9
  autoload :Options, 'concurrent/options'
9
10
 
10
11
  # Lazy evaluation of a block yielding an immutable result. Useful for
@@ -143,7 +143,7 @@ module Concurrent
143
143
  safe_initialization!
144
144
 
145
145
  class Node < Concurrent::Synchronization::Object
146
- attr_volatile_with_cas :value
146
+ attr_atomic :value
147
147
  safe_initialization!
148
148
 
149
149
  def initialize(item)
@@ -170,7 +170,7 @@ module Concurrent
170
170
 
171
171
  private
172
172
 
173
- attr_volatile_with_cas(:slot)
173
+ attr_atomic(:slot)
174
174
 
175
175
  # @!macro exchanger_method_do_exchange
176
176
  #
@@ -116,8 +116,8 @@ module Concurrent
116
116
  #
117
117
  # * `idletime`: The number of seconds that a thread may be idle before being reclaimed.
118
118
  # * `max_queue`: The maximum number of tasks that may be waiting in the work queue at
119
- # any one time. When the queue size reaches `max_queue` subsequent tasks will be
120
- # rejected in accordance with the configured `fallback_policy`.
119
+ # any one time. When the queue size reaches `max_queue` and no new threads can be created,
120
+ # subsequent tasks will be rejected in accordance with the configured `fallback_policy`.
121
121
  # * `auto_terminate`: When true (default) an `at_exit` handler will be registered which
122
122
  # will stop the thread pool when the application exits. See below for more information
123
123
  # on shutting down thread pools.
@@ -146,7 +146,7 @@ module Concurrent
146
146
  # On some runtime platforms (most notably the JVM) the application will not
147
147
  # exit until all thread pools have been shutdown. To prevent applications from
148
148
  # "hanging" on exit all thread pools include an `at_exit` handler that will
149
- # stop the thread pool when the application exists. This handler uses a brute
149
+ # stop the thread pool when the application exits. This handler uses a brute
150
150
  # force method to stop the pool and makes no guarantees regarding resources being
151
151
  # used by any tasks still running. Registration of this `at_exit` handler can be
152
152
  # prevented by setting the thread pool's constructor `:auto_terminate` option to
@@ -171,8 +171,8 @@ module Concurrent
171
171
 
172
172
  # @!macro [attach] fixed_thread_pool
173
173
  #
174
- # A thread pool with a set number of threads. The number of threads in the pool
175
- # is set on construction and remains constant. When all threads are busy new
174
+ # A thread pool that reuses a fixed number of threads operating off an unbounded queue.
175
+ # At any point, at most `num_threads` will be active processing tasks. When all threads are busy new
176
176
  # tasks `#post` to the thread pool are enqueued until a thread becomes available.
177
177
  # Should a thread crash for any reason the thread will immediately be removed
178
178
  # from the pool and replaced.
@@ -131,6 +131,7 @@ module Concurrent
131
131
  @scheduled_task_count = 0
132
132
  @completed_task_count = 0
133
133
  @largest_length = 0
134
+ @ruby_pid = $$ # detects if Ruby has forked
134
135
 
135
136
  @gc_interval = opts.fetch(:gc_interval, @idletime / 2.0).to_i # undocumented
136
137
  @next_gc_time = Concurrent.monotonic_time + @gc_interval
@@ -143,6 +144,8 @@ module Concurrent
143
144
 
144
145
  # @!visibility private
145
146
  def ns_execute(*args, &task)
147
+ ns_reset_if_forked
148
+
146
149
  if ns_assign_worker(*args, &task) || ns_enqueue(*args, &task)
147
150
  @scheduled_task_count += 1
148
151
  else
@@ -150,21 +153,21 @@ module Concurrent
150
153
  end
151
154
 
152
155
  ns_prune_pool if @next_gc_time < Concurrent.monotonic_time
153
- # raise unless @ready.empty? || @queue.empty? # assert
154
156
  end
155
157
 
156
158
  # @!visibility private
157
159
  def ns_shutdown_execution
160
+ ns_reset_if_forked
161
+
158
162
  if @pool.empty?
159
163
  # nothing to do
160
164
  stopped_event.set
161
165
  end
166
+
162
167
  if @queue.empty?
163
168
  # no more tasks will be accepted, just stop all workers
164
169
  @pool.each(&:stop)
165
170
  end
166
-
167
- # raise unless @ready.empty? || @queue.empty? # assert
168
171
  end
169
172
 
170
173
  # @!visibility private
@@ -273,6 +276,18 @@ module Concurrent
273
276
  @next_gc_time = Concurrent.monotonic_time + @gc_interval
274
277
  end
275
278
 
279
+ def ns_reset_if_forked
280
+ if $$ != @ruby_pid
281
+ @queue.clear
282
+ @ready.clear
283
+ @pool.clear
284
+ @scheduled_task_count = 0
285
+ @completed_task_count = 0
286
+ @largest_length = 0
287
+ @ruby_pid = $$
288
+ end
289
+ end
290
+
276
291
  # @!visibility private
277
292
  class Worker
278
293
  include Concern::Logging
@@ -18,16 +18,22 @@ module Concurrent
18
18
  # @!macro [attach] thread_pool_executor
19
19
  #
20
20
  # An abstraction composed of one or more threads and a task queue. Tasks
21
- # (blocks or `proc` objects) are submit to the pool and added to the queue.
21
+ # (blocks or `proc` objects) are submitted to the pool and added to the queue.
22
22
  # The threads in the pool remove the tasks and execute them in the order
23
- # they were received. When there are more tasks queued than there are
24
- # threads to execute them the pool will create new threads, up to the
25
- # configured maximum. Similarly, threads that are idle for too long will
26
- # be garbage collected, down to the configured minimum options. Should a
27
- # thread crash it, too, will be garbage collected.
23
+ # they were received.
24
+ #
25
+ # A `ThreadPoolExecutor` will automatically adjust the pool size according
26
+ # to the bounds set by `min-threads` and `max-threads`. When a new task is
27
+ # submitted and fewer than `min-threads` threads are running, a new thread
28
+ # is created to handle the request, even if other worker threads are idle.
29
+ # If there are more than `min-threads` but less than `max-threads` threads
30
+ # running, a new thread will be created only if the queue is full.
31
+ #
32
+ # Threads that are idle for too long will be garbage collected, down to the
33
+ # configured minimum options. Should a thread crash it, too, will be garbage collected.
28
34
  #
29
35
  # `ThreadPoolExecutor` is based on the Java class of the same name. From
30
- # the official Java documentationa;
36
+ # the official Java documentation;
31
37
  #
32
38
  # > Thread pools address two different problems: they usually provide
33
39
  # > improved performance when executing large numbers of asynchronous tasks,
@@ -57,8 +63,8 @@ module Concurrent
57
63
  #
58
64
  # @option opts [Integer] :max_threads (DEFAULT_MAX_POOL_SIZE) the maximum
59
65
  # number of threads to be created
60
- # @option opts [Integer] :min_threads (DEFAULT_MIN_POOL_SIZE) the minimum
61
- # number of threads to be retained
66
+ # @option opts [Integer] :min_threads (DEFAULT_MIN_POOL_SIZE) When a new task is submitted
67
+ # and fewer than `min_threads` are running, a new thread is created
62
68
  # @option opts [Integer] :idletime (DEFAULT_THREAD_IDLETIMEOUT) the maximum
63
69
  # number of seconds a thread may be idle before being reclaimed
64
70
  # @option opts [Integer] :max_queue (DEFAULT_MAX_QUEUE_SIZE) the maximum
@@ -4,9 +4,9 @@ require 'concurrent/collection/non_concurrent_priority_queue'
4
4
  require 'concurrent/executor/executor_service'
5
5
  require 'concurrent/executor/single_thread_executor'
6
6
 
7
- module Concurrent
7
+ require 'concurrent/options'
8
8
 
9
- autoload :Options, 'concurrent/options'
9
+ module Concurrent
10
10
 
11
11
  # Executes a collection of tasks, each after a given delay. A master task
12
12
  # monitors the set and schedules each task for execution at the appropriate
@@ -21,7 +21,7 @@ module Concurrent
21
21
  # Create a new set of timed tasks.
22
22
  #
23
23
  # @!macro [attach] executor_options
24
- #
24
+ #
25
25
  # @param [Hash] opts the options used to specify the executor on which to perform actions
26
26
  # @option opts [Executor] :executor when set use the given `Executor` instance.
27
27
  # Three special values are also supported: `:task` returns the global task pool,
@@ -4,9 +4,9 @@ require 'concurrent/errors'
4
4
  require 'concurrent/ivar'
5
5
  require 'concurrent/executor/safe_task_executor'
6
6
 
7
- module Concurrent
7
+ require 'concurrent/options'
8
8
 
9
- autoload :Options, 'concurrent/options'
9
+ module Concurrent
10
10
 
11
11
  # {include:file:doc/future.md}
12
12
  #
@@ -22,7 +22,7 @@ module Concurrent
22
22
  include JRuby::Synchronized
23
23
  end
24
24
 
25
- elsif Concurrent.on_rbx?
25
+ elsif Concurrent.on_rbx? || Concurrent.on_truffle?
26
26
  require 'monitor'
27
27
  require 'concurrent/thread_safe/util/array_hash_rbx'
28
28
 
@@ -18,7 +18,7 @@ module Concurrent
18
18
  # @!macro edge_warning
19
19
  class LazyRegister < Synchronization::Object
20
20
 
21
- private(*attr_volatile_with_cas(:data))
21
+ private(*attr_atomic(:data))
22
22
 
23
23
  def initialize
24
24
  super
@@ -18,6 +18,9 @@ module Concurrent
18
18
  when 'rbx'
19
19
  require 'concurrent/collection/map/atomic_reference_map_backend'
20
20
  AtomicReferenceMapBackend
21
+ when 'jruby+truffle'
22
+ require 'concurrent/collection/map/atomic_reference_map_backend'
23
+ AtomicReferenceMapBackend
21
24
  else
22
25
  warn 'Concurrent::Map: unsupported Ruby engine, using a fully synchronized Concurrent::Map implementation' if $VERBOSE
23
26
  require 'concurrent/collection/map/synchronized_map_backend'
@@ -38,8 +41,43 @@ module Concurrent
38
41
  # > require 'concurrent'
39
42
  # >
40
43
  # > map = Concurrent::Map.new
41
-
42
44
  class Map < Collection::MapImplementation
45
+
46
+ # @!macro [new] map_method_is_atomic
47
+ # This method is atomic. Atomic methods of `Map` which accept a block
48
+ # do not allow the `self` instance to be used within the block. Doing
49
+ # so will cause a deadlock.
50
+
51
+ # @!method put_if_absent
52
+ # @!macro map_method_is_atomic
53
+
54
+ # @!method compute_if_absent
55
+ # @!macro map_method_is_atomic
56
+
57
+ # @!method compute_if_present
58
+ # @!macro map_method_is_atomic
59
+
60
+ # @!method compute
61
+ # @!macro map_method_is_atomic
62
+
63
+ # @!method merge_pair
64
+ # @!macro map_method_is_atomic
65
+
66
+ # @!method replace_pair
67
+ # @!macro map_method_is_atomic
68
+
69
+ # @!method replace_if_exists
70
+ # @!macro map_method_is_atomic
71
+
72
+ # @!method get_and_set
73
+ # @!macro map_method_is_atomic
74
+
75
+ # @!method delete
76
+ # @!macro map_method_is_atomic
77
+
78
+ # @!method delete_pair
79
+ # @!macro map_method_is_atomic
80
+
43
81
  def initialize(options = nil, &block)
44
82
  if options.kind_of?(::Hash)
45
83
  validate_options_hash!(options)
@@ -68,6 +106,15 @@ module Concurrent
68
106
  alias_method :get, :[]
69
107
  alias_method :put, :[]=
70
108
 
109
+ # @!macro [attach] map_method_not_atomic
110
+ # The "fetch-then-act" methods of `Map` are not atomic. `Map` is intended
111
+ # to be use as a concurrency primitive with strong happens-before
112
+ # guarantees. It is not intended to be used as a high-level abstraction
113
+ # supporting complex operations. All read and write operations are
114
+ # thread safe, but no guarantees are made regarding race conditions
115
+ # between the fetch operation and yielding to the block. Additionally,
116
+ # this method does not support recursion. This is due to internal
117
+ # constraints that are very unlikely to change in the near future.
71
118
  def fetch(key, default_value = NULL)
72
119
  if NULL != (value = get_or_default(key, NULL))
73
120
  value
@@ -80,12 +127,14 @@ module Concurrent
80
127
  end
81
128
  end
82
129
 
130
+ # @!macro map_method_not_atomic
83
131
  def fetch_or_store(key, default_value = NULL)
84
132
  fetch(key) do
85
133
  put(key, block_given? ? yield(key) : (NULL == default_value ? raise_fetch_no_key : default_value))
86
134
  end
87
135
  end
88
136
 
137
+ # @!macro map_method_is_atomic
89
138
  def put_if_absent(key, value)
90
139
  computed = false
91
140
  result = compute_if_absent(key) do
@@ -1,5 +1,3 @@
1
- # This file has circular require issues. It must be autoloaded.
2
-
3
1
  require 'concurrent/configuration'
4
2
 
5
3
  module Concurrent
@@ -3,9 +3,9 @@ require 'concurrent/constants'
3
3
  require 'concurrent/errors'
4
4
  require 'concurrent/ivar'
5
5
 
6
- module Concurrent
6
+ require 'concurrent/options'
7
7
 
8
- autoload :Options, 'concurrent/options'
8
+ module Concurrent
9
9
 
10
10
  PromiseExecutionError = Class.new(StandardError)
11
11
 
@@ -5,9 +5,9 @@ require 'concurrent/ivar'
5
5
  require 'concurrent/collection/copy_on_notify_observer_set'
6
6
  require 'concurrent/utility/monotonic_time'
7
7
 
8
- module Concurrent
8
+ require 'concurrent/options'
9
9
 
10
- autoload :Options, 'concurrent/options'
10
+ module Concurrent
11
11
 
12
12
  # `ScheduledTask` is a close relative of `Concurrent::Future` but with one
13
13
  # important difference: A `Future` is set to execute as soon as possible
@@ -7,6 +7,7 @@ Concurrent.load_native_extensions
7
7
  require 'concurrent/synchronization/mri_object'
8
8
  require 'concurrent/synchronization/jruby_object'
9
9
  require 'concurrent/synchronization/rbx_object'
10
+ require 'concurrent/synchronization/truffle_object'
10
11
  require 'concurrent/synchronization/object'
11
12
  require 'concurrent/synchronization/volatile'
12
13
 
@@ -14,6 +15,7 @@ require 'concurrent/synchronization/abstract_lockable_object'
14
15
  require 'concurrent/synchronization/mri_lockable_object'
15
16
  require 'concurrent/synchronization/jruby_lockable_object'
16
17
  require 'concurrent/synchronization/rbx_lockable_object'
18
+ require 'concurrent/synchronization/truffle_lockable_object'
17
19
 
18
20
  require 'concurrent/synchronization/lockable_object'
19
21
 
@@ -2,7 +2,7 @@ module Concurrent
2
2
  module Synchronization
3
3
 
4
4
  # @!visibility private
5
- class AbstractLockableObject < Object
5
+ class AbstractLockableObject < Synchronization::Object
6
6
 
7
7
  protected
8
8
 
@@ -10,8 +10,10 @@ module Concurrent
10
10
  MriMutexLockableObject
11
11
  when Concurrent.on_jruby?
12
12
  JRubyLockableObject
13
- when Concurrent.on_rbx? || Concurrent.on_truffle?
13
+ when Concurrent.on_rbx?
14
14
  RbxLockableObject
15
+ when Concurrent.on_truffle?
16
+ MriMutexLockableObject
15
17
  else
16
18
  warn 'Possibly unsupported Ruby implementation'
17
19
  MriMonitorLockableObject
@@ -8,8 +8,10 @@ module Concurrent
8
8
  MriObject
9
9
  when Concurrent.on_jruby?
10
10
  JRubyObject
11
- when Concurrent.on_rbx? || Concurrent.on_truffle?
11
+ when Concurrent.on_rbx?
12
12
  RbxObject
13
+ when Concurrent.on_truffle?
14
+ TruffleObject
13
15
  else
14
16
  MriObject
15
17
  end
@@ -18,7 +20,7 @@ module Concurrent
18
20
  # Abstract object providing final, volatile, ans CAS extensions to build other concurrent abstractions.
19
21
  # - final instance variables see {Object.safe_initialization!}
20
22
  # - volatile instance variables see {Object.attr_volatile}
21
- # - volatile instance variables see {Object.attr_volatile_with_cas}
23
+ # - volatile instance variables see {Object.attr_atomic}
22
24
  class Object < ObjectImplementation
23
25
 
24
26
  # @!method self.attr_volatile(*names)
@@ -49,8 +51,8 @@ module Concurrent
49
51
  # define only once, and not again in children
50
52
  return if safe_initialization?
51
53
 
52
- def self.new(*)
53
- object = super
54
+ def self.new(*args, &block)
55
+ object = super(*args, &block)
54
56
  ensure
55
57
  object.full_memory_barrier if object
56
58
  end
@@ -87,14 +89,14 @@ module Concurrent
87
89
  # `compare_and_set_value(expected, value) #=> true || false`, `update_value(&block)`.
88
90
  # @param [Array<Symbol>] names of the instance variables to be volatile with CAS.
89
91
  # @return [Array<Symbol>] names of defined method names.
90
- def self.attr_volatile_with_cas(*names)
92
+ def self.attr_atomic(*names)
91
93
  @volatile_cas_fields ||= []
92
94
  @volatile_cas_fields += names
93
95
  safe_initialization!
94
96
  define_initialize_volatile_with_cas
95
97
 
96
98
  names.each do |name|
97
- ivar = :"@VolatileCas#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }}"
99
+ ivar = :"@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }}"
98
100
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
99
101
  def #{name}
100
102
  #{ivar}.get
@@ -131,7 +133,7 @@ module Concurrent
131
133
  private
132
134
 
133
135
  def self.define_initialize_volatile_with_cas
134
- assignments = @volatile_cas_fields.map { |name| "@VolatileCas#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }} = AtomicReference.new(nil)" }.join("\n")
136
+ assignments = @volatile_cas_fields.map { |name| "@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }} = AtomicReference.new(nil)" }.join("\n")
135
137
  class_eval <<-RUBY
136
138
  def initialize_volatile_with_cas
137
139
  super
@@ -7,6 +7,7 @@ module Concurrent
7
7
  end
8
8
 
9
9
  module ClassMethods
10
+
10
11
  def attr_volatile(*names)
11
12
  names.each do |name|
12
13
  ivar = :"@volatile_#{name}"
@@ -24,6 +25,7 @@ module Concurrent
24
25
  end
25
26
  names.map { |n| [n, :"#{n}="] }.flatten
26
27
  end
28
+
27
29
  end
28
30
 
29
31
  def full_memory_barrier
@@ -0,0 +1,9 @@
1
+ module Concurrent
2
+ module Synchronization
3
+ class TruffleLockableObject < AbstractLockableObject
4
+ def new(*)
5
+ raise NotImplementedError
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,32 @@
1
+ module Concurrent
2
+ module Synchronization
3
+
4
+ module TruffleAttrVolatile
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+ def attr_volatile(*names)
11
+ # TODO may not always be available
12
+ attr_atomic(*names)
13
+ end
14
+ end
15
+
16
+ def full_memory_barrier
17
+ # Rubinius instance variables are not volatile so we need to insert barrier
18
+ Rubinius.memory_barrier
19
+ end
20
+ end
21
+
22
+ # @!visibility private
23
+ # @!macro internal_implementation_note
24
+ class TruffleObject < AbstractObject
25
+ include TruffleAttrVolatile
26
+
27
+ def initialize
28
+ # nothing to do
29
+ end
30
+ end
31
+ end
32
+ end
@@ -3,7 +3,9 @@ require 'concurrent/concern/dereferenceable'
3
3
  require 'concurrent/concern/observable'
4
4
  require 'concurrent/atomic/atomic_boolean'
5
5
  require 'concurrent/executor/executor_service'
6
+ require 'concurrent/executor/ruby_executor_service'
6
7
  require 'concurrent/executor/safe_task_executor'
8
+ require 'concurrent/scheduled_task'
7
9
 
8
10
  module Concurrent
9
11
 
@@ -27,6 +27,14 @@ module Concurrent
27
27
  !(RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/).nil?
28
28
  end
29
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
+
30
38
  def ruby_engine
31
39
  defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
32
40
  end
@@ -75,6 +75,8 @@ module Concurrent
75
75
  def compute_processor_count
76
76
  if Concurrent.on_jruby?
77
77
  java.lang.Runtime.getRuntime.availableProcessors
78
+ elsif Concurrent.on_truffle?
79
+ Truffle::Primitive.logical_processors
78
80
  else
79
81
  os_name = RbConfig::CONFIG["target_os"]
80
82
  if os_name =~ /mingw|mswin/
@@ -1,4 +1,4 @@
1
1
  module Concurrent
2
- VERSION = '1.0.0.pre5'
3
- EDGE_VERSION = '0.2.0.pre5'
2
+ VERSION = '1.0.1'
3
+ EDGE_VERSION = '0.2.1'
4
4
  end
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: concurrent-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre5
4
+ version: 1.0.1
5
5
  platform: java
6
6
  authors:
7
7
  - Jerry D'Antonio
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-11-04 00:00:00.000000000 Z
12
+ date: 2016-02-27 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: |
15
15
  Modern concurrency tools including agents, futures, promises, thread pools, actors, supervisors, and more.
@@ -128,6 +128,8 @@ files:
128
128
  - lib/concurrent/synchronization/object.rb
129
129
  - lib/concurrent/synchronization/rbx_lockable_object.rb
130
130
  - lib/concurrent/synchronization/rbx_object.rb
131
+ - lib/concurrent/synchronization/truffle_lockable_object.rb
132
+ - lib/concurrent/synchronization/truffle_object.rb
131
133
  - lib/concurrent/synchronization/volatile.rb
132
134
  - lib/concurrent/thread_safe/synchronized_delegator.rb
133
135
  - lib/concurrent/thread_safe/util.rb
@@ -163,9 +165,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
163
165
  version: 1.9.3
164
166
  required_rubygems_version: !ruby/object:Gem::Requirement
165
167
  requirements:
166
- - - ">"
168
+ - - ">="
167
169
  - !ruby/object:Gem::Version
168
- version: 1.3.1
170
+ version: '0'
169
171
  requirements: []
170
172
  rubyforge_project:
171
173
  rubygems_version: 2.4.8