Skip to content

Commit 7b03abb

Browse files
committed
Synchronisation support for Java 7
1 parent a9da852 commit 7b03abb

File tree

1 file changed

+28
-21
lines changed

1 file changed

+28
-21
lines changed

ext/com/concurrent_ruby/ext/SynchronizationLibrary.java

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,17 @@ private RubyClass defineClass(Ruby runtime, RubyModule namespace, String parentN
7474
return newClass;
7575
}
7676

77+
// Facts:
78+
// - all ivar reads are without any synchronisation of fences see
79+
// https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/runtime/ivars/VariableAccessor.java#L110-110
80+
// - writes depend on UnsafeHolder.U, null -> SynchronizedVariableAccessor, !null -> StampedVariableAccessor
81+
// SynchronizedVariableAccessor wraps with synchronized block, StampedVariableAccessor uses fullFence or
82+
// volatilePut
83+
7784
@JRubyClass(name = "JRubyObject", parent = "AbstractObject")
7885
public static class JRubyObject extends RubyObject {
86+
private static volatile ThreadContext threadContext = null;
87+
7988
public JRubyObject(Ruby runtime, RubyClass metaClass) {
8089
super(runtime, metaClass);
8190
}
@@ -87,10 +96,12 @@ public IRubyObject initialize(ThreadContext context) {
8796

8897
@JRubyMethod(name = "full_memory_barrier", visibility = Visibility.PRIVATE)
8998
public IRubyObject fullMemoryBarrier(ThreadContext context) {
99+
// Prevent reordering of ivar writes with publication of this instance
90100
if (UnsafeHolder.U == null || !UnsafeHolder.SUPPORTS_FENCES) {
91-
throw new UnsupportedOperationException(
92-
"concurrent-ruby requires java with sun.mics.Unsafe fences support, such as Java 8. " +
93-
"Current version is: " + System.getProperty("java.version"));
101+
// Assuming that following volatile read and write is not eliminated it simulates fullFence.
102+
// If it's eliminated it'll cause problems only on non-x86 platforms.
103+
final ThreadContext oldContext = threadContext;
104+
threadContext = context;
94105
} else {
95106
UnsafeHolder.fullFence();
96107
}
@@ -99,34 +110,30 @@ public IRubyObject fullMemoryBarrier(ThreadContext context) {
99110

100111
@JRubyMethod(name = "instance_variable_get_volatile", visibility = Visibility.PROTECTED)
101112
public IRubyObject instanceVariableGetVolatile(ThreadContext context, IRubyObject name) {
102-
if (UnsafeHolder.U == null) {
103-
synchronized (this) {
104-
// TODO (pitr 06-Sep-2015): Possibly dangerous, there may be a deadlock here
105-
// TODO (pitr 08-Sep-2015): maybe remove the branch since full_memory_barrier is not supported anyway
106-
return instance_variable_get(context, name);
107-
}
108-
} else if (UnsafeHolder.SUPPORTS_FENCES) {
109-
// ensure we see latest value
110-
UnsafeHolder.loadFence();
113+
// Ensure we ses latest value with loadFence
114+
if (UnsafeHolder.U == null || !UnsafeHolder.SUPPORTS_FENCES) {
115+
// piggybacking on volatile read, simulating loadFence
116+
final ThreadContext oldContext = threadContext;
111117
return instance_variable_get(context, name);
112118
} else {
113-
throw new UnsupportedOperationException();
119+
UnsafeHolder.loadFence();
120+
return instance_variable_get(context, name);
114121
}
115122
}
116123

117124
@JRubyMethod(name = "instance_variable_set_volatile", visibility = Visibility.PROTECTED)
118125
public IRubyObject InstanceVariableSetVolatile(ThreadContext context, IRubyObject name, IRubyObject value) {
119-
if (UnsafeHolder.U == null) {
120-
synchronized (this) {
121-
return instance_variable_set(name, value);
122-
}
123-
} else if (UnsafeHolder.SUPPORTS_FENCES) {
126+
// Ensure we make last update visible
127+
if (UnsafeHolder.U == null || !UnsafeHolder.SUPPORTS_FENCES) {
128+
// piggybacking on volatile write, simulating storeFence
124129
final IRubyObject result = instance_variable_set(name, value);
125-
// ensure we make latest value visible
126-
UnsafeHolder.storeFence();
130+
threadContext = context;
127131
return result;
128132
} else {
129-
throw new UnsupportedOperationException();
133+
// JRuby uses StampedVariableAccessor which calls fullFence
134+
// so no additional steps needed.
135+
// See https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/runtime/ivars/StampedVariableAccessor.java#L151-L159
136+
return instance_variable_set(name, value);
130137
}
131138
}
132139
}

0 commit comments

Comments
 (0)