Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix circular dependency between AtomicReference and Synchronization::Object #982

Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,6 @@ private static boolean supportsFences() {
}
}

private static final ObjectAllocator JRUBY_OBJECT_ALLOCATOR = new ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
return new JRubyObject(runtime, klazz);
}
};

private static final ObjectAllocator OBJECT_ALLOCATOR = new ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
return new Object(runtime, klazz);
Expand All @@ -87,10 +81,7 @@ public void load(Ruby runtime, boolean wrap) throws IOException {
RubyModule jrubyAttrVolatileModule = synchronizationModule.defineModuleUnder("JRubyAttrVolatile");
jrubyAttrVolatileModule.defineAnnotatedMethods(JRubyAttrVolatile.class);

defineClass(runtime, synchronizationModule, "AbstractObject", "JRubyObject",
JRubyObject.class, JRUBY_OBJECT_ALLOCATOR);

defineClass(runtime, synchronizationModule, "JRubyObject", "Object",
defineClass(runtime, synchronizationModule, "AbstractObject", "Object",
Object.class, OBJECT_ALLOCATOR);

defineClass(runtime, synchronizationModule, "Object", "AbstractLockableObject",
Expand Down Expand Up @@ -143,8 +134,8 @@ public static class JRubyAttrVolatile {
// attempt to avoid code elimination.
private static volatile int volatileField;

@JRubyMethod(name = "full_memory_barrier", visibility = Visibility.PUBLIC)
public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject self) {
@JRubyMethod(name = "full_memory_barrier", visibility = Visibility.PUBLIC, module = true)
public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject module) {
// Prevent reordering of ivar writes with publication of this instance
if (!FULL_FENCE) {
// Assuming that following volatile read and write is not eliminated it simulates fullFence.
Expand All @@ -158,9 +149,10 @@ public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject s
return context.nil;
}

@JRubyMethod(name = "instance_variable_get_volatile", visibility = Visibility.PUBLIC)
@JRubyMethod(name = "instance_variable_get_volatile", visibility = Visibility.PUBLIC, module = true)
public static IRubyObject instanceVariableGetVolatile(
ThreadContext context,
IRubyObject module,
IRubyObject self,
IRubyObject name) {
// Ensure we ses latest value with loadFence
Expand All @@ -174,9 +166,10 @@ public static IRubyObject instanceVariableGetVolatile(
}
}

@JRubyMethod(name = "instance_variable_set_volatile", visibility = Visibility.PUBLIC)
@JRubyMethod(name = "instance_variable_set_volatile", visibility = Visibility.PUBLIC, module = true)
public static IRubyObject InstanceVariableSetVolatile(
ThreadContext context,
IRubyObject module,
IRubyObject self,
IRubyObject name,
IRubyObject value) {
Expand All @@ -195,16 +188,8 @@ public static IRubyObject InstanceVariableSetVolatile(
}
}

@JRubyClass(name = "JRubyObject", parent = "AbstractObject")
public static class JRubyObject extends RubyObject {

public JRubyObject(Ruby runtime, RubyClass metaClass) {
super(runtime, metaClass);
}
}

@JRubyClass(name = "Object", parent = "JRubyObject")
public static class Object extends JRubyObject {
@JRubyClass(name = "Object", parent = "AbstractObject")
public static class Object extends RubyObject {

public Object(Ruby runtime, RubyClass metaClass) {
super(runtime, metaClass);
Expand All @@ -220,7 +205,7 @@ public AbstractLockableObject(Ruby runtime, RubyClass metaClass) {
}

@JRubyClass(name = "JRubyLockableObject", parent = "AbstractLockableObject")
public static class JRubyLockableObject extends JRubyObject {
public static class JRubyLockableObject extends AbstractLockableObject {

public JRubyLockableObject(Ruby runtime, RubyClass metaClass) {
super(runtime, metaClass);
Expand Down
9 changes: 5 additions & 4 deletions lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'concurrent/utility/native_extension_loader' # load native parts first

require 'concurrent/atomic/mutex_atomic_boolean'
require 'concurrent/synchronization'

module Concurrent

Expand Down Expand Up @@ -79,10 +80,10 @@ module Concurrent
# @!visibility private
# @!macro internal_implementation_note
AtomicBooleanImplementation = case
when defined?(JavaAtomicBoolean)
JavaAtomicBoolean
when defined?(CAtomicBoolean)
when Concurrent.on_cruby? && Concurrent.c_extensions_loaded?
CAtomicBoolean
when Concurrent.on_jruby?
JavaAtomicBoolean
else
MutexAtomicBoolean
end
Expand Down
9 changes: 5 additions & 4 deletions lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'concurrent/utility/native_extension_loader' # load native parts first

require 'concurrent/atomic/mutex_atomic_fixnum'
require 'concurrent/synchronization'

module Concurrent

Expand Down Expand Up @@ -96,10 +97,10 @@ module Concurrent
# @!visibility private
# @!macro internal_implementation_note
AtomicFixnumImplementation = case
when defined?(JavaAtomicFixnum)
JavaAtomicFixnum
when defined?(CAtomicFixnum)
when Concurrent.on_cruby? && Concurrent.c_extensions_loaded?
CAtomicFixnum
when Concurrent.on_jruby?
JavaAtomicFixnum
else
MutexAtomicFixnum
end
Expand Down
4 changes: 2 additions & 2 deletions lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require 'concurrent/synchronization'
require 'concurrent/utility/engine'
require 'concurrent/utility/native_extension_loader' # load native parts first

require 'concurrent/atomic_reference/numeric_cas_wrapper'

# Shim for TruffleRuby::AtomicReference
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
if Concurrent.on_jruby?
require 'concurrent/utility/native_extension_loader'

module Concurrent

Expand Down
16 changes: 11 additions & 5 deletions lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
require 'concurrent/synchronization'
require 'concurrent/synchronization/safe_initialization'

module Concurrent

# @!macro atomic_boolean
# @!visibility private
# @!macro internal_implementation_note
class MutexAtomicBoolean < Synchronization::LockableObject
class MutexAtomicBoolean
extend Concurrent::Synchronization::SafeInitialization

# @!macro atomic_boolean_method_initialize
def initialize(initial = false)
super()
synchronize { ns_initialize(initial) }
@Lock = ::Mutex.new
@value = !!initial
end

# @!macro atomic_boolean_method_value_get
Expand Down Expand Up @@ -46,8 +48,12 @@ def make_false
protected

# @!visibility private
def ns_initialize(initial)
@value = !!initial
def synchronize
if @Lock.owned?
yield
else
@Lock.synchronize { yield }
end
end

private
Expand Down
16 changes: 11 additions & 5 deletions lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
require 'concurrent/synchronization'
require 'concurrent/synchronization/safe_initialization'
require 'concurrent/utility/native_integer'

module Concurrent

# @!macro atomic_fixnum
# @!visibility private
# @!macro internal_implementation_note
class MutexAtomicFixnum < Synchronization::LockableObject
class MutexAtomicFixnum
extend Concurrent::Synchronization::SafeInitialization

# @!macro atomic_fixnum_method_initialize
def initialize(initial = 0)
super()
synchronize { ns_initialize(initial) }
@Lock = ::Mutex.new
ns_set(initial)
end

# @!macro atomic_fixnum_method_value_get
Expand Down Expand Up @@ -60,8 +62,12 @@ def update
protected

# @!visibility private
def ns_initialize(initial)
ns_set(initial)
def synchronize
if @Lock.owned?
yield
else
@Lock.synchronize { yield }
end
end

private
Expand Down
4 changes: 2 additions & 2 deletions lib/concurrent-ruby/concurrent/atomic/semaphore.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ module Concurrent

# @!visibility private
# @!macro internal_implementation_note
SemaphoreImplementation = case
when defined?(JavaSemaphore)
SemaphoreImplementation = if Concurrent.on_jruby?
require 'concurrent/utility/native_extension_loader'
JavaSemaphore
else
MutexSemaphore
Expand Down
17 changes: 13 additions & 4 deletions lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
require 'concurrent/synchronization/safe_initialization'

module Concurrent

# @!visibility private
# @!macro internal_implementation_note
class MutexAtomicReference < Synchronization::LockableObject
class MutexAtomicReference
extend Concurrent::Synchronization::SafeInitialization
include AtomicDirectUpdate
include AtomicNumericCompareAndSetWrapper
alias_method :compare_and_swap, :compare_and_set

# @!macro atomic_reference_method_initialize
def initialize(value = nil)
super()
synchronize { ns_initialize(value) }
@Lock = ::Mutex.new
@value = value
end

# @!macro atomic_reference_method_get
Expand Down Expand Up @@ -49,8 +53,13 @@ def _compare_and_set(old_value, new_value)

protected

def ns_initialize(value)
@value = value
# @!visibility private
def synchronize
if @Lock.owned?
yield
else
@Lock.synchronize { yield }
end
end
end
end
1 change: 1 addition & 0 deletions lib/concurrent-ruby/concurrent/exchanger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ def do_exchange(value, timeout)
end

if Concurrent.on_jruby?
require 'concurrent/utility/native_extension_loader'

# @!macro internal_implementation_note
# @!visibility private
Expand Down
1 change: 1 addition & 0 deletions lib/concurrent-ruby/concurrent/map.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module Collection
# @!visibility private
MapImplementation = case
when Concurrent.on_jruby?
require 'concurrent/utility/native_extension_loader'
# noinspection RubyResolve
JRubyMapBackend
when Concurrent.on_cruby?
Expand Down
7 changes: 0 additions & 7 deletions lib/concurrent-ruby/concurrent/synchronization.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
require 'concurrent/utility/engine'

require 'concurrent/synchronization/abstract_object'
require 'concurrent/utility/native_extension_loader' # load native parts first
Concurrent.load_native_extensions

require 'concurrent/synchronization/mri_object'
require 'concurrent/synchronization/jruby_object'
require 'concurrent/synchronization/truffleruby_object'
require 'concurrent/synchronization/object'
require 'concurrent/synchronization/volatile'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'concurrent/utility/native_extension_loader' # load native parts first

module Concurrent
module Synchronization

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ module Synchronization
# @!visibility private
# @!macro internal_implementation_note
class AbstractObject

# @abstract has to be implemented based on Ruby runtime
def initialize
raise NotImplementedError
# nothing to do
end

# @!visibility private
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require 'concurrent/utility/native_extension_loader' # load native parts first

module Concurrent
module Synchronization
case
when Concurrent.on_cruby?
def self.full_memory_barrier
# relying on undocumented behavior of CRuby, GVL acquire has lock which ensures visibility of ivars
# https://github.com/ruby/ruby/blob/ruby_2_2/thread_pthread.c#L204-L211
end

when Concurrent.on_jruby?
require 'concurrent/utility/native_extension_loader'
def self.full_memory_barrier
JRubyAttrVolatile.full_memory_barrier
end

when Concurrent.on_truffleruby?
def self.full_memory_barrier
TruffleRuby.full_memory_barrier
end

else
warn 'Possibly unsupported Ruby implementation'
def self.full_memory_barrier
end
end
end
end
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
require 'concurrent/utility/native_extension_loader' # load native parts first

module Concurrent
module Synchronization

if Concurrent.on_jruby? && Concurrent.java_extensions_loaded?
if Concurrent.on_jruby?

# @!visibility private
# @!macro internal_implementation_note
Expand Down
Loading