From e597e04b51533ec3b57fef9689699fcc63883f61 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Tue, 9 Dec 2014 22:45:01 -0500 Subject: [PATCH 01/25] Builds two gems from one repo. Specs and docs need updated. --- Gemfile | 2 +- Rakefile | 46 ++++++++++++++++++------ concurrent-ruby-ext.gemspec | 30 ++++++++++++++++ concurrent-ruby.gemspec | 9 ++--- examples/atomic_example.rb | 2 +- examples/bench_atomic.rb | 3 +- examples/bench_atomic_1.rb | 6 +++- examples/benchmark_atomic_boolean.rb | 2 +- examples/benchmark_atomic_fixnum.rb | 2 +- lib/concurrent/atomic.rb | 3 +- lib/concurrent/atomic/atomic_boolean.rb | 3 +- lib/concurrent/atomic/atomic_fixnum.rb | 3 +- lib/concurrent/atomic_reference/jruby.rb | 1 - lib/concurrent/atomic_reference/ruby.rb | 10 ------ lib/concurrent/version.rb | 2 +- lib/extension_helper.rb | 42 ++++++++++++---------- 16 files changed, 106 insertions(+), 60 deletions(-) create mode 100644 concurrent-ruby-ext.gemspec diff --git a/Gemfile b/Gemfile index 848592d37..abfcd79c1 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gemspec +gemspec name: 'concurrent-ruby' group :development do gem 'rake', '~> 10.3.2' diff --git a/Rakefile b/Rakefile index 094554f72..76489bed0 100644 --- a/Rakefile +++ b/Rakefile @@ -1,12 +1,7 @@ -require 'bundler/gem_tasks' -require 'rake/extensiontask' -require 'rake/javaextensiontask' - -GEMSPEC = Gem::Specification.load('concurrent-ruby.gemspec') +CORE_GEMSPEC = Gem::Specification.load('concurrent-ruby.gemspec') +EXT_GEMSPEC = Gem::Specification.load('concurrent-ruby-ext.gemspec') EXTENSION_NAME = 'concurrent_ruby_ext' -Bundler::GemHelper.install_tasks - $:.push File.join(File.dirname(__FILE__), 'lib') require 'extension_helper' @@ -23,20 +18,22 @@ Dir.glob('tasks/**/*.rake').each do |rakefile| safe_load rakefile end -desc 'Run benchmarks' +#desc 'Run benchmarks' task :bench do exec 'ruby -Ilib -Iext examples/bench_atomic.rb' end if defined?(JRUBY_VERSION) + require 'rake/javaextensiontask' - Rake::JavaExtensionTask.new(EXTENSION_NAME, GEMSPEC) do |ext| + Rake::JavaExtensionTask.new(EXTENSION_NAME, CORE_GEMSPEC) do |ext| ext.ext_dir = 'ext' end elsif Concurrent.allow_c_extensions? + require 'rake/extensiontask' - Rake::ExtensionTask.new(EXTENSION_NAME, GEMSPEC) do |ext| + Rake::ExtensionTask.new(EXTENSION_NAME, EXT_GEMSPEC) do |ext| ext.ext_dir = "ext/#{EXTENSION_NAME}" ext.cross_compile = true ext.cross_platform = ['x86-mingw32', 'x64-mingw32'] @@ -61,7 +58,6 @@ elsif Concurrent.allow_c_extensions? else task :clean task :compile - task "compile:#{EXTENSION_NAME}" end Rake::Task[:clean].enhance do @@ -71,6 +67,7 @@ Rake::Task[:clean].enhance do rm_rf 'lib/2.0' rm_f Dir.glob('./lib/*.jar') rm_f Dir.glob('./**/*.bundle') + mkdir_p 'pkg' end begin @@ -85,3 +82,30 @@ begin rescue LoadError puts 'Error loading Rspec rake tasks, probably building the gem...' end + +namespace :build do + + build_deps = [:clean] + build_deps << :compile if defined?(JRUBY_VERSION) + + desc 'Build the concurrent-ruby gem' + task :core => build_deps do + sh "gem build #{CORE_GEMSPEC.name}.gemspec" + sh 'mv *.gem pkg/' + Rake::Task[:clean].execute + end + + if Concurrent.allow_c_extensions? + desc 'Build the concurrent-ruby-ext gem' + task :ext => [:clean, :compile] do + sh "gem build #{EXT_GEMSPEC.name}.gemspec" + sh 'mv *.gem pkg/' + Rake::Task[:clean].execute + end + else + task :ext + end +end + +desc 'Build all gems for this platform' +task :build => ['build:core', 'build:ext'] diff --git a/concurrent-ruby-ext.gemspec b/concurrent-ruby-ext.gemspec new file mode 100644 index 000000000..f09fb562b --- /dev/null +++ b/concurrent-ruby-ext.gemspec @@ -0,0 +1,30 @@ +Gem::Specification.new do |s| + s.name = 'concurrent-ruby-ext' + s.version = '0.1.0.pre1' + s.platform = Gem::Platform::RUBY + s.author = "Jerry D'Antonio" + s.email = 'jerry.dantonio@gmail.com' + s.homepage = 'http://www.concurrent-ruby.com' + s.summary = 'C extensions to optimize concurrent-ruby under MRI.' + s.license = 'MIT' + s.date = Time.now.strftime('%Y-%m-%d') + + s.description = <<-EOF + Modern concurrency tools including agents, futures, promises, thread pools, actors, supervisors, and more. + Inspired by Erlang, Clojure, Go, JavaScript, actors, and classic concurrency patterns. + EOF + + s.files = Dir['ext/**/*.{h,c,cpp}'] + s.files += [ + 'lib/concurrent/atomic_reference/concurrent_update_error.rb', + 'lib/concurrent/atomic_reference/direct_update.rb', + 'lib/concurrent/atomic_reference/numeric_cas_wrapper.rb', + ] + s.extra_rdoc_files = Dir['README*', 'LICENSE*', 'CHANGELOG*'] + s.require_paths = ['lib'] + s.extensions = 'ext/concurrent_ruby_ext/extconf.rb' + + s.required_ruby_version = '>= 1.9.3' + + s.add_runtime_dependency 'concurrent-ruby', '~> 0.8.0.pre1' +end diff --git a/concurrent-ruby.gemspec b/concurrent-ruby.gemspec index 63f7142f3..7ffbe62b4 100644 --- a/concurrent-ruby.gemspec +++ b/concurrent-ruby.gemspec @@ -25,14 +25,9 @@ Gem::Specification.new do |s| if defined?(JRUBY_VERSION) s.files += Dir['lib/concurrent_ruby_ext.jar'] s.platform = 'java' - elsif ! ENV['BUILD_PURE_RUBY'] - s.extensions = 'ext/concurrent_ruby_ext/extconf.rb' - s.files += Dir['ext/**/*.{h,c,cpp}'] + else + s.add_runtime_dependency 'ref', '~> 1.0', '>= 1.0.5' end s.required_ruby_version = '>= 1.9.3' - - unless defined?(JRUBY_VERSION) - s.add_dependency 'ref', '~> 1.0.5' - end end diff --git a/examples/atomic_example.rb b/examples/atomic_example.rb index 5debe298f..0c97b2c24 100644 --- a/examples/atomic_example.rb +++ b/examples/atomic_example.rb @@ -1,4 +1,4 @@ -require 'concurrent' +require 'concurrent/atomic' my_atomic = Concurrent::Atomic.new(0) my_atomic.update {|v| v + 1} diff --git a/examples/bench_atomic.rb b/examples/bench_atomic.rb index f4b164eb0..a5701f643 100644 --- a/examples/bench_atomic.rb +++ b/examples/bench_atomic.rb @@ -1,7 +1,8 @@ require 'benchmark' require 'rbconfig' require 'thread' -require 'concurrent' +require 'concurrent/atomic' + Thread.abort_on_exception = true $go = false # for synchronizing parallel threads diff --git a/examples/bench_atomic_1.rb b/examples/bench_atomic_1.rb index c945e75ea..5f5585e49 100644 --- a/examples/bench_atomic_1.rb +++ b/examples/bench_atomic_1.rb @@ -6,7 +6,11 @@ require 'thread' require 'benchmark' -require 'concurrent' +begin + require 'concurrent-ext' +rescue LoadError + require 'concurrent' +end Thread.abort_on_exception = true diff --git a/examples/benchmark_atomic_boolean.rb b/examples/benchmark_atomic_boolean.rb index 6f6fda918..29e17069f 100755 --- a/examples/benchmark_atomic_boolean.rb +++ b/examples/benchmark_atomic_boolean.rb @@ -2,7 +2,7 @@ $:.push File.join(File.dirname(__FILE__), '../lib') -require 'concurrent' +require 'concurrent/atomics' require 'benchmark' require 'rbconfig' diff --git a/examples/benchmark_atomic_fixnum.rb b/examples/benchmark_atomic_fixnum.rb index f1c5c081f..f096c6d2a 100755 --- a/examples/benchmark_atomic_fixnum.rb +++ b/examples/benchmark_atomic_fixnum.rb @@ -2,7 +2,7 @@ $:.push File.join(File.dirname(__FILE__), '../lib') -require 'concurrent' +require 'concurrent/atomics' require 'benchmark' require 'rbconfig' diff --git a/lib/concurrent/atomic.rb b/lib/concurrent/atomic.rb index ab65c2bae..d18172b80 100644 --- a/lib/concurrent/atomic.rb +++ b/lib/concurrent/atomic.rb @@ -12,6 +12,7 @@ end ##################################################################### +require_relative '../extension_helper' require 'concurrent/atomic_reference/concurrent_update_error' require 'concurrent/atomic_reference/mutex_atomic' @@ -77,7 +78,7 @@ class Concurrent::Atomic < Concurrent::JavaAtomic class Concurrent::Atomic < Concurrent::RbxAtomic end -elsif Concurrent.allow_c_native_class?('CAtomic') +elsif defined?(CAtomic) # @!macro atomic_reference class Concurrent::Atomic < Concurrent::CAtomic diff --git a/lib/concurrent/atomic/atomic_boolean.rb b/lib/concurrent/atomic/atomic_boolean.rb index 2e88b2414..7bcdfe6e4 100644 --- a/lib/concurrent/atomic/atomic_boolean.rb +++ b/lib/concurrent/atomic/atomic_boolean.rb @@ -1,5 +1,4 @@ require_relative '../../extension_helper' -Concurrent.safe_require_c_extensions module Concurrent @@ -162,7 +161,7 @@ def make_false class AtomicBoolean < JavaAtomicBoolean end - elsif Concurrent.allow_c_native_class?('CAtomicBoolean') + elsif defined?(CAtomicBoolean) # @!macro atomic_boolean class CAtomicBoolean diff --git a/lib/concurrent/atomic/atomic_fixnum.rb b/lib/concurrent/atomic/atomic_fixnum.rb index 31863112f..87e474e8e 100644 --- a/lib/concurrent/atomic/atomic_fixnum.rb +++ b/lib/concurrent/atomic/atomic_fixnum.rb @@ -1,5 +1,4 @@ require_relative '../../extension_helper' -Concurrent.safe_require_c_extensions module Concurrent @@ -166,7 +165,7 @@ def compare_and_set(expect, update) class AtomicFixnum < JavaAtomicFixnum end - elsif Concurrent.allow_c_native_class?('CAtomicFixnum') + elsif defined?(CAtomicFixnum) # @!macro atomic_fixnum class CAtomicFixnum diff --git a/lib/concurrent/atomic_reference/jruby.rb b/lib/concurrent/atomic_reference/jruby.rb index 7533aec01..adb7e23e4 100644 --- a/lib/concurrent/atomic_reference/jruby.rb +++ b/lib/concurrent/atomic_reference/jruby.rb @@ -1,5 +1,4 @@ require_relative '../../extension_helper' -Concurrent.safe_require_java_extensions if defined?(Concurrent::JavaAtomic) require 'concurrent/atomic_reference/direct_update' diff --git a/lib/concurrent/atomic_reference/ruby.rb b/lib/concurrent/atomic_reference/ruby.rb index 437e1d3e4..b35d67bc0 100644 --- a/lib/concurrent/atomic_reference/ruby.rb +++ b/lib/concurrent/atomic_reference/ruby.rb @@ -1,14 +1,4 @@ require_relative '../../extension_helper' - -if Concurrent.allow_c_extensions? - begin - require 'concurrent_ruby_ext' - rescue LoadError - # may be a Windows cross-compiled native gem - require "#{RUBY_VERSION[0..2]}/concurrent_ruby_ext" - end -end - require 'concurrent/atomic_reference/direct_update' require 'concurrent/atomic_reference/numeric_cas_wrapper' diff --git a/lib/concurrent/version.rb b/lib/concurrent/version.rb index f0e3f6e3c..387fd018e 100644 --- a/lib/concurrent/version.rb +++ b/lib/concurrent/version.rb @@ -1,3 +1,3 @@ module Concurrent - VERSION = '0.7.2' + VERSION = '0.8.0.pre3' end diff --git a/lib/extension_helper.rb b/lib/extension_helper.rb index a342b598f..8f53d3c9a 100644 --- a/lib/extension_helper.rb +++ b/lib/extension_helper.rb @@ -1,28 +1,32 @@ module Concurrent + + @@c_ext_loaded ||= false + @@java_ext_loaded ||= false # @!visibility private def self.allow_c_extensions? defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby' end - # @!visibility private - def self.allow_c_native_class?(clazz) - allow_c_extensions? && Concurrent.const_defined?(clazz) - rescue - false - end - - # @!visibility private - def self.safe_require_c_extensions - require 'concurrent_ruby_ext' if allow_c_extensions? - rescue LoadError - #warn 'Attempted to load C extensions on unsupported platform. Continuing with pure-Ruby.' - end - - # @!visibility private - def self.safe_require_java_extensions - require 'concurrent_ruby_ext' if RUBY_PLATFORM == 'java' - rescue LoadError - #warn 'Attempted to load Java extensions on unsupported platform. Continuing with pure-Ruby.' + if allow_c_extensions? && !@@c_ext_loaded + begin + require 'concurrent_ruby_ext' + @@c_ext_loaded = true + rescue LoadError + # may be a Windows cross-compiled native gem + begin + require "#{RUBY_VERSION[0..2]}/concurrent_ruby_ext" + @@c_ext_loaded = true + rescue LoadError + warn 'Performance on MRI may be improved with the concurrent-ruby-ext gem. Please see http://concurrent-ruby.com' + end + end + elsif RUBY_PLATFORM == 'java' && !@@java_ext_loaded + begin + require 'concurrent_ruby_ext' + @@java_ext_loaded = true + rescue LoadError + #warn 'Attempted to load Java extensions on unsupported platform. Continuing with pure-Ruby.' + end end end From 7fc55eccb8461833f4b021b2d6c949565d02fecb Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Wed, 10 Dec 2014 23:08:07 -0500 Subject: [PATCH 02/25] Fixed broken CAtomic specs. --- .travis.yml | 2 +- lib/concurrent/atomic.rb | 2 +- spec/concurrent/atomic_spec.rb | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9d62e0051..aaf9ecca8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,4 +25,4 @@ matrix: - rvm: jruby-head - rvm: 1.9.3 -script: "bundle exec rake compile && bundle exec rspec --color --backtrace --tag ~unfinished --seed 1 --format documentation ./spec" +script: "rake compile && bundle exec rspec --color --backtrace --tag ~unfinished --seed 1 --format documentation ./spec" diff --git a/lib/concurrent/atomic.rb b/lib/concurrent/atomic.rb index d18172b80..bc0b80d7a 100644 --- a/lib/concurrent/atomic.rb +++ b/lib/concurrent/atomic.rb @@ -78,7 +78,7 @@ class Concurrent::Atomic < Concurrent::JavaAtomic class Concurrent::Atomic < Concurrent::RbxAtomic end -elsif defined?(CAtomic) +elsif defined?(Concurrent::CAtomic) # @!macro atomic_reference class Concurrent::Atomic < Concurrent::CAtomic diff --git a/spec/concurrent/atomic_spec.rb b/spec/concurrent/atomic_spec.rb index f7343a9b9..4d9912a51 100644 --- a/spec/concurrent/atomic_spec.rb +++ b/spec/concurrent/atomic_spec.rb @@ -154,19 +154,19 @@ module Concurrent describe Atomic do if TestHelpers.jruby? it 'inherits from JavaAtomic' do - expect(Atomic.ancestors).to include(JavaAtomic) + expect(Atomic.ancestors).to include(Concurrent::JavaAtomic) end elsif TestHelpers.use_c_extensions? it 'inherits from CAtomic' do - expect(Atomic.ancestors).to include(CAtomic) + expect(Atomic.ancestors).to include(Concurrent::CAtomic) end elsif TestHelpers.rbx? it 'inherits from RbxAtomic' do - expect(Atomic.ancestors).to include(RbxAtomic) + expect(Atomic.ancestors).to include(Concurrent::RbxAtomic) end else it 'inherits from MutexAtomic' do - expect(Atomic.ancestors).to include(MutexAtomic) + expect(Atomic.ancestors).to include(Concurrent::MutexAtomic) end end end From be255429d0afe942046391d066ed882eb3a16f48 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Wed, 10 Dec 2014 23:37:01 -0500 Subject: [PATCH 03/25] Updated README with information regarding concurrent-ruby-ext --- README.md | 94 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 73c374264..f5101d632 100644 --- a/README.md +++ b/README.md @@ -38,9 +38,7 @@ ### Supported Ruby versions MRI 1.9.3, 2.0, 2.1, JRuby (1.9 mode), and Rubinius 2.x are supported. -Although native code is used for performance optimizations on some platforms, all functionality -is available in pure Ruby. This gem should be fully compatible with any interpreter that is -compliant with Ruby 1.9.3 or newer. +This gem should be fully compatible with any interpreter that is compliant with Ruby 1.9.3 or newer. ## Features & Documentation @@ -62,6 +60,7 @@ This library contains a variety of concurrency abstractions at high and low leve * [Promise](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Promise.html): Similar to Futures, with more features. * [ScheduledTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ScheduledTask.html): Like a Future scheduled for a specific future time. * [TimerTask](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TimerTask.html): A Thread that periodically wakes up to perform work at regular intervals. +* [Channel](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Channel.html): Communicating Sequential Processes (CSP). ### Java-inspired ThreadPools and other executors @@ -98,28 +97,45 @@ Lower-level abstractions mainly used as building blocks. * [thread-local variables](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ThreadLocalVar.html) * [software transactional memory](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/TVar.html) (TVar) -## Installing and Building +## Usage -This gem includes several platform-specific optimizations. To reduce the possibility of -compilation errors, we provide pre-compiled gem packages for several platforms as well -as a pure-Ruby build. Installing the gem should be no different than installing any other -Rubygems-hosted gem. Rubygems will automatically detect your platform and install the -appropriate pre-compiled build. You should never see Rubygems attempt to compile the gem -on installation. Additionally, to ensure compatability with the largest possible number -of Ruby interpreters, the C extensions will *never* load under any Ruby other than MRI, -even when installed. +All abstractions within this gem can be loaded simply by requiring it: -The following gem builds will be built at every release: +```ruby +require 'concurrent' +``` -* concurrent-ruby-x.y.z.gem (pure Ruby) -* concurrent-ruby-x.y.z-java.gem (JRuby) -* concurrent-ruby-x.y.z-x86-linux.gem (Linux 32-bit) -* concurrent-ruby-x.y.z-x86_64-linux.gem (Linux 64-bit) -* concurrent-ruby-x.y.z-x86-mingw32.gem (Windows 32-bit) -* concurrent-ruby-x.y.z-x64-mingw32.gem (Windows 64-bit) -* concurrent-ruby-x.y.z-x86-solaris-2.11.gem (Solaris) +To reduce the amount of code loaded at runtime, subsets of this gem can be required: -### Installing +```ruby +require 'concurrent' # everything + +# groups + +require 'concurrent/actor' # Concurrent::Actor and supporting code +require 'concurrent/atomics' # atomic and thread synchronization classes +require 'concurrent/channels' # Concurrent::Channel and supporting code +require 'concurrent/executors' # Thread pools and other executors +require 'concurrent/utilities' # utility methods such as processor count and timers + +# individual abstractions + +require 'concurrent/agent' # Concurrent::Agent +require 'concurrent/async' # Concurrent::Async +require 'concurrent/atomic' # Concurrent::Atomic (formerly the `atomic` gem) +require 'concurrent/dataflow' # Concurrent::dataflow +require 'concurrent/delay' # Concurrent::Delay +require 'concurrent/exchanger' # Concurrent::Exchanger +require 'concurrent/future' # Concurrent::Future +require 'concurrent/ivar' # Concurrent::IVar +require 'concurrent/mvar' # Concurrent::MVar +require 'concurrent/promise' # Concurrent::Promise +require 'concurrent/scheduled_task' # Concurrent::ScheduledTask +require 'concurrent/timer_task' # Concurrent::TimerTask +require 'concurrent/tvar' # Concurrent::TVar +``` + +## Installation ```shell gem install concurrent-ruby @@ -133,33 +149,34 @@ gem 'concurrent-ruby' and run `bundle install` from your shell. -### Building +### C Extensions for MRI -Because we provide pre-compiled gem builds, users should never need to build the gem manually. -The build process for this gem is completely automated using open source tools. All of -the automation components are available in the [ruby-concurrency/rake-compiler-dev-box](https://github.com/ruby-concurrency/rake-compiler-dev-box) -GitHub repository. +Potential performance improvements may be achieved under MRI by installing optional C extensions. +To minimize installation errors the C extensions are available in the `concurrent-ruby-ext` extension +gem. The extension gem lists `concurrent-ruby` as a dependency so it is not necessary to install both. +Simply install the extension gen: -This gem will compile native C code under MRI and native Java code under JRuby. It is -also possible to build a pure-Ruby version. All builds have identical functionality. -The only difference is performance. Additionally, pure-Ruby classes are always available, -even when using the native optimizations. Please see the [documentation](http://ruby-concurrency.github.io/concurrent-ruby/) -for more details. +```shell +gem install concurrent-ruby-ext +``` -To build and package the gem using MRI or JRuby, install the necessary build dependencies and run: +or add the following line to Gemfile: -```shell -bundle exec rake compile -bundle exec rake build +```ruby +gem 'concurrent-ruby-ext' ``` -To build and package a pure-Ruby gem, on *any* platform and interpreter -(including MRI and JRuby), run: +and run `bundle install` from your shell. + +In code it is only necessary to ```shell -BUILD_PURE_RUBY='true' bundle exec rake build +require 'concurrent' ``` +The `concurrent-ruby` gem will automatically detect the presence of the `concurrent-ruby-ext` gem +and load the appropriate C extensions. + ## Maintainers * [Jerry D'Antonio](https://github.com/jdantonio) @@ -167,6 +184,7 @@ BUILD_PURE_RUBY='true' bundle exec rake build * [Chris Seaton](https://github.com/chrisseaton) * [Lucas Allan](https://github.com/lucasallan) * [Petr Chalupa](https://github.com/pitr-ch) +* [Paweł Obrok](https://github.com/obrok) ### Contributing From 011851d3957276e6fe38492a4dafff30fa327d3d Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Sat, 13 Dec 2014 23:50:30 -0500 Subject: [PATCH 04/25] Fixed bug with CAtomic erroneously being defined in pure-Ruby gem. --- Rakefile | 3 +- concurrent-ruby.gemspec | 2 +- lib/concurrent/atomic.rb | 2 +- lib/concurrent/atomic_reference/ruby.rb | 38 +++++++++++++------------ 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/Rakefile b/Rakefile index 76489bed0..8f51a8728 100644 --- a/Rakefile +++ b/Rakefile @@ -65,8 +65,9 @@ Rake::Task[:clean].enhance do rm_rf 'tmp' rm_rf 'lib/1.9' rm_rf 'lib/2.0' - rm_f Dir.glob('./lib/*.jar') + rm_f Dir.glob('./**/*.so') rm_f Dir.glob('./**/*.bundle') + rm_f Dir.glob('./lib/*.jar') mkdir_p 'pkg' end diff --git a/concurrent-ruby.gemspec b/concurrent-ruby.gemspec index 7ffbe62b4..eb2912040 100644 --- a/concurrent-ruby.gemspec +++ b/concurrent-ruby.gemspec @@ -18,7 +18,7 @@ Gem::Specification.new do |s| Inspired by Erlang, Clojure, Go, JavaScript, actors, and classic concurrency patterns. EOF - s.files = Dir['lib/**/*'] + s.files = Dir['lib/**/*.rb'] s.extra_rdoc_files = Dir['README*', 'LICENSE*', 'CHANGELOG*'] s.require_paths = ['lib'] diff --git a/lib/concurrent/atomic.rb b/lib/concurrent/atomic.rb index bc0b80d7a..d6c2bd0bc 100644 --- a/lib/concurrent/atomic.rb +++ b/lib/concurrent/atomic.rb @@ -78,7 +78,7 @@ class Concurrent::Atomic < Concurrent::JavaAtomic class Concurrent::Atomic < Concurrent::RbxAtomic end -elsif defined?(Concurrent::CAtomic) +elsif defined? Concurrent::CAtomic # @!macro atomic_reference class Concurrent::Atomic < Concurrent::CAtomic diff --git a/lib/concurrent/atomic_reference/ruby.rb b/lib/concurrent/atomic_reference/ruby.rb index b35d67bc0..6f9b76631 100644 --- a/lib/concurrent/atomic_reference/ruby.rb +++ b/lib/concurrent/atomic_reference/ruby.rb @@ -1,27 +1,29 @@ -require_relative '../../extension_helper' -require 'concurrent/atomic_reference/direct_update' -require 'concurrent/atomic_reference/numeric_cas_wrapper' +if defined? Concurrent::CAtomic + require_relative '../../extension_helper' + require 'concurrent/atomic_reference/direct_update' + require 'concurrent/atomic_reference/numeric_cas_wrapper' -module Concurrent + module Concurrent - # @!macro atomic_reference - class CAtomic - include Concurrent::AtomicDirectUpdate - include Concurrent::AtomicNumericCompareAndSetWrapper + # @!macro atomic_reference + class CAtomic + include Concurrent::AtomicDirectUpdate + include Concurrent::AtomicNumericCompareAndSetWrapper - # @!method initialize - # @!macro atomic_reference_method_initialize + # @!method initialize + # @!macro atomic_reference_method_initialize - # @!method get - # @!macro atomic_reference_method_get + # @!method get + # @!macro atomic_reference_method_get - # @!method set - # @!macro atomic_reference_method_set + # @!method set + # @!macro atomic_reference_method_set - # @!method get_and_set - # @!macro atomic_reference_method_get_and_set + # @!method get_and_set + # @!macro atomic_reference_method_get_and_set - # @!method _compare_and_set - # @!macro atomic_reference_method_compare_and_set + # @!method _compare_and_set + # @!macro atomic_reference_method_compare_and_set + end end end From 57110e9af621f4b4da00943e483087df1c9df9a5 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Sun, 14 Dec 2014 08:27:55 -0500 Subject: [PATCH 05/25] Extension version number now a constant within lib --- concurrent-ruby-ext.gemspec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/concurrent-ruby-ext.gemspec b/concurrent-ruby-ext.gemspec index f09fb562b..2ea327ae3 100644 --- a/concurrent-ruby-ext.gemspec +++ b/concurrent-ruby-ext.gemspec @@ -1,6 +1,10 @@ +$:.push File.join(File.dirname(__FILE__), 'lib') + +require 'concurrent/version' + Gem::Specification.new do |s| s.name = 'concurrent-ruby-ext' - s.version = '0.1.0.pre1' + s.version = Concurrent::EXT_VERSION s.platform = Gem::Platform::RUBY s.author = "Jerry D'Antonio" s.email = 'jerry.dantonio@gmail.com' From cc75945b23004ab05e17fb1b5836cac9b7c6c1a5 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Sun, 14 Dec 2014 11:06:16 -0500 Subject: [PATCH 06/25] Created specs to test the various gem builds. --- build-tests/atomic_boolean_builds_spec.rb | 84 +++++++++++++++++ build-tests/atomic_fixnum_builds_spec.rb | 84 +++++++++++++++++ build-tests/example_group_extensions.rb | 7 ++ build-tests/platform_helpers.rb | 13 +++ build-tests/runner.rb | 105 ++++++++++++++++++++++ spec/spec_helper.rb | 4 + 6 files changed, 297 insertions(+) create mode 100644 build-tests/atomic_boolean_builds_spec.rb create mode 100644 build-tests/atomic_fixnum_builds_spec.rb create mode 100644 build-tests/example_group_extensions.rb create mode 100644 build-tests/platform_helpers.rb create mode 100755 build-tests/runner.rb diff --git a/build-tests/atomic_boolean_builds_spec.rb b/build-tests/atomic_boolean_builds_spec.rb new file mode 100644 index 000000000..e04231c76 --- /dev/null +++ b/build-tests/atomic_boolean_builds_spec.rb @@ -0,0 +1,84 @@ +require 'benchmark' +require_relative 'example_group_extensions' +require_relative 'platform_helpers' + +require 'concurrent/atomics' + +def atomic_boolean_test(clazz, opts = {}) + threads = opts.fetch(:threads, 5) + tests = opts.fetch(:tests, 100) + + atomic = Concurrent.const_get(clazz.to_s).new + latch = Concurrent::CountDownLatch.new(threads) + + stats = Benchmark.measure do + threads.times do |i| + Thread.new do + tests.times{ atomic.value = true } + latch.count_down + end + end + latch.wait + end + stats +end + +describe Concurrent::AtomicBoolean do + + let!(:threads) { 10 } + let!(:tests) { 1000 } + + describe Concurrent::MutexAtomicBoolean do + + specify 'is defined' do + expect(defined?(Concurrent::MutexAtomicBoolean)).to be_truthy + end + + specify 'runs the benchmarks' do + stats = atomic_boolean_test('MutexAtomicBoolean', threads: threads, tests: tests) + expect(stats).to be_benchmark_results + end + end + + if jruby? + + describe Concurrent::JavaAtomicBoolean do + + specify 'Concurrent::JavaAtomicBoolean is defined' do + expect(defined?(Concurrent::JavaAtomicBoolean)).to be_truthy + end + + specify 'runs the benchmarks' do + stats = atomic_boolean_test('JavaAtomicBoolean', threads: threads, tests: tests) + expect(stats).to be_benchmark_results + end + end + + else + + specify 'Concurrent::JavaAtomicBoolean is not defined' do + expect(defined?(Concurrent::JavaAtomicBoolean)).to be_falsey + end + end + + if 'EXT' == ENV['TEST_PLATFORM'] + + describe Concurrent::CAtomicBoolean do + + specify 'Concurrent::CAtomicBoolean is defined' do + expect(defined?(Concurrent::CAtomicBoolean)).to be_truthy + end + + specify 'runs the benchmarks' do + stats = atomic_boolean_test('CAtomicBoolean', threads: threads, tests: tests) + expect(stats).to be_benchmark_results + end + end + + else + + specify 'Concurrent::CAtomicBoolean is not defined' do + expect(defined?(Concurrent::CAtomicBoolean)).to be_falsey + end + end +end diff --git a/build-tests/atomic_fixnum_builds_spec.rb b/build-tests/atomic_fixnum_builds_spec.rb new file mode 100644 index 000000000..66e7f9324 --- /dev/null +++ b/build-tests/atomic_fixnum_builds_spec.rb @@ -0,0 +1,84 @@ +require 'benchmark' +require_relative 'example_group_extensions' +require_relative 'platform_helpers' + +require 'concurrent/atomics' + +def atomic_fixnum_test(clazz, opts = {}) + threads = opts.fetch(:threads, 5) + tests = opts.fetch(:tests, 100) + + atomic = Concurrent.const_get(clazz.to_s).new + latch = Concurrent::CountDownLatch.new(threads) + + stats = Benchmark.measure do + threads.times do |i| + Thread.new do + tests.times{ atomic.up } + latch.count_down + end + end + latch.wait + end + stats +end + +describe Concurrent::AtomicFixnum do + + let!(:threads) { 10 } + let!(:tests) { 1000 } + + describe Concurrent::MutexAtomicFixnum do + + specify 'is defined' do + expect(defined?(Concurrent::MutexAtomicFixnum)).to be_truthy + end + + specify 'runs the benchmarks' do + stats = atomic_fixnum_test('MutexAtomicFixnum', threads: threads, tests: tests) + expect(stats).to be_benchmark_results + end + end + + if jruby? + + describe Concurrent::JavaAtomicFixnum do + + specify 'Concurrent::JavaAtomicFixnum is defined' do + expect(defined?(Concurrent::JavaAtomicFixnum)).to be_truthy + end + + specify 'runs the benchmarks' do + stats = atomic_fixnum_test('JavaAtomicFixnum', threads: threads, tests: tests) + expect(stats).to be_benchmark_results + end + end + + else + + specify 'Concurrent::JavaAtomicFixnum is not defined' do + expect(defined?(Concurrent::JavaAtomicFixnum)).to be_falsey + end + end + + if 'EXT' == ENV['TEST_PLATFORM'] + + describe Concurrent::CAtomicFixnum do + + specify 'Concurrent::CAtomicFixnum is defined' do + expect(defined?(Concurrent::CAtomicFixnum)).to be_truthy + end + + specify 'runs the benchmarks' do + stats = atomic_fixnum_test('CAtomicFixnum', threads: threads, tests: tests) + expect(stats).to be_benchmark_results + end + end + + else + + specify 'Concurrent::CAtomicFixnum is not defined' do + expect(defined?(Concurrent::CAtomicFixnum)).to be_falsey + end + end +end diff --git a/build-tests/example_group_extensions.rb b/build-tests/example_group_extensions.rb new file mode 100644 index 000000000..f2dd88497 --- /dev/null +++ b/build-tests/example_group_extensions.rb @@ -0,0 +1,7 @@ +require 'benchmark' + +RSpec::Matchers.define :be_benchmark_results do + match do |actual| + actual.is_a? Benchmark::Tms + end +end diff --git a/build-tests/platform_helpers.rb b/build-tests/platform_helpers.rb new file mode 100644 index 000000000..e03e54cae --- /dev/null +++ b/build-tests/platform_helpers.rb @@ -0,0 +1,13 @@ +require 'rbconfig' + +def mri?(engine = RUBY_ENGINE) + engine == 'ruby' +end + +def jruby?(engine = RUBY_ENGINE) + engine == 'jruby' +end + +def rbx?(engine = RUBY_ENGINE) + engine == 'rbx' +end diff --git a/build-tests/runner.rb b/build-tests/runner.rb new file mode 100755 index 000000000..8a8661a29 --- /dev/null +++ b/build-tests/runner.rb @@ -0,0 +1,105 @@ +#!/usr/bin/env ruby + +if File.exist?('Gemfile') + puts <<-WARNING +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!! A Gemfile has been detected. This will likely cause some tests !! +!! to erroneously fail (RSpec + Bundler shenanigans!). You may need !! +!! to run tests from a different directory. !! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + WARNING +end + +$:.push File.join(File.dirname(__FILE__), '..', 'lib') + +require 'concurrent/version' +require_relative 'platform_helpers' + +EXT_PLATFORMS = { + 'i686-linux' => 'x86-linux', + 'x86_64-linux' => 'x86_64-linux', + 'x86-mingw32' => 'x86-mingw32', + 'x64-mingw32' => 'x64-mingw32', + 'i386-solaris2.11' => 'x86-solaris-2.11', + 'x86_64-darwin14.0' => 'x86_64-darwin-14', +} + +TEST_PATH = File.dirname(__FILE__) +PKG_PATH = File.join(File.dirname(__FILE__), '..', 'pkg') + +RSPEC = "rspec --default-path #{TEST_PATH} -fd --color --seed 0" + +UNINSTALL_GEMS_COMMAND = <<-CMD +gem uninstall -q -a -I concurrent-ruby-ext +gem uninstall -q -a -I concurrent-ruby +gem uninstall -q -a -I ref +CMD + +SUITE_BREAK = "######################################################################\n" +GEM_BREAK = "----------------------------------------------------------------------\n" + +def platform_specific_extensions?(platform = RUBY_PLATFORM) + EXT_PLATFORMS.keys.include?(platform) && + File.exists?("#{PKG_PATH}/#{extension_gem_name(platform)}") +end + +def extension_gem_name(platform = RUBY_PLATFORM) + platform = EXT_PLATFORMS.fetch(platform, '') + platform = '-' + platform unless platform.empty? + "concurrent-ruby-ext-#{Concurrent::EXT_VERSION}#{platform}.gem" +end + +def install_gems_command(ext, platform = '') + cmd = "gem install #{PKG_PATH}/concurrent-ruby-#{Concurrent::VERSION}.gem" + if ext + cmd << "\ngem install #{PKG_PATH}/#{extension_gem_name(platform)}" + end + cmd +end + +def install_java_gem_command + "gem install #{PKG_PATH}/concurrent-ruby-#{Concurrent::VERSION}-java.gem" +end + +def run_tests_cmd(file, ext, platform = '') + test_platform = if ext + 'EXT' + elsif jruby?(platform) + 'JRUBY' + else + 'RUBY' + end + + cmd = if jruby?(platform) + install_java_gem_command + else + install_gems_command(ext, platform) + end + + cmd << "\n" + cmd << "TEST_PLATFORM='#{test_platform}' #{RSPEC} #{file}" + cmd << "\n" + cmd << UNINSTALL_GEMS_COMMAND + cmd +end + +TESTS = Dir["#{TEST_PATH}/*_spec.rb"] +ok = system(UNINSTALL_GEMS_COMMAND) + +TESTS.each do |file| + puts SUITE_BREAK + puts "Running #{file}" + puts GEM_BREAK + ok = system(run_tests_cmd(file, false)) + if jruby? + puts GEM_BREAK + ok = system(run_tests_cmd(file, false, 'jruby')) + elsif mri? + puts GEM_BREAK + ok = system(run_tests_cmd(file, true)) + if platform_specific_extensions?(RUBY_PLATFORM) + puts GEM_BREAK + ok = system(run_tests_cmd(file, true, RUBY_PLATFORM)) + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index faaae3992..439ce5830 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -8,11 +8,15 @@ SimpleCov.start do project_name 'concurrent-ruby' + add_filter '/build-tests/' add_filter '/coverage/' add_filter '/doc/' + add_filter '/examples/' add_filter '/pkg/' add_filter '/spec/' add_filter '/tasks/' + add_filter '/yard-template/' + add_filter '/yardoc/' end require 'concurrent' From e7011f3ad57252a8e660cb859df56eefe3e831db Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Sun, 14 Dec 2014 21:08:05 -0500 Subject: [PATCH 07/25] Improved build test runner. --- build-tests/runner.rb | 44 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/build-tests/runner.rb b/build-tests/runner.rb index 8a8661a29..2cf58f919 100755 --- a/build-tests/runner.rb +++ b/build-tests/runner.rb @@ -26,6 +26,7 @@ TEST_PATH = File.dirname(__FILE__) PKG_PATH = File.join(File.dirname(__FILE__), '..', 'pkg') +TEST_FILES = Dir["#{TEST_PATH}/*_spec.rb"] RSPEC = "rspec --default-path #{TEST_PATH} -fd --color --seed 0" @@ -36,7 +37,6 @@ CMD SUITE_BREAK = "######################################################################\n" -GEM_BREAK = "----------------------------------------------------------------------\n" def platform_specific_extensions?(platform = RUBY_PLATFORM) EXT_PLATFORMS.keys.include?(platform) && @@ -61,7 +61,8 @@ def install_java_gem_command "gem install #{PKG_PATH}/concurrent-ruby-#{Concurrent::VERSION}-java.gem" end -def run_tests_cmd(file, ext, platform = '') +def run_test_suite(files, ext, platform = '') + test_platform = if ext 'EXT' elsif jruby?(platform) @@ -75,31 +76,26 @@ def run_tests_cmd(file, ext, platform = '') else install_gems_command(ext, platform) end + ok = system(cmd) - cmd << "\n" - cmd << "TEST_PLATFORM='#{test_platform}' #{RSPEC} #{file}" - cmd << "\n" - cmd << UNINSTALL_GEMS_COMMAND - cmd -end + files.each do |file| + cmd = "TEST_PLATFORM='#{test_platform}' #{RSPEC} #{file}" + ok = system(cmd) + end -TESTS = Dir["#{TEST_PATH}/*_spec.rb"] -ok = system(UNINSTALL_GEMS_COMMAND) + ok = system(UNINSTALL_GEMS_COMMAND) +end -TESTS.each do |file| +puts SUITE_BREAK +run_test_suite(TEST_FILES, false) +if jruby? + puts SUITE_BREAK + run_test_suite(TEST_FILES, false, 'jruby') +elsif mri? puts SUITE_BREAK - puts "Running #{file}" - puts GEM_BREAK - ok = system(run_tests_cmd(file, false)) - if jruby? - puts GEM_BREAK - ok = system(run_tests_cmd(file, false, 'jruby')) - elsif mri? - puts GEM_BREAK - ok = system(run_tests_cmd(file, true)) - if platform_specific_extensions?(RUBY_PLATFORM) - puts GEM_BREAK - ok = system(run_tests_cmd(file, true, RUBY_PLATFORM)) - end + run_test_suite(TEST_FILES, true) + if platform_specific_extensions?(RUBY_PLATFORM) + puts SUITE_BREAK + run_test_suite(TEST_FILES, true, RUBY_PLATFORM) end end From d742d08cfa79a872dc972f2217d8e90eee612804 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Sun, 14 Dec 2014 22:40:50 -0500 Subject: [PATCH 08/25] Build tests now install RSpec when running tests. --- build-tests/runner.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build-tests/runner.rb b/build-tests/runner.rb index 2cf58f919..ff13cdad0 100755 --- a/build-tests/runner.rb +++ b/build-tests/runner.rb @@ -30,6 +30,8 @@ RSPEC = "rspec --default-path #{TEST_PATH} -fd --color --seed 0" +INSTALL_RSPEC_COMMAND = 'gem install rspec' + UNINSTALL_GEMS_COMMAND = <<-CMD gem uninstall -q -a -I concurrent-ruby-ext gem uninstall -q -a -I concurrent-ruby @@ -86,6 +88,9 @@ def run_test_suite(files, ext, platform = '') ok = system(UNINSTALL_GEMS_COMMAND) end +ok = system(INSTALL_RSPEC_COMMAND) +ok = system(UNINSTALL_GEMS_COMMAND) + puts SUITE_BREAK run_test_suite(TEST_FILES, false) if jruby? From 5aa707aef3bcf85a344664c9b009f932601c55d8 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Wed, 24 Dec 2014 10:03:01 -0500 Subject: [PATCH 09/25] Updated build tests to support Windows. --- build-tests/platform_helpers.rb | 5 +++++ build-tests/runner.rb | 10 +++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/build-tests/platform_helpers.rb b/build-tests/platform_helpers.rb index e03e54cae..6067f1843 100644 --- a/build-tests/platform_helpers.rb +++ b/build-tests/platform_helpers.rb @@ -1,5 +1,10 @@ require 'rbconfig' +def windows? + host_os = RbConfig::CONFIG['host_os'] + host_os =~ /mswin32/i || host_os =~ /mingw32/i +end + def mri?(engine = RUBY_ENGINE) engine == 'ruby' end diff --git a/build-tests/runner.rb b/build-tests/runner.rb index ff13cdad0..680bb5cf5 100755 --- a/build-tests/runner.rb +++ b/build-tests/runner.rb @@ -33,8 +33,8 @@ INSTALL_RSPEC_COMMAND = 'gem install rspec' UNINSTALL_GEMS_COMMAND = <<-CMD -gem uninstall -q -a -I concurrent-ruby-ext -gem uninstall -q -a -I concurrent-ruby +gem uninstall -q -a -I concurrent-ruby-ext && \ +gem uninstall -q -a -I concurrent-ruby && \ gem uninstall -q -a -I ref CMD @@ -81,7 +81,11 @@ def run_test_suite(files, ext, platform = '') ok = system(cmd) files.each do |file| - cmd = "TEST_PLATFORM='#{test_platform}' #{RSPEC} #{file}" + if windows? + cmd = "set TEST_PLATFORM='#{test_platform}' && #{RSPEC} #{file}" + else + cmd = "TEST_PLATFORM='#{test_platform}' #{RSPEC} #{file}" + end ok = system(cmd) end From db81830cc477d7dc25762a524d3ae58a7331fb29 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Mon, 29 Dec 2014 08:53:56 -0500 Subject: [PATCH 10/25] Core and extension gems now have same version number. --- concurrent-ruby-ext.gemspec | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/concurrent-ruby-ext.gemspec b/concurrent-ruby-ext.gemspec index 2ea327ae3..5273e9e6a 100644 --- a/concurrent-ruby-ext.gemspec +++ b/concurrent-ruby-ext.gemspec @@ -4,7 +4,7 @@ require 'concurrent/version' Gem::Specification.new do |s| s.name = 'concurrent-ruby-ext' - s.version = Concurrent::EXT_VERSION + s.version = Concurrent::VERSION s.platform = Gem::Platform::RUBY s.author = "Jerry D'Antonio" s.email = 'jerry.dantonio@gmail.com' @@ -14,8 +14,8 @@ Gem::Specification.new do |s| s.date = Time.now.strftime('%Y-%m-%d') s.description = <<-EOF - Modern concurrency tools including agents, futures, promises, thread pools, actors, supervisors, and more. - Inspired by Erlang, Clojure, Go, JavaScript, actors, and classic concurrency patterns. + C extensions to optimize the concurrent-ruby gem when running under MRI. + Please see http://concurrent-ruby.com for more information. EOF s.files = Dir['ext/**/*.{h,c,cpp}'] @@ -30,5 +30,5 @@ Gem::Specification.new do |s| s.required_ruby_version = '>= 1.9.3' - s.add_runtime_dependency 'concurrent-ruby', '~> 0.8.0.pre1' + s.add_runtime_dependency 'concurrent-ruby', "~> #{Concurrent::VERSION}" end From 077064466c504ab3173395e27e12a427fb7cc0a4 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Mon, 29 Dec 2014 08:57:51 -0500 Subject: [PATCH 11/25] Added note for gem developers to the README. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index f5101d632..24ce32261 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,11 @@ require 'concurrent' The `concurrent-ruby` gem will automatically detect the presence of the `concurrent-ruby-ext` gem and load the appropriate C extensions. +#### Note For gem developers + +No gems should depend on `concurrent-ruby-ext`. Doing so will force C extensions on your users. +The best practice is to depend on `concurrent-ruby` and let users to decide if they want C extensions. + ## Maintainers * [Jerry D'Antonio](https://github.com/jdantonio) From 0aa9b017c8eec06b65bc20d5a14a3db745c357be Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Mon, 29 Dec 2014 09:03:13 -0500 Subject: [PATCH 12/25] Fixed code samples in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 24ce32261..c3da58dbe 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ To minimize installation errors the C extensions are available in the `concurren gem. The extension gem lists `concurrent-ruby` as a dependency so it is not necessary to install both. Simply install the extension gen: -```shell +```ruby gem install concurrent-ruby-ext ``` @@ -170,7 +170,7 @@ and run `bundle install` from your shell. In code it is only necessary to -```shell +```ruby require 'concurrent' ``` From d5d0c06c08ea9a821ef491b4acb659cb1c0c600c Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Mon, 29 Dec 2014 09:06:00 -0500 Subject: [PATCH 13/25] Updated benchmark scripts to check for C extensions. --- examples/bench_atomic.rb | 10 ++++++++++ examples/bench_atomic_1.rb | 9 +++++---- 2 files changed, 15 insertions(+), 4 deletions(-) mode change 100644 => 100755 examples/bench_atomic.rb mode change 100644 => 100755 examples/bench_atomic_1.rb diff --git a/examples/bench_atomic.rb b/examples/bench_atomic.rb old mode 100644 new mode 100755 index a5701f643..5c2339baa --- a/examples/bench_atomic.rb +++ b/examples/bench_atomic.rb @@ -1,8 +1,18 @@ +#!/usr/bin/env ruby + +$: << File.expand_path('../../lib', __FILE__) + require 'benchmark' require 'rbconfig' require 'thread' + require 'concurrent/atomic' +unless defined? Concurrent::CAtomic + warn "[ERROR] C extensions not loaded!" + exit(1) +end + Thread.abort_on_exception = true $go = false # for synchronizing parallel threads diff --git a/examples/bench_atomic_1.rb b/examples/bench_atomic_1.rb old mode 100644 new mode 100755 index 5f5585e49..711fa3ed8 --- a/examples/bench_atomic_1.rb +++ b/examples/bench_atomic_1.rb @@ -6,10 +6,11 @@ require 'thread' require 'benchmark' -begin - require 'concurrent-ext' -rescue LoadError - require 'concurrent' +require 'concurrent/atomic' + +unless defined? Concurrent::CAtomic + warn "[ERROR] C extensions not loaded!" + exit(1) end Thread.abort_on_exception = true From d3d9ab47327d9e48c75b59a5e67b7a461862cff6 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Mon, 29 Dec 2014 12:12:15 -0500 Subject: [PATCH 14/25] Fixed version number in build test runner. --- build-tests/runner.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-tests/runner.rb b/build-tests/runner.rb index 680bb5cf5..52ff10781 100755 --- a/build-tests/runner.rb +++ b/build-tests/runner.rb @@ -48,7 +48,7 @@ def platform_specific_extensions?(platform = RUBY_PLATFORM) def extension_gem_name(platform = RUBY_PLATFORM) platform = EXT_PLATFORMS.fetch(platform, '') platform = '-' + platform unless platform.empty? - "concurrent-ruby-ext-#{Concurrent::EXT_VERSION}#{platform}.gem" + "concurrent-ruby-ext-#{Concurrent::VERSION}#{platform}.gem" end def install_gems_command(ext, platform = '') From 3369e4613172c3401ed572a78509926e8afc2d20 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Tue, 30 Dec 2014 00:04:48 -0500 Subject: [PATCH 15/25] Updated extensions and build tasks based on Heroku testing. --- Gemfile | 1 + Rakefile | 51 ++++++++++--------- concurrent-ruby-ext.gemspec | 5 +- .../atomic_boolean.c | 0 .../atomic_boolean.h | 0 .../atomic_fixnum.c | 0 .../atomic_fixnum.h | 0 .../atomic_reference.c | 0 .../atomic_reference.h | 0 .../extconf.rb | 7 ++- .../rb_concurrent.c | 4 +- .../ruby_193_compatible.h | 0 lib/extension_helper.rb | 6 +-- 13 files changed, 40 insertions(+), 34 deletions(-) rename ext/{concurrent_ruby_ext => concurrent}/atomic_boolean.c (100%) rename ext/{concurrent_ruby_ext => concurrent}/atomic_boolean.h (100%) rename ext/{concurrent_ruby_ext => concurrent}/atomic_fixnum.c (100%) rename ext/{concurrent_ruby_ext => concurrent}/atomic_fixnum.h (100%) rename ext/{concurrent_ruby_ext => concurrent}/atomic_reference.c (100%) rename ext/{concurrent_ruby_ext => concurrent}/atomic_reference.h (100%) rename ext/{concurrent_ruby_ext => concurrent}/extconf.rb (87%) rename ext/{concurrent_ruby_ext => concurrent}/rb_concurrent.c (97%) rename ext/{concurrent_ruby_ext => concurrent}/ruby_193_compatible.h (100%) diff --git a/Gemfile b/Gemfile index abfcd79c1..bec4a264a 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,7 @@ gemspec name: 'concurrent-ruby' group :development do gem 'rake', '~> 10.3.2' gem 'rake-compiler', '~> 0.9.2' + gem 'gem-compiler', '~> 0.3.0' end group :testing do diff --git a/Rakefile b/Rakefile index 8f51a8728..e3fc1d468 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,7 @@ CORE_GEMSPEC = Gem::Specification.load('concurrent-ruby.gemspec') EXT_GEMSPEC = Gem::Specification.load('concurrent-ruby-ext.gemspec') -EXTENSION_NAME = 'concurrent_ruby_ext' +GEM_NAME = 'concurrent-ruby' +EXTENSION_NAME = 'extension' $:.push File.join(File.dirname(__FILE__), 'lib') require 'extension_helper' @@ -18,15 +19,10 @@ Dir.glob('tasks/**/*.rake').each do |rakefile| safe_load rakefile end -#desc 'Run benchmarks' -task :bench do - exec 'ruby -Ilib -Iext examples/bench_atomic.rb' -end - if defined?(JRUBY_VERSION) require 'rake/javaextensiontask' - Rake::JavaExtensionTask.new(EXTENSION_NAME, CORE_GEMSPEC) do |ext| + Rake::JavaExtensionTask.new('concurrent_ruby_ext', CORE_GEMSPEC) do |ext| ext.ext_dir = 'ext' end @@ -34,9 +30,9 @@ elsif Concurrent.allow_c_extensions? require 'rake/extensiontask' Rake::ExtensionTask.new(EXTENSION_NAME, EXT_GEMSPEC) do |ext| - ext.ext_dir = "ext/#{EXTENSION_NAME}" - ext.cross_compile = true - ext.cross_platform = ['x86-mingw32', 'x64-mingw32'] + ext.ext_dir = 'ext/concurrent' + ext.lib_dir = 'lib/concurrent' + ext.source_pattern = '*.{c,h}' end ENV['RUBY_CC_VERSION'].to_s.split(':').each do |ruby_version| @@ -56,11 +52,10 @@ elsif Concurrent.allow_c_extensions? end end else - task :clean task :compile end -Rake::Task[:clean].enhance do +task :clean do rm_rf 'pkg/classes' rm_rf 'tmp' rm_rf 'lib/1.9' @@ -84,29 +79,39 @@ rescue LoadError puts 'Error loading Rspec rake tasks, probably building the gem...' end +build_deps = [:clean] +build_deps << :compile if defined?(JRUBY_VERSION) + +build_tasks = ['build:core'] +build_tasks += ['build:ext', 'build:native'] if Concurrent.allow_c_extensions? + +CoreGem = "#{GEM_NAME}-#{Concurrent::VERSION}.gem" +ExtensionGem = "#{GEM_NAME}-ext-#{Concurrent::VERSION}.gem" +NativeGem = "#{GEM_NAME}-ext-#{Concurrent::VERSION}-#{Gem::Platform.new(RUBY_PLATFORM)}.gem" + namespace :build do - - build_deps = [:clean] - build_deps << :compile if defined?(JRUBY_VERSION) - desc 'Build the concurrent-ruby gem' + desc "Build #{CoreGem} into the pkg directory" task :core => build_deps do sh "gem build #{CORE_GEMSPEC.name}.gemspec" sh 'mv *.gem pkg/' - Rake::Task[:clean].execute end if Concurrent.allow_c_extensions? - desc 'Build the concurrent-ruby-ext gem' - task :ext => [:clean, :compile] do + + desc "Build #{ExtensionGem}.gem into the pkg directory" + task :ext => [:clean] do sh "gem build #{EXT_GEMSPEC.name}.gemspec" sh 'mv *.gem pkg/' - Rake::Task[:clean].execute end - else - task :ext + + desc "Build #{NativeGem} into the pkg directory" + task :native do + sh "gem compile pkg/#{ExtensionGem}" + sh 'mv *.gem pkg/' + end end end desc 'Build all gems for this platform' -task :build => ['build:core', 'build:ext'] +task :build => build_tasks diff --git a/concurrent-ruby-ext.gemspec b/concurrent-ruby-ext.gemspec index 5273e9e6a..c0e6040c0 100644 --- a/concurrent-ruby-ext.gemspec +++ b/concurrent-ruby-ext.gemspec @@ -20,13 +20,14 @@ Gem::Specification.new do |s| s.files = Dir['ext/**/*.{h,c,cpp}'] s.files += [ + 'lib/extension_helper.rb', 'lib/concurrent/atomic_reference/concurrent_update_error.rb', 'lib/concurrent/atomic_reference/direct_update.rb', 'lib/concurrent/atomic_reference/numeric_cas_wrapper.rb', ] s.extra_rdoc_files = Dir['README*', 'LICENSE*', 'CHANGELOG*'] - s.require_paths = ['lib'] - s.extensions = 'ext/concurrent_ruby_ext/extconf.rb' + s.require_paths = ['lib', 'ext'] + s.extensions = 'ext/concurrent/extconf.rb' s.required_ruby_version = '>= 1.9.3' diff --git a/ext/concurrent_ruby_ext/atomic_boolean.c b/ext/concurrent/atomic_boolean.c similarity index 100% rename from ext/concurrent_ruby_ext/atomic_boolean.c rename to ext/concurrent/atomic_boolean.c diff --git a/ext/concurrent_ruby_ext/atomic_boolean.h b/ext/concurrent/atomic_boolean.h similarity index 100% rename from ext/concurrent_ruby_ext/atomic_boolean.h rename to ext/concurrent/atomic_boolean.h diff --git a/ext/concurrent_ruby_ext/atomic_fixnum.c b/ext/concurrent/atomic_fixnum.c similarity index 100% rename from ext/concurrent_ruby_ext/atomic_fixnum.c rename to ext/concurrent/atomic_fixnum.c diff --git a/ext/concurrent_ruby_ext/atomic_fixnum.h b/ext/concurrent/atomic_fixnum.h similarity index 100% rename from ext/concurrent_ruby_ext/atomic_fixnum.h rename to ext/concurrent/atomic_fixnum.h diff --git a/ext/concurrent_ruby_ext/atomic_reference.c b/ext/concurrent/atomic_reference.c similarity index 100% rename from ext/concurrent_ruby_ext/atomic_reference.c rename to ext/concurrent/atomic_reference.c diff --git a/ext/concurrent_ruby_ext/atomic_reference.h b/ext/concurrent/atomic_reference.h similarity index 100% rename from ext/concurrent_ruby_ext/atomic_reference.h rename to ext/concurrent/atomic_reference.h diff --git a/ext/concurrent_ruby_ext/extconf.rb b/ext/concurrent/extconf.rb similarity index 87% rename from ext/concurrent_ruby_ext/extconf.rb rename to ext/concurrent/extconf.rb index eb635c2f9..76cb706dd 100644 --- a/ext/concurrent_ruby_ext/extconf.rb +++ b/ext/concurrent/extconf.rb @@ -1,9 +1,8 @@ require 'fileutils' -$:.push File.join(File.dirname(__FILE__), '../../lib') -require 'extension_helper' +require_relative '../../lib/extension_helper' -EXTENSION_NAME = 'concurrent_ruby_ext' +EXTENSION_NAME = 'extension' def create_dummy_makefile File.open('Makefile', 'w') do |f| @@ -50,7 +49,7 @@ def compiler_is_gcc } CODE - create_makefile(EXTENSION_NAME) + create_makefile('concurrent/' + EXTENSION_NAME) rescue create_dummy_makefile warn 'C optimizations cannot be compiled on this version of Ruby.' diff --git a/ext/concurrent_ruby_ext/rb_concurrent.c b/ext/concurrent/rb_concurrent.c similarity index 97% rename from ext/concurrent_ruby_ext/rb_concurrent.c rename to ext/concurrent/rb_concurrent.c index c8d85ef34..e927ab4f8 100644 --- a/ext/concurrent_ruby_ext/rb_concurrent.c +++ b/ext/concurrent/rb_concurrent.c @@ -11,9 +11,9 @@ static VALUE rb_cAtomic; static VALUE rb_cAtomicBoolean; static VALUE rb_cAtomicFixnum; -// Init_concurrent_ruby_ext +// Init_extension -void Init_concurrent_ruby_ext() { +void Init_extension() { // define modules and classes rb_mConcurrent = rb_define_module("Concurrent"); diff --git a/ext/concurrent_ruby_ext/ruby_193_compatible.h b/ext/concurrent/ruby_193_compatible.h similarity index 100% rename from ext/concurrent_ruby_ext/ruby_193_compatible.h rename to ext/concurrent/ruby_193_compatible.h diff --git a/lib/extension_helper.rb b/lib/extension_helper.rb index 8f53d3c9a..84410bfef 100644 --- a/lib/extension_helper.rb +++ b/lib/extension_helper.rb @@ -10,12 +10,12 @@ def self.allow_c_extensions? if allow_c_extensions? && !@@c_ext_loaded begin - require 'concurrent_ruby_ext' + require 'concurrent/extension' @@c_ext_loaded = true rescue LoadError # may be a Windows cross-compiled native gem begin - require "#{RUBY_VERSION[0..2]}/concurrent_ruby_ext" + require "#{RUBY_VERSION[0..2]}/concurrent/extension" @@c_ext_loaded = true rescue LoadError warn 'Performance on MRI may be improved with the concurrent-ruby-ext gem. Please see http://concurrent-ruby.com' @@ -23,7 +23,7 @@ def self.allow_c_extensions? end elsif RUBY_PLATFORM == 'java' && !@@java_ext_loaded begin - require 'concurrent_ruby_ext' + require 'concurrent/extension' @@java_ext_loaded = true rescue LoadError #warn 'Attempted to load Java extensions on unsupported platform. Continuing with pure-Ruby.' From 1a2377efbe27b51c41fbc39b086d5d929257aadb Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Tue, 30 Dec 2014 10:44:35 -0500 Subject: [PATCH 16/25] Better platform detection in Rake compile and build tasks. --- Rakefile | 95 +++++++++++++++++++++++++---------------- lib/extension_helper.rb | 9 +++- yardoc | 1 + 3 files changed, 67 insertions(+), 38 deletions(-) create mode 160000 yardoc diff --git a/Rakefile b/Rakefile index e3fc1d468..90e0045d7 100644 --- a/Rakefile +++ b/Rakefile @@ -1,16 +1,31 @@ +#!/usr/bin/env rake + +require_relative './lib/extension_helper' + +## load the two gemspec files CORE_GEMSPEC = Gem::Specification.load('concurrent-ruby.gemspec') EXT_GEMSPEC = Gem::Specification.load('concurrent-ruby-ext.gemspec') + +## constants used for compile/build tasks + GEM_NAME = 'concurrent-ruby' EXTENSION_NAME = 'extension' -$:.push File.join(File.dirname(__FILE__), 'lib') -require 'extension_helper' +if Concurrent.jruby? + CORE_GEM = "#{GEM_NAME}-#{Concurrent::VERSION}-java.gem" +else + CORE_GEM = "#{GEM_NAME}-#{Concurrent::VERSION}.gem" + EXTENSION_GEM = "#{GEM_NAME}-ext-#{Concurrent::VERSION}.gem" + NATIVE_GEM = "#{GEM_NAME}-ext-#{Concurrent::VERSION}-#{Gem::Platform.new(RUBY_PLATFORM)}.gem" +end + +## safely load all the rake tasks in the `tasks` directory def safe_load(file) begin load file rescue LoadError => ex - puts 'Error loading rake tasks, but will continue...' + puts "Error loading rake tasks from '#{file}' but will continue..." puts ex.message end end @@ -19,17 +34,21 @@ Dir.glob('tasks/**/*.rake').each do |rakefile| safe_load rakefile end -if defined?(JRUBY_VERSION) +if Concurrent.jruby? + + ## create the compile task for the JRuby-specific gem require 'rake/javaextensiontask' - Rake::JavaExtensionTask.new('concurrent_ruby_ext', CORE_GEMSPEC) do |ext| + Rake::JavaExtensionTask.new('java', CORE_GEMSPEC) do |ext| ext.ext_dir = 'ext' end elsif Concurrent.allow_c_extensions? + + ## create the compile tasks for the extension gem require 'rake/extensiontask' - Rake::ExtensionTask.new(EXTENSION_NAME, EXT_GEMSPEC) do |ext| + Rake::ExtensionTask.new('ext', EXT_GEMSPEC) do |ext| ext.ext_dir = 'ext/concurrent' ext.lib_dir = 'lib/concurrent' ext.source_pattern = '*.{c,h}' @@ -52,6 +71,7 @@ elsif Concurrent.allow_c_extensions? end end else + ## create an empty compile task task :compile end @@ -66,52 +86,55 @@ task :clean do mkdir_p 'pkg' end -begin - require 'rspec' - require 'rspec/core/rake_task' - - RSpec::Core::RakeTask.new(:spec) do |t| - t.rspec_opts = '--color --backtrace --format documentation' - end - - task :default => [:clean, :compile, :spec] -rescue LoadError - puts 'Error loading Rspec rake tasks, probably building the gem...' -end - -build_deps = [:clean] -build_deps << :compile if defined?(JRUBY_VERSION) - -build_tasks = ['build:core'] -build_tasks += ['build:ext', 'build:native'] if Concurrent.allow_c_extensions? - -CoreGem = "#{GEM_NAME}-#{Concurrent::VERSION}.gem" -ExtensionGem = "#{GEM_NAME}-ext-#{Concurrent::VERSION}.gem" -NativeGem = "#{GEM_NAME}-ext-#{Concurrent::VERSION}-#{Gem::Platform.new(RUBY_PLATFORM)}.gem" +## create build tasks tailored to current platform namespace :build do - desc "Build #{CoreGem} into the pkg directory" + build_deps = [:clean] + build_deps << :compile if Concurrent.jruby? + + desc "Build #{CORE_GEM} into the pkg directory" task :core => build_deps do sh "gem build #{CORE_GEMSPEC.name}.gemspec" sh 'mv *.gem pkg/' end - if Concurrent.allow_c_extensions? - - desc "Build #{ExtensionGem}.gem into the pkg directory" + unless Concurrent.jruby? + desc "Build #{EXTENSION_GEM} into the pkg directory" task :ext => [:clean] do sh "gem build #{EXT_GEMSPEC.name}.gemspec" sh 'mv *.gem pkg/' end + end - desc "Build #{NativeGem} into the pkg directory" + if Concurrent.allow_c_extensions? + desc "Build #{NATIVE_GEM} into the pkg directory" task :native do - sh "gem compile pkg/#{ExtensionGem}" + sh "gem compile pkg/#{EXTENSION_GEM}" sh 'mv *.gem pkg/' end end end -desc 'Build all gems for this platform' -task :build => build_tasks +if Concurrent.jruby? + desc 'Build JRuby-specific core gem (alias for `build:core`)' + task :build => ['build:core'] +else + desc 'Build core and extension gems' + task :build => ['build:core', 'build:ext'] +end + +## the RSpec task that compiles extensions when available + +begin + require 'rspec' + require 'rspec/core/rake_task' + + RSpec::Core::RakeTask.new(:spec) do |t| + t.rspec_opts = '--color --backtrace --format documentation' + end + + task :default => [:clean, :compile, :spec] +rescue LoadError + puts 'Error loading Rspec rake tasks, probably building the gem...' +end diff --git a/lib/extension_helper.rb b/lib/extension_helper.rb index 84410bfef..e433b2b91 100644 --- a/lib/extension_helper.rb +++ b/lib/extension_helper.rb @@ -1,5 +1,5 @@ module Concurrent - + @@c_ext_loaded ||= false @@java_ext_loaded ||= false @@ -8,6 +8,11 @@ def self.allow_c_extensions? defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby' end + # @!visibility private + def self.jruby? + RUBY_PLATFORM == 'java' + end + if allow_c_extensions? && !@@c_ext_loaded begin require 'concurrent/extension' @@ -21,7 +26,7 @@ def self.allow_c_extensions? warn 'Performance on MRI may be improved with the concurrent-ruby-ext gem. Please see http://concurrent-ruby.com' end end - elsif RUBY_PLATFORM == 'java' && !@@java_ext_loaded + elsif jruby? && !@@java_ext_loaded begin require 'concurrent/extension' @@java_ext_loaded = true diff --git a/yardoc b/yardoc new file mode 160000 index 000000000..db7483b80 --- /dev/null +++ b/yardoc @@ -0,0 +1 @@ +Subproject commit db7483b80f6efb7df9930f0031508d7e2eb6bad0 From 20f0e44f853ef0c7913fee948bec7b4246b616cc Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Tue, 30 Dec 2014 17:14:30 -0500 Subject: [PATCH 17/25] Fixed cross-compile build problems in Rakefile. --- Rakefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 90e0045d7..cbe230fa1 100644 --- a/Rakefile +++ b/Rakefile @@ -48,10 +48,12 @@ elsif Concurrent.allow_c_extensions? ## create the compile tasks for the extension gem require 'rake/extensiontask' - Rake::ExtensionTask.new('ext', EXT_GEMSPEC) do |ext| + Rake::ExtensionTask.new(EXTENSION_NAME, EXT_GEMSPEC) do |ext| ext.ext_dir = 'ext/concurrent' ext.lib_dir = 'lib/concurrent' ext.source_pattern = '*.{c,h}' + ext.cross_compile = true + ext.cross_platform = ['x86-mingw32', 'x64-mingw32'] end ENV['RUBY_CC_VERSION'].to_s.split(':').each do |ruby_version| From 37e5dc3e5f626c346eafcf87e33b32efcaa976c5 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Tue, 30 Dec 2014 17:28:38 -0500 Subject: [PATCH 18/25] Added build information to the README. --- README.md | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c3da58dbe..130bd69c5 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ ### Supported Ruby versions -MRI 1.9.3, 2.0, 2.1, JRuby (1.9 mode), and Rubinius 2.x are supported. +MRI 1.9.3, 2.0, 2.1, 2.2, JRuby (1.9 mode), and Rubinius 2.x are supported. This gem should be fully compatible with any interpreter that is compliant with Ruby 1.9.3 or newer. ## Features & Documentation @@ -182,6 +182,33 @@ and load the appropriate C extensions. No gems should depend on `concurrent-ruby-ext`. Doing so will force C extensions on your users. The best practice is to depend on `concurrent-ruby` and let users to decide if they want C extensions. +### Building + +All published versions of this gem (core, extension, and several platform-specific packages) are compiled, +packaged, tested, and published using an open, [automated process](https://github.com/ruby-concurrency/rake-compiler-dev-box). +This process can also be used to create pre-compiled binaries of the extension gem for virtally +any platform. *Documentation is forthcoming...* + +``` +*MRI only* +rake build:native # Build concurrent-ruby-ext--.gem into the pkg directory + +*JRuby only* +rake build # Build JRuby-specific core gem (alias for `build:core`) +rake build:core # Build concurrent-ruby--java.gem into the pkg directory + +*All except JRuby* +rake build # Build core and extension gems +rake build:core # Build concurrent-ruby-.gem into the pkg directory +rake build:ext # Build concurrent-ruby-ext-.gem into the pkg directory + +*All* +rake clean # Remove any temporary products +rake clobber # Remove any generated file +rake compile # Compile all the extensions +rake compile:extension # Compile extension +``` + ## Maintainers * [Jerry D'Antonio](https://github.com/jdantonio) From 495113c0df86ec8b3af9e61961c5201d91047582 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Wed, 14 Jan 2015 21:19:17 -0500 Subject: [PATCH 19/25] Fixed bad Java compile task. --- README.md | 2 +- Rakefile | 3 ++- concurrent-ruby.gemspec | 2 +- lib/extension_helper.rb | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 130bd69c5..6c29822ff 100644 --- a/README.md +++ b/README.md @@ -192,6 +192,7 @@ any platform. *Documentation is forthcoming...* ``` *MRI only* rake build:native # Build concurrent-ruby-ext--.gem into the pkg directory +rake compile:extension # Compile extension *JRuby only* rake build # Build JRuby-specific core gem (alias for `build:core`) @@ -206,7 +207,6 @@ rake build:ext # Build concurrent-ruby-ext-.gem into the pkg d rake clean # Remove any temporary products rake clobber # Remove any generated file rake compile # Compile all the extensions -rake compile:extension # Compile extension ``` ## Maintainers diff --git a/Rakefile b/Rakefile index cbe230fa1..5da44fcbe 100644 --- a/Rakefile +++ b/Rakefile @@ -10,6 +10,7 @@ EXT_GEMSPEC = Gem::Specification.load('concurrent-ruby-ext.gemspec') GEM_NAME = 'concurrent-ruby' EXTENSION_NAME = 'extension' +JAVA_EXT_NAME = 'concurrent_ruby_ext' if Concurrent.jruby? CORE_GEM = "#{GEM_NAME}-#{Concurrent::VERSION}-java.gem" @@ -39,7 +40,7 @@ if Concurrent.jruby? ## create the compile task for the JRuby-specific gem require 'rake/javaextensiontask' - Rake::JavaExtensionTask.new('java', CORE_GEMSPEC) do |ext| + Rake::JavaExtensionTask.new(JAVA_EXT_NAME, CORE_GEMSPEC) do |ext| ext.ext_dir = 'ext' end diff --git a/concurrent-ruby.gemspec b/concurrent-ruby.gemspec index eb2912040..d4e306560 100644 --- a/concurrent-ruby.gemspec +++ b/concurrent-ruby.gemspec @@ -23,7 +23,7 @@ Gem::Specification.new do |s| s.require_paths = ['lib'] if defined?(JRUBY_VERSION) - s.files += Dir['lib/concurrent_ruby_ext.jar'] + s.files += Dir['lib/**/*.jar'] s.platform = 'java' else s.add_runtime_dependency 'ref', '~> 1.0', '>= 1.0.5' diff --git a/lib/extension_helper.rb b/lib/extension_helper.rb index e433b2b91..1579d825d 100644 --- a/lib/extension_helper.rb +++ b/lib/extension_helper.rb @@ -28,10 +28,10 @@ def self.jruby? end elsif jruby? && !@@java_ext_loaded begin - require 'concurrent/extension' + require 'concurrent_ruby_ext' @@java_ext_loaded = true rescue LoadError - #warn 'Attempted to load Java extensions on unsupported platform. Continuing with pure-Ruby.' + warn 'Attempted to load Java extensions on unsupported platform. Continuing with pure-Ruby.' end end end From 7d484639c25748bd9cc53fb347be4d4ddec05c83 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Wed, 14 Jan 2015 22:58:52 -0500 Subject: [PATCH 20/25] Better warning when using pure-Ruby build under JRuby. --- lib/extension_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/extension_helper.rb b/lib/extension_helper.rb index 1579d825d..f75244e3b 100644 --- a/lib/extension_helper.rb +++ b/lib/extension_helper.rb @@ -31,7 +31,7 @@ def self.jruby? require 'concurrent_ruby_ext' @@java_ext_loaded = true rescue LoadError - warn 'Attempted to load Java extensions on unsupported platform. Continuing with pure-Ruby.' + warn 'Performance on JRuby may be improved by installing the pre-compiled Java extensions. Please see http://concurrent-ruby.com' end end end From 3877635170b9da0017bc28be8ab059ac83a9bd4a Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Fri, 16 Jan 2015 11:09:20 -0500 Subject: [PATCH 21/25] Created build tests for CAtomic and JavaAtomic. --- build-tests/atomic_reference_builds_spec.rb | 84 +++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 build-tests/atomic_reference_builds_spec.rb diff --git a/build-tests/atomic_reference_builds_spec.rb b/build-tests/atomic_reference_builds_spec.rb new file mode 100644 index 000000000..62921110d --- /dev/null +++ b/build-tests/atomic_reference_builds_spec.rb @@ -0,0 +1,84 @@ +require 'benchmark' +require_relative 'example_group_extensions' +require_relative 'platform_helpers' + +require 'concurrent/atomics' + +def atomic_reference_test(clazz, opts = {}) + threads = opts.fetch(:threads, 5) + tests = opts.fetch(:tests, 100) + + atomic = Concurrent.const_get(clazz.to_s).new + latch = Concurrent::CountDownLatch.new(threads) + + stats = Benchmark.measure do + threads.times do |i| + Thread.new do + tests.times{ atomic.value = true } + latch.count_down + end + end + latch.wait + end + stats +end + +describe Concurrent::Atomic do + + let!(:threads) { 10 } + let!(:tests) { 1000 } + + describe Concurrent::MutexAtomic do + + specify 'is defined' do + expect(defined?(Concurrent::MutexAtomic)).to be_truthy + end + + specify 'runs the benchmarks' do + stats = atomic_reference_test('MutexAtomic', threads: threads, tests: tests) + expect(stats).to be_benchmark_results + end + end + + if jruby? + + describe Concurrent::JavaAtomic do + + specify 'Concurrent::JavaAtomic is defined' do + expect(defined?(Concurrent::JavaAtomic)).to be_truthy + end + + specify 'runs the benchmarks' do + stats = atomic_reference_test('JavaAtomic', threads: threads, tests: tests) + expect(stats).to be_benchmark_results + end + end + + else + + specify 'Concurrent::JavaAtomic is not defined' do + expect(defined?(Concurrent::JavaAtomic)).to be_falsey + end + end + + if 'EXT' == ENV['TEST_PLATFORM'] + + describe Concurrent::CAtomic do + + specify 'Concurrent::CAtomic is defined' do + expect(defined?(Concurrent::CAtomic)).to be_truthy + end + + specify 'runs the benchmarks' do + stats = atomic_reference_test('CAtomic', threads: threads, tests: tests) + expect(stats).to be_benchmark_results + end + end + + else + + specify 'Concurrent::CAtomic is not defined' do + expect(defined?(Concurrent::CAtomic)).to be_falsey + end + end +end From 1795faa881d7df6d72b5593106ac4bc93d2d00a7 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Sat, 24 Jan 2015 22:54:34 -0500 Subject: [PATCH 22/25] Fixed build tests for JRuby. --- build-tests/atomic_reference_builds_spec.rb | 2 +- build-tests/runner.rb | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/build-tests/atomic_reference_builds_spec.rb b/build-tests/atomic_reference_builds_spec.rb index 62921110d..63fc7919a 100644 --- a/build-tests/atomic_reference_builds_spec.rb +++ b/build-tests/atomic_reference_builds_spec.rb @@ -40,7 +40,7 @@ def atomic_reference_test(clazz, opts = {}) end end - if jruby? + if jruby? && 'JRUBY' == ENV['TEST_PLATFORM'] describe Concurrent::JavaAtomic do diff --git a/build-tests/runner.rb b/build-tests/runner.rb index 52ff10781..471b771a8 100755 --- a/build-tests/runner.rb +++ b/build-tests/runner.rb @@ -38,7 +38,8 @@ gem uninstall -q -a -I ref CMD -SUITE_BREAK = "######################################################################\n" +PLATFORM_BREAK = "######################################################################\n" +SUITE_BREAK = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" def platform_specific_extensions?(platform = RUBY_PLATFORM) EXT_PLATFORMS.keys.include?(platform) && @@ -95,7 +96,10 @@ def run_test_suite(files, ext, platform = '') ok = system(INSTALL_RSPEC_COMMAND) ok = system(UNINSTALL_GEMS_COMMAND) +puts PLATFORM_BREAK +puts RUBY_PLATFORM puts SUITE_BREAK + run_test_suite(TEST_FILES, false) if jruby? puts SUITE_BREAK From 12ba3a82cc4e2dee8eb7dd100f714c4c79ddec7e Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Sun, 25 Jan 2015 00:29:23 -0500 Subject: [PATCH 23/25] Fixed bug with Windows pre-compiled extension loading. --- lib/extension_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/extension_helper.rb b/lib/extension_helper.rb index f75244e3b..8ddf1bb1b 100644 --- a/lib/extension_helper.rb +++ b/lib/extension_helper.rb @@ -20,7 +20,7 @@ def self.jruby? rescue LoadError # may be a Windows cross-compiled native gem begin - require "#{RUBY_VERSION[0..2]}/concurrent/extension" + require "concurrent/#{RUBY_VERSION[0..2]}/extension" @@c_ext_loaded = true rescue LoadError warn 'Performance on MRI may be improved with the concurrent-ruby-ext gem. Please see http://concurrent-ruby.com' From 6a17ca071611d9e404f9eda0a80b104ffd687e2a Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Sun, 25 Jan 2015 01:35:53 -0500 Subject: [PATCH 24/25] Fixed tests for JavaAtomic. --- examples/bench_atomic.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/bench_atomic.rb b/examples/bench_atomic.rb index 5c2339baa..9f466b0ea 100755 --- a/examples/bench_atomic.rb +++ b/examples/bench_atomic.rb @@ -8,9 +8,8 @@ require 'concurrent/atomic' -unless defined? Concurrent::CAtomic - warn "[ERROR] C extensions not loaded!" - exit(1) +if RUBY_PLATFORM != 'java' && ! defined? Concurrent::CAtomic + warn "[WARN] C extensions not loaded!" end Thread.abort_on_exception = true From 372a68f78928c191c5e3656a6b0946035acbb24a Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Sun, 25 Jan 2015 02:32:21 -0500 Subject: [PATCH 25/25] Fixed build tests on Windows. --- build-tests/atomic_boolean_builds_spec.rb | 2 +- build-tests/atomic_fixnum_builds_spec.rb | 2 +- build-tests/atomic_reference_builds_spec.rb | 4 ++-- build-tests/runner.rb | 15 +++++++++------ 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/build-tests/atomic_boolean_builds_spec.rb b/build-tests/atomic_boolean_builds_spec.rb index e04231c76..9d754fba4 100644 --- a/build-tests/atomic_boolean_builds_spec.rb +++ b/build-tests/atomic_boolean_builds_spec.rb @@ -61,7 +61,7 @@ def atomic_boolean_test(clazz, opts = {}) end end - if 'EXT' == ENV['TEST_PLATFORM'] + if 'EXT' == ENV['TEST_PLATFORM'].strip describe Concurrent::CAtomicBoolean do diff --git a/build-tests/atomic_fixnum_builds_spec.rb b/build-tests/atomic_fixnum_builds_spec.rb index 66e7f9324..d35071637 100644 --- a/build-tests/atomic_fixnum_builds_spec.rb +++ b/build-tests/atomic_fixnum_builds_spec.rb @@ -61,7 +61,7 @@ def atomic_fixnum_test(clazz, opts = {}) end end - if 'EXT' == ENV['TEST_PLATFORM'] + if 'EXT' == ENV['TEST_PLATFORM'].strip describe Concurrent::CAtomicFixnum do diff --git a/build-tests/atomic_reference_builds_spec.rb b/build-tests/atomic_reference_builds_spec.rb index 63fc7919a..846a20ba8 100644 --- a/build-tests/atomic_reference_builds_spec.rb +++ b/build-tests/atomic_reference_builds_spec.rb @@ -40,7 +40,7 @@ def atomic_reference_test(clazz, opts = {}) end end - if jruby? && 'JRUBY' == ENV['TEST_PLATFORM'] + if jruby? && 'JRUBY' == ENV['TEST_PLATFORM'].strip describe Concurrent::JavaAtomic do @@ -61,7 +61,7 @@ def atomic_reference_test(clazz, opts = {}) end end - if 'EXT' == ENV['TEST_PLATFORM'] + if 'EXT' == ENV['TEST_PLATFORM'].strip describe Concurrent::CAtomic do diff --git a/build-tests/runner.rb b/build-tests/runner.rb index 471b771a8..4b7b2171b 100755 --- a/build-tests/runner.rb +++ b/build-tests/runner.rb @@ -15,10 +15,11 @@ require 'concurrent/version' require_relative 'platform_helpers' + EXT_PLATFORMS = { 'i686-linux' => 'x86-linux', 'x86_64-linux' => 'x86_64-linux', - 'x86-mingw32' => 'x86-mingw32', + 'i386-mingw32' => 'x86-mingw32', 'x64-mingw32' => 'x64-mingw32', 'i386-solaris2.11' => 'x86-solaris-2.11', 'x86_64-darwin14.0' => 'x86_64-darwin-14', @@ -28,7 +29,7 @@ PKG_PATH = File.join(File.dirname(__FILE__), '..', 'pkg') TEST_FILES = Dir["#{TEST_PATH}/*_spec.rb"] -RSPEC = "rspec --default-path #{TEST_PATH} -fd --color --seed 0" +RSPEC = "rspec --default-path #{TEST_PATH} -fd #{windows? ? '' : '--color'} --seed 0" INSTALL_RSPEC_COMMAND = 'gem install rspec' @@ -55,7 +56,7 @@ def extension_gem_name(platform = RUBY_PLATFORM) def install_gems_command(ext, platform = '') cmd = "gem install #{PKG_PATH}/concurrent-ruby-#{Concurrent::VERSION}.gem" if ext - cmd << "\ngem install #{PKG_PATH}/#{extension_gem_name(platform)}" + cmd << " && gem install #{PKG_PATH}/#{extension_gem_name(platform)}" end cmd end @@ -83,7 +84,7 @@ def run_test_suite(files, ext, platform = '') files.each do |file| if windows? - cmd = "set TEST_PLATFORM='#{test_platform}' && #{RSPEC} #{file}" + cmd = "set TEST_PLATFORM=#{test_platform} && #{RSPEC} #{file}" else cmd = "TEST_PLATFORM='#{test_platform}' #{RSPEC} #{file}" end @@ -105,8 +106,10 @@ def run_test_suite(files, ext, platform = '') puts SUITE_BREAK run_test_suite(TEST_FILES, false, 'jruby') elsif mri? - puts SUITE_BREAK - run_test_suite(TEST_FILES, true) + if ! windows? + puts SUITE_BREAK + run_test_suite(TEST_FILES, true) + end if platform_specific_extensions?(RUBY_PLATFORM) puts SUITE_BREAK run_test_suite(TEST_FILES, true, RUBY_PLATFORM)