concurrent-ruby-ext 0.1.0.pre1-x86-solaris-2.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9014fe556fac8662f384005c0ac0f87eb49f012c
4
+ data.tar.gz: a4c98cbb36f37d9698dd651ffd2bbea3e1af893d
5
+ SHA512:
6
+ metadata.gz: d1f3aad98cd11762aa796947400ed1804b0aa6e0594d597bc27f9929d557ad21a40f6c05fcfe6bc5e4955ce355a6fac5e844ffecc7ee855a1dd98aa075fab022
7
+ data.tar.gz: 6ce7da2475c2ee38bb0fe5fa0cb0d459f452782bf62d30ee8248ac1caedb2c56621edee59cf780248112f980121bc89393a80929fe1e4568eeaa2cc1a55b24ca
data/CHANGELOG.md ADDED
@@ -0,0 +1,149 @@
1
+ ### Next Release v0.7.2 (TBD)
2
+
3
+ * New `Promise.all?` and `Promise.any?` class methods
4
+ * Renamed `:overflow_policy` on thread pools to `:fallback_policy`
5
+ * Thread pools still accept the `:overflow_policy` option but display a warning
6
+ * Thread pools now implement `fallback_policy` behavior when not running (rather than universally rejecting tasks)
7
+ * Fixed minor `set_deref_options` constructor bug in `Promise` class
8
+ * Numerous non-functional updates to clear warning when running in debug mode
9
+ * Fixed more intermittently failing tests
10
+ * Tests now run on new Travis build environment
11
+
12
+ ## Current Release v0.7.1 (4 December 2014)
13
+
14
+ Please see the [roadmap](https://github.com/ruby-concurrency/concurrent-ruby/issues/142) for more information on the next planned release.
15
+
16
+ * Added `flat_map` method to `Promise`
17
+ * Added `zip` method to `Promise`
18
+ * Fixed bug with logging in `Actor`
19
+ * Improvements to `Promise` tests
20
+ * Removed actor-experimental warning
21
+ * Added an `IndirectImmediateExecutor` class
22
+ * Allow disabling auto termination of global executors
23
+ * Fix thread leaking in `ThreadLocalVar` (uses `Ref` gem on non-JRuby systems)
24
+ * Fix thread leaking when pruning pure-Ruby thread pools
25
+ * Prevent `Actor` from using an `ImmediateExecutor` (causes deadlock)
26
+ * Added missing synchronizations to `TimerSet`
27
+ * Fixed bug with return value of `Concurrent::Actor::Utils::Pool#ask`
28
+ * Fixed timing bug in `TimerTask`
29
+ * Fixed bug when creating a `JavaThreadPoolExecutor` with minimum pool size of zero
30
+ * Removed confusing warning when not using native extenstions
31
+ * Improved documentation
32
+
33
+ ### Release v0.7.0 (13 August 2014)
34
+
35
+ * Merge the [atomic](https://github.com/ruby-concurrency/atomic) gem
36
+ - Pure Ruby `MutexAtomic` atomic reference class
37
+ - Platform native atomic reference classes `CAtomic`, `JavaAtomic`, and `RbxAtomic`
38
+ - Automated [build process](https://github.com/ruby-concurrency/rake-compiler-dev-box)
39
+ - Fat binary releases for [multiple platforms](https://rubygems.org/gems/concurrent-ruby/versions) including Windows (32/64), Linux (32/64), OS X (64-bit), Solaris (64-bit), and JRuby
40
+ * C native `CAtomicBoolean`
41
+ * C native `CAtomicFixnum`
42
+ * Refactored intermittently failing tests
43
+ * Added `dataflow!` and `dataflow_with!` methods to match `Future#value!` method
44
+ * Better handling of timeout in `Agent`
45
+ * Actor Improvements
46
+ - Fine-grained implementation using chain of behaviors. Each behavior is responsible for single aspect like: `Termination`, `Pausing`, `Linking`, `Supervising`, etc. Users can create custom Actors easily based on their needs.
47
+ - Supervision was added. `RestartingContext` will pause on error waiting on its supervisor to decide what to do next ( options are `:terminate!`, `:resume!`, `:reset!`, `:restart!`). Supervising behavior also supports strategies `:one_for_one` and `:one_for_all`.
48
+ - Linking was added to be able to monitor actor's events like: `:terminated`, `:paused`, `:restarted`, etc.
49
+ - Dead letter routing added. Rejected envelopes are collected in a configurable actor (default: `Concurrent::Actor.root.ask!(:dead_letter_routing)`)
50
+ - Old `Actor` class removed and replaced by new implementation previously called `Actress`. `Actress` was kept as an alias for `Actor` to keep compatibility.
51
+ - `Utils::Broadcast` actor which allows Publish–subscribe pattern.
52
+ * More executors for managing serialized operations
53
+ - `SerializedExecution` mixin module
54
+ - `SerializedExecutionDelegator` for serializing *any* executor
55
+ * Updated `Async` with serialized execution
56
+ * Updated `ImmediateExecutor` and `PerThreadExecutor` with full executor service lifecycle
57
+ * Added a `Delay` to root `Actress` initialization
58
+ * Minor bug fixes to thread pools
59
+ * Refactored many intermittently failing specs
60
+ * Removed Java interop warning `executor.rb:148 warning: ambiguous Java methods found, using submit(java.lang.Runnable)`
61
+ * Fixed minor bug in `RubyCachedThreadPool` overflow policy
62
+ * Updated tests to use [RSpec 3.0](http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3)
63
+ * Removed deprecated `Actor` class
64
+ * Better support for Rubinius
65
+
66
+ ### Release v0.6.1 (14 June 2014)
67
+
68
+ * Many improvements to `Concurrent::Actress`
69
+ * Bug fixes to `Concurrent::RubyThreadPoolExecutor`
70
+ * Fixed several brittle tests
71
+ * Moved documentation to http://ruby-concurrency.github.io/concurrent-ruby/frames.html
72
+
73
+ ### Release v0.6.0 (25 May 2014)
74
+
75
+ * Added `Concurrent::Observable` to encapsulate our thread safe observer sets
76
+ * Improvements to new `Channel`
77
+ * Major improvements to `CachedThreadPool` and `FixedThreadPool`
78
+ * Added `SingleThreadExecutor`
79
+ * Added `Current::timer` function
80
+ * Added `TimerSet` executor
81
+ * Added `AtomicBoolean`
82
+ * `ScheduledTask` refactoring
83
+ * Pure Ruby and JRuby-optimized `PriorityQueue` classes
84
+ * Updated `Agent` behavior to more closely match Clojure
85
+ * Observer sets support block callbacks to the `add_observer` method
86
+ * New algorithm for thread creation in `RubyThreadPoolExecutor`
87
+ * Minor API updates to `Event`
88
+ * Rewritten `TimerTask` now an `Executor` instead of a `Runnable`
89
+ * Fixed many brittle specs
90
+ * Renamed `FixedThreadPool` and `CachedThreadPool` to `RubyFixedThreadPool` and `RubyCachedThreadPool`
91
+ * Created JRuby optimized `JavaFixedThreadPool` and `JavaCachedThreadPool`
92
+ * Consolidated fixed thread pool tests into `spec/concurrent/fixed_thread_pool_shared.rb` and `spec/concurrent/cached_thread_pool_shared.rb`
93
+ * `FixedThreadPool` now subclasses `RubyFixedThreadPool` or `JavaFixedThreadPool` as appropriate
94
+ * `CachedThreadPool` now subclasses `RubyCachedThreadPool` or `JavaCachedThreadPool` as appropriate
95
+ * New `Delay` class
96
+ * `Concurrent::processor_count` helper function
97
+ * New `Async` module
98
+ * Renamed `NullThreadPool` to `PerThreadExecutor`
99
+ * Deprecated `Channel` (we are planning a new implementation based on [Go](http://golangtutorials.blogspot.com/2011/06/channels-in-go.html))
100
+ * Added gem-level [configuration](http://robots.thoughtbot.com/mygem-configure-block)
101
+ * Deprecated `$GLOBAL_THREAD_POOL` in lieu of gem-level configuration
102
+ * Removed support for Ruby [1.9.2](https://www.ruby-lang.org/en/news/2013/12/17/maintenance-of-1-8-7-and-1-9-2/)
103
+ * New `RubyThreadPoolExecutor` and `JavaThreadPoolExecutor` classes
104
+ * All thread pools now extend the appropriate thread pool executor classes
105
+ * All thread pools now support `:overflow_policy` (based on Java's [reject policies](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html))
106
+ * Deprecated `UsesGlobalThreadPool` in lieu of explicit `:executor` option (dependency injection) on `Future`, `Promise`, and `Agent`
107
+ * Added `Concurrent::dataflow_with(executor, *inputs)` method to support executor dependency injection for dataflow
108
+ * Software transactional memory with `TVar` and `Concurrent::atomically`
109
+ * First implementation of [new, high-performance](https://github.com/ruby-concurrency/concurrent-ruby/pull/49) `Channel`
110
+ * `Actor` is deprecated in favor of new experimental actor implementation [#73](https://github.com/ruby-concurrency/concurrent-ruby/pull/73). To avoid namespace collision it is living in `Actress` namespace until `Actor` is removed in next release.
111
+
112
+ ### Release v0.5.0
113
+
114
+ This is the most significant release of this gem since its inception. This release includes many improvements and optimizations. It also includes several bug fixes. The major areas of focus for this release were:
115
+
116
+ * Stability improvements on Ruby versions with thread-level parallelism ([JRuby](http://jruby.org/) and [Rubinius](http://rubini.us/))
117
+ * Creation of new low-level concurrency abstractions
118
+ * Internal refactoring to use the new low-level abstractions
119
+
120
+ Most of these updates had no effect on the gem API. There are a few notable exceptions which were unavoidable. Please read the [release notes](API-Updates-in-v0.5.0) for more information.
121
+
122
+ Specific changes include:
123
+
124
+ * New class `IVar`
125
+ * New class `MVar`
126
+ * New class `ThreadLocalVar`
127
+ * New class `AtomicFixnum`
128
+ * New class method `dataflow`
129
+ * New class `Condition`
130
+ * New class `CountDownLatch`
131
+ * New class `DependencyCounter`
132
+ * New class `SafeTaskExecutor`
133
+ * New class `CopyOnNotifyObserverSet`
134
+ * New class `CopyOnWriteObserverSet`
135
+ * `Future` updated with `execute` API
136
+ * `ScheduledTask` updated with `execute` API
137
+ * New `Promise` API
138
+ * `Future` now extends `IVar`
139
+ * `Postable#post?` now returns an `IVar`
140
+ * Thread safety fixes to `Dereferenceable`
141
+ * Thread safety fixes to `Obligation`
142
+ * Thread safety fixes to `Supervisor`
143
+ * Thread safety fixes to `Event`
144
+ * Various other thread safety (race condition) fixes
145
+ * Refactored brittle tests
146
+ * Implemented pending tests
147
+ * Added JRuby and Rubinius as Travis CI build targets
148
+ * Added [CodeClimate](https://codeclimate.com/) code review
149
+ * Improved YARD documentation
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) Jerry D'Antonio -- released under the MIT license.
2
+
3
+ http://www.opensource.org/licenses/mit-license.php
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,200 @@
1
+ # Concurrent Ruby
2
+ [![Gem Version](https://badge.fury.io/rb/concurrent-ruby.svg)](http://badge.fury.io/rb/concurrent-ruby) [![Build Status](https://travis-ci.org/ruby-concurrency/concurrent-ruby.svg?branch=master)](https://travis-ci.org/ruby-concurrency/concurrent-ruby) [![Coverage Status](https://img.shields.io/coveralls/ruby-concurrency/concurrent-ruby/master.svg)](https://coveralls.io/r/ruby-concurrency/concurrent-ruby) [![Code Climate](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby.svg)](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby) [![Inline docs](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby.svg)](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby) [![Dependency Status](https://gemnasium.com/ruby-concurrency/concurrent-ruby.svg)](https://gemnasium.com/ruby-concurrency/concurrent-ruby) [![License](https://img.shields.io/badge/license-MIT-green.svg)](http://opensource.org/licenses/MIT) [![Gitter chat](http://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/ruby-concurrency/concurrent-ruby)
3
+
4
+ <table>
5
+ <tr>
6
+ <td align="left" valign="top">
7
+ <p>
8
+ Modern concurrency tools for Ruby. Inspired by
9
+ <a href="http://www.erlang.org/doc/reference_manual/processes.html">Erlang</a>,
10
+ <a href="http://clojure.org/concurrent_programming">Clojure</a>,
11
+ <a href="http://akka.io/">Scala</a>,
12
+ <a href="http://www.haskell.org/haskellwiki/Applications_and_libraries/Concurrency_and_parallelism#Concurrent_Haskell">Haskell</a>,
13
+ <a href="http://blogs.msdn.com/b/dsyme/archive/2010/02/15/async-and-parallel-design-patterns-in-f-part-3-agents.aspx">F#</a>,
14
+ <a href="http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx">C#</a>,
15
+ <a href="http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html">Java</a>,
16
+ and classic concurrency patterns.
17
+ </p>
18
+ <p>
19
+ The design goals of this gem are:
20
+ <ul>
21
+ <li>Be an 'unopinionated' toolbox that provides useful utilities without debating which is better or why</li>
22
+ <li>Remain free of external gem dependencies</li>
23
+ <li>Stay true to the spirit of the languages providing inspiration</li>
24
+ <li>But implement in a way that makes sense for Ruby</li>
25
+ <li>Keep the semantics as idiomatic Ruby as possible</li>
26
+ <li>Support features that make sense in Ruby</li>
27
+ <li>Exclude features that don't make sense in Ruby</li>
28
+ <li>Be small, lean, and loosely coupled</li>
29
+ </ul>
30
+ </p>
31
+ </td>
32
+ <td align="right" valign="top">
33
+ <img src="https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/logo/concurrent-ruby-logo-300x300.png"/>
34
+ </td>
35
+ </tr>
36
+ </table>
37
+
38
+ ### Supported Ruby versions
39
+
40
+ MRI 1.9.3, 2.0, 2.1, JRuby (1.9 mode), and Rubinius 2.x are supported.
41
+ This gem should be fully compatible with any interpreter that is compliant with Ruby 1.9.3 or newer.
42
+
43
+ ## Features & Documentation
44
+
45
+ We have a roadmap guiding our work toward the [v1.0.0 release](https://github.com/ruby-concurrency/concurrent-ruby/wiki/v1.0-Roadmap).
46
+
47
+ The primary site for documentation is the automatically generated [API documentation](http://ruby-concurrency.github.io/concurrent-ruby/frames.html)
48
+
49
+ We also have a [mailing list](http://groups.google.com/group/concurrent-ruby).
50
+
51
+ 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.
52
+
53
+ ### High-level, general-purpose asynchronous concurrency abstractions
54
+
55
+ * [Actor](./doc/actor/main.md): Implements the Actor Model, where concurrent actors exchange messages.
56
+ * [Agent](./doc/agent.md): A single atomic value that represents an identity.
57
+ * [Async](./doc/async.md): A mixin module that provides simple asynchronous behavior to any standard class/object or object.
58
+ * [Future](./doc/future.md): An asynchronous operation that produces a value.
59
+ * [Dataflow](./doc/dataflow.md): Built on Futures, Dataflow allows you to create a task that will be scheduled when all of its data dependencies are available.
60
+ * [Promise](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Promise.html): Similar to Futures, with more features.
61
+ * [ScheduledTask](./doc/scheduled_task.md): Like a Future scheduled for a specific future time.
62
+ * [TimerTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TimerTask.html): A Thread that periodically wakes up to perform work at regular intervals.
63
+ * [Channel](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Channel.html): Communicating Sequential Processes (CSP).
64
+
65
+ ### Java-inspired ThreadPools and other executors
66
+
67
+ * See [ThreadPool](./doc/thread_pools.md) overview, which also contains a list of other Executors available.
68
+
69
+ ### Thread-safe Observers
70
+
71
+ * [Concurrent::Observable](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Observable.html) mixin module
72
+ * [CopyOnNotifyObserverSet](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CopyOnNotifyObserverSet.html)
73
+ * [CopyOnWriteObserverSet](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CopyOnWriteObserverSet.html)
74
+
75
+ ### Thread synchronization classes and algorithms
76
+ Lower-level abstractions mainly used as building blocks.
77
+
78
+ * [condition](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Condition.html)
79
+ * [countdown latch](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CountDownLatch.html)
80
+ * [cyclic barrier](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/CyclicBarrier.html)
81
+ * [event](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Event.html)
82
+ * [exchanger](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Exchanger.html)
83
+ * [timeout](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent.html#timeout-class_method)
84
+ * [timer](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent.html#timer-class_method)
85
+
86
+ ### Thread-safe variables
87
+ Lower-level abstractions mainly used as building blocks.
88
+
89
+ * [AtomicBoolean](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/AtomicBoolean.html)
90
+ * [AtomicFixnum](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/AtomicFixnum.html)
91
+ * AtomicReference (no docs currently available, check source)
92
+ * [I-Structures](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/IVar.html) (IVar)
93
+ * [M-Structures](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/MVar.html) (MVar)
94
+ * [thread-local variables](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ThreadLocalVar.html)
95
+ * [software transactional memory](./doc/tvar.md) (TVar)
96
+
97
+ ## Usage
98
+
99
+ All abstractions within this gem can be loaded simply by requiring it:
100
+
101
+ ```ruby
102
+ require 'concurrent'
103
+ ```
104
+
105
+ To reduce the amount of code loaded at runtime, subsets of this gem can be required:
106
+
107
+ ```ruby
108
+ require 'concurrent' # everything
109
+
110
+ # groups
111
+
112
+ require 'concurrent/actor' # Concurrent::Actor and supporting code
113
+ require 'concurrent/atomics' # atomic and thread synchronization classes
114
+ require 'concurrent/channels' # Concurrent::Channel and supporting code
115
+ require 'concurrent/executors' # Thread pools and other executors
116
+ require 'concurrent/utilities' # utility methods such as processor count and timers
117
+
118
+ # individual abstractions
119
+
120
+ require 'concurrent/agent' # Concurrent::Agent
121
+ require 'concurrent/async' # Concurrent::Async
122
+ require 'concurrent/atomic' # Concurrent::Atomic (formerly the `atomic` gem)
123
+ require 'concurrent/dataflow' # Concurrent::dataflow
124
+ require 'concurrent/delay' # Concurrent::Delay
125
+ require 'concurrent/exchanger' # Concurrent::Exchanger
126
+ require 'concurrent/future' # Concurrent::Future
127
+ require 'concurrent/ivar' # Concurrent::IVar
128
+ require 'concurrent/mvar' # Concurrent::MVar
129
+ require 'concurrent/promise' # Concurrent::Promise
130
+ require 'concurrent/scheduled_task' # Concurrent::ScheduledTask
131
+ require 'concurrent/timer_task' # Concurrent::TimerTask
132
+ require 'concurrent/tvar' # Concurrent::TVar
133
+ ```
134
+
135
+ ## Installation
136
+
137
+ ```shell
138
+ gem install concurrent-ruby
139
+ ```
140
+
141
+ or add the following line to Gemfile:
142
+
143
+ ```ruby
144
+ gem 'concurrent-ruby'
145
+ ```
146
+
147
+ and run `bundle install` from your shell.
148
+
149
+ ### C Extensions for MRI
150
+
151
+ Potential performance improvements may be achieved under MRI by installing optional C extensions.
152
+ To minimize installation errors the C extensions are available in the `concurrent-ruby-ext` extension
153
+ gem. The extension gem lists `concurrent-ruby` as a dependency so it is not necessary to install both.
154
+ Simply install the extension gen:
155
+
156
+ ```shell
157
+ gem install concurrent-ruby-ext
158
+ ```
159
+
160
+ or add the following line to Gemfile:
161
+
162
+ ```ruby
163
+ gem 'concurrent-ruby-ext'
164
+ ```
165
+
166
+ and run `bundle install` from your shell.
167
+
168
+ In code it is only necessary to
169
+
170
+ ```shell
171
+ require 'concurrent'
172
+ ```
173
+
174
+ The `concurrent-ruby` gem will automatically detect the presence of the `concurrent-ruby-ext` gem
175
+ and load the appropriate C extensions.
176
+
177
+ ## Maintainers
178
+
179
+ * [Jerry D'Antonio](https://github.com/jdantonio)
180
+ * [Michele Della Torre](https://github.com/mighe)
181
+ * [Chris Seaton](https://github.com/chrisseaton)
182
+ * [Lucas Allan](https://github.com/lucasallan)
183
+ * [Petr Chalupa](https://github.com/pitr-ch)
184
+ * [Paweł Obrok](https://github.com/obrok)
185
+
186
+ ### Contributing
187
+
188
+ 1. Fork it
189
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
190
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
191
+ 4. Push to the branch (`git push origin my-new-feature`)
192
+ 5. Create new Pull Request
193
+
194
+ ## License and Copyright
195
+
196
+ *Concurrent Ruby* is free software released under the [MIT License](http://www.opensource.org/licenses/MIT).
197
+
198
+ The *Concurrent Ruby* [logo](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Logo)
199
+ was designed by [David Jones](https://twitter.com/zombyboy).
200
+ It is Copyright &copy; 2014 [Jerry D'Antonio](https://twitter.com/jerrydantonio). All Rights Reserved.
@@ -0,0 +1,48 @@
1
+ #include <ruby.h>
2
+
3
+ #include "atomic_boolean.h"
4
+ #include "atomic_reference.h"
5
+ #include "ruby_193_compatible.h"
6
+
7
+ void atomic_boolean_mark(void *value) {
8
+ rb_gc_mark_maybe((VALUE) value);
9
+ }
10
+
11
+ VALUE atomic_boolean_allocate(VALUE klass) {
12
+ return rb_data_object_alloc(klass, (void *) Qfalse, atomic_boolean_mark, NULL);
13
+ }
14
+
15
+ VALUE method_atomic_boolean_initialize(int argc, VALUE* argv, VALUE self) {
16
+ VALUE value = Qfalse;
17
+ rb_check_arity(argc, 0, 1);
18
+ if (argc == 1) value = TRUTHY(argv[0]);
19
+ DATA_PTR(self) = (void *) value;
20
+ return(self);
21
+ }
22
+
23
+ VALUE method_atomic_boolean_value(VALUE self) {
24
+ return (VALUE) DATA_PTR(self);
25
+ }
26
+
27
+ VALUE method_atomic_boolean_value_set(VALUE self, VALUE value) {
28
+ VALUE new_value = TRUTHY(value);
29
+ DATA_PTR(self) = (void *) new_value;
30
+ return(new_value);
31
+ }
32
+
33
+ VALUE method_atomic_boolean_true_question(VALUE self) {
34
+ return(method_atomic_boolean_value(self));
35
+ }
36
+
37
+ VALUE method_atomic_boolean_false_question(VALUE self) {
38
+ VALUE current = method_atomic_boolean_value(self);
39
+ return(current == Qfalse ? Qtrue : Qfalse);
40
+ }
41
+
42
+ VALUE method_atomic_boolean_make_true(VALUE self) {
43
+ return(ir_compare_and_set(self, Qfalse, Qtrue));
44
+ }
45
+
46
+ VALUE method_atomic_boolean_make_false(VALUE self) {
47
+ return(ir_compare_and_set(self, Qtrue, Qfalse));
48
+ }
@@ -0,0 +1,16 @@
1
+ #ifndef __ATOMIC_BOOLEAN_H__
2
+ #define __ATOMIC_BOOLEAN_H__
3
+
4
+ #define TRUTHY(value)(value == Qfalse || value == Qnil ? Qfalse : Qtrue)
5
+
6
+ void atomic_boolean_mark(void*);
7
+ VALUE atomic_boolean_allocate(VALUE);
8
+ VALUE method_atomic_boolean_initialize(int, VALUE*, VALUE);
9
+ VALUE method_atomic_boolean_value(VALUE);
10
+ VALUE method_atomic_boolean_value_set(VALUE, VALUE);
11
+ VALUE method_atomic_boolean_true_question(VALUE);
12
+ VALUE method_atomic_boolean_false_question(VALUE);
13
+ VALUE method_atomic_boolean_make_true(VALUE);
14
+ VALUE method_atomic_boolean_make_false(VALUE);
15
+
16
+ #endif
@@ -0,0 +1,50 @@
1
+ #include <ruby.h>
2
+
3
+ #include "atomic_fixnum.h"
4
+ #include "atomic_reference.h"
5
+ #include "ruby_193_compatible.h"
6
+
7
+ void atomic_fixnum_mark(void *value) {
8
+ rb_gc_mark_maybe((VALUE) value);
9
+ }
10
+
11
+ VALUE atomic_fixnum_allocate(VALUE klass) {
12
+ return rb_data_object_alloc(klass, (void *) Qnil, atomic_fixnum_mark, NULL);
13
+ }
14
+
15
+ VALUE method_atomic_fixnum_initialize(int argc, VALUE* argv, VALUE self) {
16
+ VALUE value = LL2NUM(0);
17
+ rb_check_arity(argc, 0, 1);
18
+ if (argc == 1) {
19
+ Check_Type(argv[0], T_FIXNUM);
20
+ value = argv[0];
21
+ }
22
+ DATA_PTR(self) = (void *) value;
23
+ return(self);
24
+ }
25
+
26
+ VALUE method_atomic_fixnum_value(VALUE self) {
27
+ return (VALUE) DATA_PTR(self);
28
+ }
29
+
30
+ VALUE method_atomic_fixnum_value_set(VALUE self, VALUE value) {
31
+ Check_Type(value, T_FIXNUM);
32
+ DATA_PTR(self) = (void *) value;
33
+ return(value);
34
+ }
35
+
36
+ VALUE method_atomic_fixnum_increment(VALUE self) {
37
+ long long value = NUM2LL((VALUE) DATA_PTR(self));
38
+ return method_atomic_fixnum_value_set(self, LL2NUM(value + 1));
39
+ }
40
+
41
+ VALUE method_atomic_fixnum_decrement(VALUE self) {
42
+ long long value = NUM2LL((VALUE) DATA_PTR(self));
43
+ return method_atomic_fixnum_value_set(self, LL2NUM(value - 1));
44
+ }
45
+
46
+ VALUE method_atomic_fixnum_compare_and_set(VALUE self, VALUE rb_expect, VALUE rb_update) {
47
+ Check_Type(rb_expect, T_FIXNUM);
48
+ Check_Type(rb_update, T_FIXNUM);
49
+ return ir_compare_and_set(self, rb_expect, rb_update);
50
+ }
@@ -0,0 +1,13 @@
1
+ #ifndef __ATOMIC_FIXNUM_H__
2
+ #define __ATOMIC_FIXNUM_H__
3
+
4
+ void atomic_fixnum_mark(void*);
5
+ VALUE atomic_fixnum_allocate(VALUE);
6
+ VALUE method_atomic_fixnum_initialize(int, VALUE*, VALUE);
7
+ VALUE method_atomic_fixnum_value(VALUE);
8
+ VALUE method_atomic_fixnum_value_set(VALUE, VALUE);
9
+ VALUE method_atomic_fixnum_increment(VALUE);
10
+ VALUE method_atomic_fixnum_decrement(VALUE);
11
+ VALUE method_atomic_fixnum_compare_and_set(VALUE, VALUE, VALUE);
12
+
13
+ #endif
@@ -0,0 +1,91 @@
1
+ #include <ruby.h>
2
+ /*#if defined(__sun)*/
3
+ /*#include <atomic.h>*/
4
+ /*#endif*/
5
+
6
+ /*#ifdef HAVE_LIBKERN_OSATOMIC_H*/
7
+ /*#include <libkern/OSAtomic.h>*/
8
+ /*#endif*/
9
+
10
+ #include "atomic_reference.h"
11
+
12
+ void ir_mark(void *value) {
13
+ rb_gc_mark_maybe((VALUE) value);
14
+ }
15
+
16
+ VALUE ir_alloc(VALUE klass) {
17
+ return rb_data_object_alloc(klass, (void *) Qnil, ir_mark, NULL);
18
+ }
19
+
20
+ VALUE ir_initialize(int argc, VALUE* argv, VALUE self) {
21
+ VALUE value = Qnil;
22
+ if (rb_scan_args(argc, argv, "01", &value) == 1) {
23
+ value = argv[0];
24
+ }
25
+ DATA_PTR(self) = (void *) value;
26
+ return Qnil;
27
+ }
28
+
29
+ VALUE ir_get(VALUE self) {
30
+ #if HAVE_GCC_SYNC
31
+ __sync_synchronize();
32
+ #elif defined _MSC_VER
33
+ MemoryBarrier();
34
+ #elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
35
+ OSMemoryBarrier();
36
+ #endif
37
+ return (VALUE) DATA_PTR(self);
38
+ }
39
+
40
+ VALUE ir_set(VALUE self, VALUE new_value) {
41
+ DATA_PTR(self) = (void *) new_value;
42
+ #if HAVE_GCC_SYNC
43
+ __sync_synchronize();
44
+ #elif defined _MSC_VER
45
+ MemoryBarrier();
46
+ #elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
47
+ OSMemoryBarrier();
48
+ #endif
49
+ return new_value;
50
+ }
51
+
52
+ VALUE ir_get_and_set(VALUE self, VALUE new_value) {
53
+ VALUE old_value = ir_get(self);
54
+ ir_set(self, new_value);
55
+ return old_value;
56
+ }
57
+
58
+ VALUE ir_compare_and_set(volatile VALUE self, VALUE expect_value, VALUE new_value) {
59
+ #if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
60
+ if (OSAtomicCompareAndSwap64(expect_value, new_value, &DATA_PTR(self))) {
61
+ return Qtrue;
62
+ }
63
+ #elif defined(__sun)
64
+ /* Assuming VALUE is uintptr_t */
65
+ /* Based on the definition of uintptr_t from /usr/include/sys/int_types.h */
66
+ #if defined(_LP64) || defined(_I32LPx)
67
+ /* 64-bit: uintptr_t === unsigned long */
68
+ if (atomic_cas_ulong((uintptr_t *) &DATA_PTR(self), expect_value, new_value)) {
69
+ return Qtrue;
70
+ }
71
+ #else
72
+ /* 32-bit: uintptr_t === unsigned int */
73
+ if (atomic_cas_uint((uintptr_t *) &DATA_PTR(self), expect_value, new_value)) {
74
+ return Qtrue;
75
+ }
76
+ #endif
77
+ #elif defined _MSC_VER && defined _M_AMD64
78
+ if (InterlockedCompareExchange64((LONGLONG*)&DATA_PTR(self), new_value, expect_value)) {
79
+ return Qtrue;
80
+ }
81
+ #elif defined _MSC_VER && defined _M_IX86
82
+ if (InterlockedCompareExchange((LONG*)&DATA_PTR(self), new_value, expect_value)) {
83
+ return Qtrue;
84
+ }
85
+ #else
86
+ if (__sync_bool_compare_and_swap(&DATA_PTR(self), expect_value, new_value)) {
87
+ return Qtrue;
88
+ }
89
+ #endif
90
+ return Qfalse;
91
+ }
@@ -0,0 +1,20 @@
1
+ #ifndef __ATOMIC_REFERENCE_H__
2
+ #define __ATOMIC_REFERENCE_H__
3
+
4
+ #if defined(__sun)
5
+ #include <atomic.h>
6
+ #endif
7
+
8
+ #ifdef HAVE_LIBKERN_OSATOMIC_H
9
+ #include <libkern/OSAtomic.h>
10
+ #endif
11
+
12
+ void ir_mark(void*);
13
+ VALUE ir_alloc(VALUE);
14
+ VALUE ir_initialize(int, VALUE*, VALUE);
15
+ VALUE ir_get(VALUE);
16
+ VALUE ir_set(VALUE, VALUE);
17
+ VALUE ir_get_and_set(VALUE, VALUE);
18
+ VALUE ir_compare_and_set(volatile VALUE, VALUE, VALUE);
19
+
20
+ #endif
@@ -0,0 +1,58 @@
1
+ require 'fileutils'
2
+
3
+ $:.push File.join(File.dirname(__FILE__), '../../lib')
4
+ require 'extension_helper'
5
+
6
+ EXTENSION_NAME = 'concurrent_ruby_ext'
7
+
8
+ def create_dummy_makefile
9
+ File.open('Makefile', 'w') do |f|
10
+ f.puts 'all:'
11
+ f.puts 'install:'
12
+ end
13
+ end
14
+
15
+ if defined?(JRUBY_VERSION) || ! Concurrent.allow_c_extensions?
16
+ create_dummy_makefile
17
+ warn 'C optimizations are not supported on this version of Ruby.'
18
+ else
19
+ begin
20
+
21
+ require 'mkmf'
22
+ dir_config(EXTENSION_NAME)
23
+
24
+ have_header "libkern/OSAtomic.h"
25
+
26
+ def compiler_is_gcc
27
+ if CONFIG["GCC"] && CONFIG["GCC"] != ""
28
+ return true
29
+ elsif ( # This could stand to be more generic... but I am afraid.
30
+ CONFIG["CC"] =~ /\bgcc\b/
31
+ )
32
+ return true
33
+ end
34
+ return false
35
+ end
36
+
37
+ if compiler_is_gcc
38
+ case CONFIG["arch"]
39
+ when /mswin32|mingw|solaris/
40
+ $CFLAGS += " -march=native"
41
+ when 'i686-linux'
42
+ $CFLAGS += " -march=i686"
43
+ end
44
+ end
45
+
46
+ try_run(<<CODE,$CFLAGS) && ($defs << '-DHAVE_GCC_SYNC')
47
+ int main() {
48
+ __sync_synchronize();
49
+ return 0;
50
+ }
51
+ CODE
52
+
53
+ create_makefile(EXTENSION_NAME)
54
+ rescue
55
+ create_dummy_makefile
56
+ warn 'C optimizations cannot be compiled on this version of Ruby.'
57
+ end
58
+ end
@@ -0,0 +1,57 @@
1
+ #include <ruby.h>
2
+
3
+ #include "atomic_reference.h"
4
+ #include "atomic_boolean.h"
5
+ #include "atomic_fixnum.h"
6
+
7
+ // module and class definitions
8
+
9
+ static VALUE rb_mConcurrent;
10
+ static VALUE rb_cAtomic;
11
+ static VALUE rb_cAtomicBoolean;
12
+ static VALUE rb_cAtomicFixnum;
13
+
14
+ // Init_concurrent_ruby_ext
15
+
16
+ void Init_concurrent_ruby_ext() {
17
+
18
+ // define modules and classes
19
+ rb_mConcurrent = rb_define_module("Concurrent");
20
+ rb_cAtomic = rb_define_class_under(rb_mConcurrent, "CAtomic", rb_cObject);
21
+ rb_cAtomicBoolean = rb_define_class_under(rb_mConcurrent, "CAtomicBoolean", rb_cObject);
22
+ rb_cAtomicFixnum = rb_define_class_under(rb_mConcurrent, "CAtomicFixnum", rb_cObject);
23
+
24
+ // CAtomic
25
+ rb_define_alloc_func(rb_cAtomic, ir_alloc);
26
+ rb_define_method(rb_cAtomic, "initialize", ir_initialize, -1);
27
+ rb_define_method(rb_cAtomic, "get", ir_get, 0);
28
+ rb_define_method(rb_cAtomic, "set", ir_set, 1);
29
+ rb_define_method(rb_cAtomic, "get_and_set", ir_get_and_set, 1);
30
+ rb_define_method(rb_cAtomic, "_compare_and_set", ir_compare_and_set, 2);
31
+ rb_define_alias(rb_cAtomic, "value", "get");
32
+ rb_define_alias(rb_cAtomic, "value=", "set");
33
+ rb_define_alias(rb_cAtomic, "swap", "get_and_set");
34
+
35
+ // CAtomicBoolean
36
+ rb_define_alloc_func(rb_cAtomicBoolean, atomic_boolean_allocate);
37
+ rb_define_method(rb_cAtomicBoolean, "initialize", method_atomic_boolean_initialize, -1);
38
+ rb_define_method(rb_cAtomicBoolean, "value", method_atomic_boolean_value, 0);
39
+ rb_define_method(rb_cAtomicBoolean, "value=", method_atomic_boolean_value_set, 1);
40
+ rb_define_method(rb_cAtomicBoolean, "true?", method_atomic_boolean_true_question, 0);
41
+ rb_define_method(rb_cAtomicBoolean, "false?", method_atomic_boolean_false_question, 0);
42
+ rb_define_method(rb_cAtomicBoolean, "make_true", method_atomic_boolean_make_true, 0);
43
+ rb_define_method(rb_cAtomicBoolean, "make_false", method_atomic_boolean_make_false, 0);
44
+
45
+ // CAtomicFixnum
46
+ rb_define_const(rb_cAtomicFixnum, "MIN_VALUE", LL2NUM(LLONG_MIN));
47
+ rb_define_const(rb_cAtomicFixnum, "MAX_VALUE", LL2NUM(LLONG_MAX));
48
+ rb_define_alloc_func(rb_cAtomicFixnum, atomic_fixnum_allocate);
49
+ rb_define_method(rb_cAtomicFixnum, "initialize", method_atomic_fixnum_initialize, -1);
50
+ rb_define_method(rb_cAtomicFixnum, "value", method_atomic_fixnum_value, 0);
51
+ rb_define_method(rb_cAtomicFixnum, "value=", method_atomic_fixnum_value_set, 1);
52
+ rb_define_method(rb_cAtomicFixnum, "increment", method_atomic_fixnum_increment, 0);
53
+ rb_define_method(rb_cAtomicFixnum, "decrement", method_atomic_fixnum_decrement, 0);
54
+ rb_define_method(rb_cAtomicFixnum, "compare_and_set", method_atomic_fixnum_compare_and_set, 2);
55
+ rb_define_alias(rb_cAtomicFixnum, "up", "increment");
56
+ rb_define_alias(rb_cAtomicFixnum, "down", "decrement");
57
+ }
@@ -0,0 +1,28 @@
1
+ #ifndef rb_check_arity
2
+
3
+ // https://github.com/ruby/ruby/blob/ruby_2_0_0/include/ruby/intern.h
4
+ // rb_check_arity was added in Ruby 2.0
5
+
6
+ #define UNLIMITED_ARGUMENTS (-1)
7
+
8
+ static inline void rb_error_arity(int argc, int min, int max)
9
+ {
10
+ VALUE err_mess = 0;
11
+ if (min == max) {
12
+ err_mess = rb_sprintf("wrong number of arguments (%d for %d)", argc, min);
13
+ }
14
+ else if (max == UNLIMITED_ARGUMENTS) {
15
+ err_mess = rb_sprintf("wrong number of arguments (%d for %d+)", argc, min);
16
+ }
17
+ else {
18
+ err_mess = rb_sprintf("wrong number of arguments (%d for %d..%d)", argc, min, max);
19
+ }
20
+ rb_raise(rb_eTypeError, err_mess);
21
+ }
22
+
23
+ #define rb_check_arity(argc, min, max) do { \
24
+ if (((argc) < (min)) || ((argc) > (max) && (max) != UNLIMITED_ARGUMENTS)) \
25
+ rb_error_arity(argc, min, max); \
26
+ } while(0)
27
+
28
+ #endif
@@ -0,0 +1,8 @@
1
+ module Concurrent
2
+
3
+ # @!macro atomic_reference
4
+ class ConcurrentUpdateError < ThreadError
5
+ # frozen pre-allocated backtrace to speed ConcurrentUpdateError
6
+ CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze
7
+ end
8
+ end
@@ -0,0 +1,50 @@
1
+ require 'concurrent/atomic_reference/concurrent_update_error'
2
+
3
+ module Concurrent
4
+
5
+ # Define update methods that use direct paths
6
+ module AtomicDirectUpdate
7
+
8
+ # @!macro [attach] atomic_reference_method_update
9
+ #
10
+ # Pass the current value to the given block, replacing it
11
+ # with the block's result. May retry if the value changes
12
+ # during the block's execution.
13
+ #
14
+ # @yield [Object] Calculate a new value for the atomic reference using
15
+ # given (old) value
16
+ # @yieldparam [Object] old_value the starting value of the atomic reference
17
+ #
18
+ # @return [Object] the new value
19
+ def update
20
+ true until compare_and_set(old_value = get, new_value = yield(old_value))
21
+ new_value
22
+ end
23
+
24
+ # @!macro [attach] atomic_reference_method_try_update
25
+ #
26
+ # Pass the current value to the given block, replacing it
27
+ # with the block's result. Raise an exception if the update
28
+ # fails.
29
+ #
30
+ # @yield [Object] Calculate a new value for the atomic reference using
31
+ # given (old) value
32
+ # @yieldparam [Object] old_value the starting value of the atomic reference
33
+ #
34
+ # @return [Object] the new value
35
+ #
36
+ # @raise [Concurrent::ConcurrentUpdateError] if the update fails
37
+ def try_update
38
+ old_value = get
39
+ new_value = yield old_value
40
+ unless compare_and_set(old_value, new_value)
41
+ if $VERBOSE
42
+ raise ConcurrentUpdateError, "Update failed"
43
+ else
44
+ raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE
45
+ end
46
+ end
47
+ new_value
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,25 @@
1
+ module Concurrent
2
+
3
+ # Special "compare and set" handling of numeric values.
4
+ module AtomicNumericCompareAndSetWrapper
5
+
6
+ # @!macro atomic_reference_method_compare_and_set
7
+ def compare_and_set(old_value, new_value)
8
+ if old_value.kind_of? Numeric
9
+ while true
10
+ old = get
11
+
12
+ return false unless old.kind_of? Numeric
13
+
14
+ return false unless old == old_value
15
+
16
+ result = _compare_and_set(old, new_value)
17
+ return result if result
18
+ end
19
+ else
20
+ _compare_and_set(old_value, new_value)
21
+ end
22
+ end
23
+ alias_method :compare_and_swap, :compare_and_set
24
+ end
25
+ end
Binary file
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: concurrent-ruby-ext
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.pre1
5
+ platform: x86-solaris-2.11
6
+ authors:
7
+ - Jerry D'Antonio
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: concurrent-ruby
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.0.pre1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.0.pre1
27
+ description: |2
28
+ Modern concurrency tools including agents, futures, promises, thread pools, actors, supervisors, and more.
29
+ Inspired by Erlang, Clojure, Go, JavaScript, actors, and classic concurrency patterns.
30
+ email: jerry.dantonio@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files:
34
+ - README.md
35
+ - LICENSE.txt
36
+ - CHANGELOG.md
37
+ files:
38
+ - CHANGELOG.md
39
+ - LICENSE.txt
40
+ - README.md
41
+ - ext/concurrent_ruby_ext/atomic_boolean.c
42
+ - ext/concurrent_ruby_ext/atomic_boolean.h
43
+ - ext/concurrent_ruby_ext/atomic_fixnum.c
44
+ - ext/concurrent_ruby_ext/atomic_fixnum.h
45
+ - ext/concurrent_ruby_ext/atomic_reference.c
46
+ - ext/concurrent_ruby_ext/atomic_reference.h
47
+ - ext/concurrent_ruby_ext/extconf.rb
48
+ - ext/concurrent_ruby_ext/rb_concurrent.c
49
+ - ext/concurrent_ruby_ext/ruby_193_compatible.h
50
+ - lib/concurrent/atomic_reference/concurrent_update_error.rb
51
+ - lib/concurrent/atomic_reference/direct_update.rb
52
+ - lib/concurrent/atomic_reference/numeric_cas_wrapper.rb
53
+ - lib/concurrent_ruby_ext.so
54
+ homepage: http://www.concurrent-ruby.com
55
+ licenses:
56
+ - MIT
57
+ metadata: {}
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 1.9.3
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">"
70
+ - !ruby/object:Gem::Version
71
+ version: 1.3.1
72
+ requirements: []
73
+ rubyforge_project:
74
+ rubygems_version: 2.2.2
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: C extensions to optimize concurrent-ruby under MRI.
78
+ test_files: []