diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index b405d52c9..5581516ec 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -4,7 +4,7 @@ Please fill following if applicable, delete otherwise: --> ``` * Operating system: linux / mac / win -* Ruby implementation: Ruby / JRuby / TruffleRuby / Rubinius +* Ruby implementation: Ruby / JRuby / TruffleRuby * `concurrent-ruby` version: x.y.z * `concurrent-ruby-ext` installed: yes / no * `concurrent-ruby-edge` used: yes / no diff --git a/README.md b/README.md index 9dbe88860..de7b9ba36 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,8 @@ You can also get started by triaging issues which may include reproducing bug re ## Thread Safety *Concurrent Ruby makes one of the strongest thread safety guarantees of any Ruby concurrency -library, providing consistent behavior and guarantees on all four of the main Ruby interpreters -(MRI/CRuby, JRuby, Rubinius, TruffleRuby).* +library, providing consistent behavior and guarantees on all three main Ruby interpreters +(MRI/CRuby, JRuby, TruffleRuby).* Every abstraction in this library is thread safe. Specific thread safety guarantees are documented with each abstraction. @@ -58,9 +58,9 @@ other Ruby library, many of which support the mantra of Concurrent Ruby is also the only Ruby library which provides a full suite of thread safe and immutable variable types and data structures. -We've also initiated discussion to document [memory model](docs-source/synchronization.md) of Ruby which -would provide consistent behaviour and guarantees on all four of the main Ruby interpreters -(MRI/CRuby, JRuby, Rubinius, TruffleRuby). +We've also initiated discussion to document the [memory model](docs-source/synchronization.md) of Ruby which +would provide consistent behaviour and guarantees on all three main Ruby interpreters +(MRI/CRuby, JRuby, TruffleRuby). ## Features & Documentation @@ -263,9 +263,6 @@ be obeyed though. Features developed in `concurrent-ruby-edge` are expected to m * Latest JRuby 9000 * Latest TruffleRuby -The legacy support for Rubinius is kept for the moment but it is no longer maintained and is liable to be removed. If you would like to help -please respond to [#739](https://github.com/ruby-concurrency/concurrent-ruby/issues/739). - ## Usage Everything within this gem can be loaded simply by requiring it: diff --git a/lib/concurrent-ruby/concurrent/array.rb b/lib/concurrent-ruby/concurrent/array.rb index 60e5b5689..96434a288 100644 --- a/lib/concurrent-ruby/concurrent/array.rb +++ b/lib/concurrent-ruby/concurrent/array.rb @@ -34,16 +34,6 @@ class JRubyArray < ::Array end JRubyArray - when Concurrent.on_rbx? - require 'monitor' - require 'concurrent/thread_safe/util/data_structures' - - class RbxArray < ::Array - end - - ThreadSafe::Util.make_synchronized_on_rbx RbxArray - RbxArray - when Concurrent.on_truffleruby? require 'concurrent/thread_safe/util/data_structures' diff --git a/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb b/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb index 674f866d0..46e276c4e 100644 --- a/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +++ b/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb @@ -171,22 +171,6 @@ class TruffleRubyAtomicReference < TruffleRuby::AtomicReference alias_method :swap, :get_and_set end TruffleRubyAtomicReference - when Concurrent.on_rbx? - # @note Extends `Rubinius::AtomicReference` version adding aliases - # and numeric logic. - # - # @!visibility private - # @!macro internal_implementation_note - class RbxAtomicReference < Rubinius::AtomicReference - alias_method :_compare_and_set, :compare_and_set - include AtomicDirectUpdate - include AtomicNumericCompareAndSetWrapper - alias_method :value, :get - alias_method :value=, :set - alias_method :swap, :get_and_set - alias_method :compare_and_swap, :compare_and_set - end - RbxAtomicReference else MutexAtomicReference end diff --git a/lib/concurrent-ruby/concurrent/hash.rb b/lib/concurrent-ruby/concurrent/hash.rb index 92df66b79..7902fe9d2 100644 --- a/lib/concurrent-ruby/concurrent/hash.rb +++ b/lib/concurrent-ruby/concurrent/hash.rb @@ -28,15 +28,6 @@ class JRubyHash < ::Hash end JRubyHash - when Concurrent.on_rbx? - require 'monitor' - require 'concurrent/thread_safe/util/data_structures' - - class RbxHash < ::Hash - end - ThreadSafe::Util.make_synchronized_on_rbx RbxHash - RbxHash - when Concurrent.on_truffleruby? require 'concurrent/thread_safe/util/data_structures' diff --git a/lib/concurrent-ruby/concurrent/map.rb b/lib/concurrent-ruby/concurrent/map.rb index c592afec0..328af19cc 100644 --- a/lib/concurrent-ruby/concurrent/map.rb +++ b/lib/concurrent-ruby/concurrent/map.rb @@ -15,12 +15,14 @@ module Collection when Concurrent.on_cruby? require 'concurrent/collection/map/mri_map_backend' MriMapBackend - when Concurrent.on_truffleruby? && defined?(::TruffleRuby::ConcurrentMap) - require 'concurrent/collection/map/truffleruby_map_backend' - TruffleRubyMapBackend - when Concurrent.on_truffleruby? || Concurrent.on_rbx? - require 'concurrent/collection/map/atomic_reference_map_backend' - AtomicReferenceMapBackend + when Concurrent.on_truffleruby? + if defined?(::TruffleRuby::ConcurrentMap) + require 'concurrent/collection/map/truffleruby_map_backend' + TruffleRubyMapBackend + else + require 'concurrent/collection/map/atomic_reference_map_backend' + AtomicReferenceMapBackend + end else warn 'Concurrent::Map: unsupported Ruby engine, using a fully synchronized Concurrent::Map implementation' require 'concurrent/collection/map/synchronized_map_backend' diff --git a/lib/concurrent-ruby/concurrent/set.rb b/lib/concurrent-ruby/concurrent/set.rb index 3bf0c895c..eee4effdf 100644 --- a/lib/concurrent-ruby/concurrent/set.rb +++ b/lib/concurrent-ruby/concurrent/set.rb @@ -42,16 +42,6 @@ class JRubySet < ::Set JRubySet - when Concurrent.on_rbx? - require 'monitor' - require 'concurrent/thread_safe/util/data_structures' - - class RbxSet < ::Set - end - - ThreadSafe::Util.make_synchronized_on_rbx RbxSet - RbxSet - when Concurrent.on_truffleruby? require 'concurrent/thread_safe/util/data_structures' diff --git a/lib/concurrent-ruby/concurrent/synchronization.rb b/lib/concurrent-ruby/concurrent/synchronization.rb index 49c68ebbb..20b606c83 100644 --- a/lib/concurrent-ruby/concurrent/synchronization.rb +++ b/lib/concurrent-ruby/concurrent/synchronization.rb @@ -6,7 +6,6 @@ require 'concurrent/synchronization/mri_object' require 'concurrent/synchronization/jruby_object' -require 'concurrent/synchronization/rbx_object' require 'concurrent/synchronization/truffleruby_object' require 'concurrent/synchronization/object' require 'concurrent/synchronization/volatile' @@ -14,7 +13,6 @@ require 'concurrent/synchronization/abstract_lockable_object' require 'concurrent/synchronization/mutex_lockable_object' require 'concurrent/synchronization/jruby_lockable_object' -require 'concurrent/synchronization/rbx_lockable_object' require 'concurrent/synchronization/lockable_object' diff --git a/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb b/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb index ae28e5bc8..18e447c42 100644 --- a/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +++ b/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb @@ -8,8 +8,6 @@ module Synchronization MutexLockableObject when Concurrent.on_jruby? JRubyLockableObject - when Concurrent.on_rbx? - RbxLockableObject when Concurrent.on_truffleruby? MutexLockableObject else diff --git a/lib/concurrent-ruby/concurrent/synchronization/object.rb b/lib/concurrent-ruby/concurrent/synchronization/object.rb index 0e6211280..db6f1c976 100644 --- a/lib/concurrent-ruby/concurrent/synchronization/object.rb +++ b/lib/concurrent-ruby/concurrent/synchronization/object.rb @@ -8,8 +8,6 @@ module Synchronization MriObject when Concurrent.on_jruby? JRubyObject - when Concurrent.on_rbx? - RbxObject when Concurrent.on_truffleruby? TruffleRubyObject else diff --git a/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb b/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb deleted file mode 100644 index 1c4697c39..000000000 --- a/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +++ /dev/null @@ -1,71 +0,0 @@ -module Concurrent - module Synchronization - - # @!visibility private - # @!macro internal_implementation_note - class RbxLockableObject < AbstractLockableObject - safe_initialization! - - def initialize(*defaults) - super(*defaults) - @__Waiters__ = [] - @__owner__ = nil - end - - def initialize_copy(other) - super - @__Waiters__ = [] - @__owner__ = nil - end - - protected - - def synchronize(&block) - if @__owner__ == Thread.current - yield - else - result = nil - Rubinius.synchronize(self) do - begin - @__owner__ = Thread.current - result = yield - ensure - @__owner__ = nil - end - end - result - end - end - - def ns_wait(timeout = nil) - wchan = Rubinius::Channel.new - - begin - @__Waiters__.push wchan - Rubinius.unlock(self) - signaled = wchan.receive_timeout timeout - ensure - Rubinius.lock(self) - - if !signaled && !@__Waiters__.delete(wchan) - # we timed out, but got signaled afterwards, - # so pass that signal on to the next waiter - @__Waiters__.shift << true unless @__Waiters__.empty? - end - end - - self - end - - def ns_signal - @__Waiters__.shift << true unless @__Waiters__.empty? - self - end - - def ns_broadcast - @__Waiters__.shift << true until @__Waiters__.empty? - self - end - end - end -end diff --git a/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb b/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb deleted file mode 100644 index 4b23f2a66..000000000 --- a/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +++ /dev/null @@ -1,49 +0,0 @@ -module Concurrent - module Synchronization - - # @!visibility private - module RbxAttrVolatile - def self.included(base) - base.extend(ClassMethods) - end - - module ClassMethods - - def attr_volatile(*names) - names.each do |name| - ivar = :"@volatile_#{name}" - class_eval <<-RUBY, __FILE__, __LINE__ + 1 - def #{name} - Rubinius.memory_barrier - #{ivar} - end - - def #{name}=(value) - #{ivar} = value - Rubinius.memory_barrier - end - RUBY - end - names.map { |n| [n, :"#{n}="] }.flatten - end - - end - - def full_memory_barrier - # Rubinius instance variables are not volatile so we need to insert barrier - # TODO (pitr 26-Nov-2015): check comments like ^ - Rubinius.memory_barrier - end - end - - # @!visibility private - # @!macro internal_implementation_note - class RbxObject < AbstractObject - include RbxAttrVolatile - - def initialize - # nothing to do - end - end - end -end diff --git a/lib/concurrent-ruby/concurrent/synchronization/volatile.rb b/lib/concurrent-ruby/concurrent/synchronization/volatile.rb index 9dffa914a..47f6a64ee 100644 --- a/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +++ b/lib/concurrent-ruby/concurrent/synchronization/volatile.rb @@ -25,8 +25,6 @@ module Synchronization MriAttrVolatile when Concurrent.on_jruby? JRubyAttrVolatile - when Concurrent.on_rbx? - RbxAttrVolatile when Concurrent.on_truffleruby? TruffleRubyAttrVolatile else diff --git a/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb b/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb index 6df7d4152..0b1213f5b 100644 --- a/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +++ b/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb @@ -32,44 +32,7 @@ module Util # @!visibility private module CheapLockable private - if Concurrent.on_rbx? - # Making use of the Rubinius' ability to lock via object headers to avoid the overhead of the extra Mutex objects. - def cheap_synchronize - Rubinius.lock(self) - begin - yield - ensure - Rubinius.unlock(self) - end - end - - def cheap_wait - wchan = Rubinius::Channel.new - - begin - waiters = @waiters ||= [] - waiters.push wchan - Rubinius.unlock(self) - signaled = wchan.receive_timeout nil - ensure - Rubinius.lock(self) - - unless signaled or waiters.delete(wchan) - # we timed out, but got signaled afterwards (e.g. while waiting to - # acquire @lock), so pass that signal on to the next waiter - waiters.shift << true unless waiters.empty? - end - end - - self - end - - def cheap_broadcast - waiters = @waiters ||= [] - waiters.shift << true until waiters.empty? - self - end - elsif Concurrent.on_jruby? + if Concurrent.on_jruby? # Use Java's native synchronized (this) { wait(); notifyAll(); } to avoid the overhead of the extra Mutex objects require 'jruby' diff --git a/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb b/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb index 24d039b2f..908768646 100644 --- a/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +++ b/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb @@ -37,43 +37,6 @@ def #{method}(*args) end end - def self.make_synchronized_on_rbx(klass) - klass.class_eval do - private - - def _mon_initialize - @_monitor ||= Monitor.new # avoid double initialisation - end - - def self.new(*args) - obj = super(*args) - obj.send(:_mon_initialize) - obj - end - end - - klass.superclass.instance_methods(false).each do |method| - case method - when :new_range, :new_reserved - klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1 - def #{method}(*args) - obj = super - obj.send(:_mon_initialize) - obj - end - RUBY - else - klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1 - def #{method}(*args) - monitor = @_monitor - monitor or raise("BUG: Internal monitor was not properly initialized. Please report this to the concurrent-ruby developers.") - monitor.synchronize { super } - end - RUBY - end - end - end - def self.make_synchronized_on_truffleruby(klass) klass.superclass.instance_methods(false).each do |method| klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1 diff --git a/lib/concurrent-ruby/concurrent/tuple.rb b/lib/concurrent-ruby/concurrent/tuple.rb index f8c4c25d3..56212cfd1 100644 --- a/lib/concurrent-ruby/concurrent/tuple.rb +++ b/lib/concurrent-ruby/concurrent/tuple.rb @@ -23,16 +23,12 @@ class Tuple # The (fixed) size of the tuple. attr_reader :size - # @!visibility private - Tuple = defined?(Rubinius::Tuple) ? Rubinius::Tuple : ::Array - private_constant :Tuple - # Create a new tuple of the given size. # # @param [Integer] size the number of elements in the tuple def initialize(size) @size = size - @tuple = tuple = Tuple.new(size) + @tuple = tuple = ::Array.new(size) i = 0 while i < size tuple[i] = Concurrent::AtomicReference.new diff --git a/lib/concurrent-ruby/concurrent/utility/engine.rb b/lib/concurrent-ruby/concurrent/utility/engine.rb index 5dbbd2382..4841fac60 100644 --- a/lib/concurrent-ruby/concurrent/utility/engine.rb +++ b/lib/concurrent-ruby/concurrent/utility/engine.rb @@ -15,10 +15,6 @@ def on_cruby? RUBY_ENGINE == 'ruby' end - def on_rbx? - RUBY_ENGINE == 'rbx' - end - def on_truffleruby? RUBY_ENGINE == 'truffleruby' end diff --git a/spec/concurrent/array_spec.rb b/spec/concurrent/array_spec.rb index f79f8e077..493af3aaa 100644 --- a/spec/concurrent/array_spec.rb +++ b/spec/concurrent/array_spec.rb @@ -82,7 +82,7 @@ module Concurrent end describe '#slice' do - # This is mostly relevant on Rubinius and TruffleRuby + # This is mostly relevant on TruffleRuby it 'correctly initializes the monitor' do ary.concat([0, 1, 2, 3, 4, 5, 6, 7, 8]) diff --git a/spec/concurrent/atomic/atomic_reference_spec.rb b/spec/concurrent/atomic/atomic_reference_spec.rb index 4403a031e..aed8f1c5a 100644 --- a/spec/concurrent/atomic/atomic_reference_spec.rb +++ b/spec/concurrent/atomic/atomic_reference_spec.rb @@ -95,7 +95,7 @@ expect(atomic.compare_and_swap(i, i - 1)).to be_truthy, "CAS failed for numeric #{i} => #{i - 1}" end - # 64-bit idempotent Fixnum (MRI, Rubinius) + # 64-bit idempotent Fixnum (MRI, TruffleRuby) max_64 = 2 ** 62 - 1 min_64 = -(2 ** 62) @@ -123,7 +123,7 @@ expect(atomic.compare_and_swap(i, i - 1)).to be_truthy, "CAS failed for numeric #{i} => #{i - 1}" end - # non-idempotent Float (JRuby, Rubinius, MRI < 2.0.0 or 32-bit) + # non-idempotent Float (JRuby, MRI < 2.0.0 or 32-bit) atomic.set(1.0 + 0.1) expect(atomic.compare_and_set(1.0 + 0.1, 1.2)).to be_truthy, "CAS failed for #{1.0 + 0.1} => 1.2" @@ -191,10 +191,6 @@ module Concurrent it 'inherits from CAtomicReference' do expect(described_class.ancestors).to include(Concurrent::CAtomicReference) end - elsif Concurrent.on_rbx? - it 'inherits from RbxAtomicReference' do - expect(described_class.ancestors).to include(Concurrent::RbxAtomicReference) - end elsif Concurrent.on_truffleruby? it 'inherits from TruffleRubyAtomicReference' do expect(described_class.ancestors).to include(Concurrent::TruffleRubyAtomicReference) diff --git a/spec/concurrent/executor/ruby_single_thread_executor_spec.rb b/spec/concurrent/executor/ruby_single_thread_executor_spec.rb index ebd4237bb..c78677978 100644 --- a/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +++ b/spec/concurrent/executor/ruby_single_thread_executor_spec.rb @@ -2,7 +2,7 @@ module Concurrent - RSpec.describe RubySingleThreadExecutor, :type=>:mrirbx do + RSpec.describe RubySingleThreadExecutor, :type=>:mri do after(:each) do subject.shutdown diff --git a/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb b/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb index 961dc3db2..d9d54b13a 100644 --- a/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +++ b/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb @@ -2,7 +2,7 @@ module Concurrent - RSpec.describe RubyThreadPoolExecutor, :type=>:mrirbx do + RSpec.describe RubyThreadPoolExecutor, :type=>:mri do after(:each) do subject.shutdown diff --git a/spec/concurrent/map_spec.rb b/spec/concurrent/map_spec.rb index c9aebfb9d..72e16d6ea 100644 --- a/spec/concurrent/map_spec.rb +++ b/spec/concurrent/map_spec.rb @@ -527,10 +527,9 @@ def key # assert_collision_resistance expects to be able to call .key to get the it 'with return' do with_or_without_default_proc do - r = fetch_with_return - # r = lambda do - # @cache.fetch(:a) { return 10 } - # end.call + r = lambda do + @cache.fetch(:a) { return 10 } + end.call expect_no_size_change do expect(10).to eq r @@ -609,7 +608,9 @@ def key # assert_collision_resistance expects to be able to call .key to get the it 'with return' do with_or_without_default_proc do - r = fetch_or_store_with_return + r = lambda do + @cache.fetch_or_store(:a) { return 10 } + end.call expect_no_size_change do expect(10).to eq r @@ -905,20 +906,5 @@ def expect_collision_resistance(keys) end expect(keys.all? { |k| @cache[k] == k.key }).to be_truthy end - - # Took out for compatibility with Rubinius, see https://github.com/rubinius/rubinius/issues/1312 - def fetch_with_return - lambda do - @cache.fetch(:a) { return 10 } - end.call - end - - # Took out for compatibility with Rubinius, see https://github.com/rubinius/rubinius/issues/1312 - def fetch_or_store_with_return - lambda do - @cache.fetch_or_store(:a) { return 10 } - end.call - end - end end diff --git a/spec/concurrent/thread_safe/map_loops_spec.rb b/spec/concurrent/thread_safe/map_loops_spec.rb index 8df1e4d3d..cf36f2797 100644 --- a/spec/concurrent/thread_safe/map_loops_spec.rb +++ b/spec/concurrent/thread_safe/map_loops_spec.rb @@ -504,5 +504,5 @@ def expect_count_up(result, cache, options, keys) expect(sum(cache.values)).to eq sum(result) expect(options[:key_count]).to eq cache.size end - end unless RUBY_ENGINE == 'rbx' + end end