Skip to content

Commit 0628986

Browse files
committed
Ensure JRuby ivar volatility
1 parent a48afe8 commit 0628986

File tree

3 files changed

+65
-1
lines changed

3 files changed

+65
-1
lines changed

ext/com/concurrent_ruby/ext/SynchronizationLibrary.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.jruby.RubyBoolean;
1818
import org.jruby.RubyNil;
1919
import org.jruby.runtime.ThreadContext;
20+
import org.jruby.util.unsafe.UnsafeHolder;
2021

2122
public class SynchronizationLibrary implements Library {
2223

@@ -44,6 +45,8 @@ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
4445
@JRubyClass(name = "JavaObject", parent = "AbstractObject")
4546
public static class JavaObject extends RubyObject {
4647

48+
private volatile int anVolatileField = 0; // TODO unused on JAVA8
49+
4750
public JavaObject(Ruby runtime, RubyClass metaClass) {
4851
super(runtime, metaClass);
4952
}
@@ -108,7 +111,31 @@ public IRubyObject nsBroadcast(ThreadContext context) {
108111

109112
@JRubyMethod(name = "ensure_ivar_visibility!", visibility = Visibility.PROTECTED)
110113
public IRubyObject ensureIvarVisibilityBang(ThreadContext context) {
114+
if (UnsafeHolder.SUPPORTS_FENCES)
115+
UnsafeHolder.storeFence();
116+
else
117+
anVolatileField = 1;
111118
return context.nil;
112119
}
120+
121+
@JRubyMethod(name = "instance_variable_get_volatile", visibility = Visibility.PROTECTED)
122+
public IRubyObject instanceVariableGetVolatile(ThreadContext context, IRubyObject name) {
123+
int tmp;
124+
if (UnsafeHolder.SUPPORTS_FENCES)
125+
UnsafeHolder.loadFence();
126+
else
127+
tmp = anVolatileField;
128+
return instance_variable_get(context, name);
129+
}
130+
131+
@JRubyMethod(name = "instance_variable_set_volatile", visibility = Visibility.PROTECTED)
132+
public IRubyObject InstanceVariableSetVolatile(ThreadContext context, IRubyObject name, IRubyObject value) {
133+
IRubyObject result = instance_variable_set(name, value);
134+
if (UnsafeHolder.SUPPORTS_FENCES)
135+
UnsafeHolder.storeFence();
136+
else
137+
anVolatileField = 1;
138+
return result;
139+
}
113140
}
114141
}

lib/concurrent/synchronization.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
require 'concurrent/utility/engine'
22
require 'concurrent/synchronization/abstract_object'
3-
require 'concurrent/native_extensions' # JavaObject
3+
require 'concurrent/synchronization/java_object'
44
require 'concurrent/synchronization/mutex_object'
55
require 'concurrent/synchronization/monitor_object'
66
require 'concurrent/synchronization/rbx_object'
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
require 'concurrent/native_extensions' # load native part first
2+
3+
module Concurrent
4+
module Synchronization
5+
6+
if Concurrent.on_jruby?
7+
require 'jruby'
8+
9+
unless org.jruby.util.unsafe.UnsafeHolder::SUPPORTS_FENCES
10+
raise 'java7 is not supported at the moment, please use java8'
11+
end
12+
13+
class JavaObject < AbstractObject
14+
15+
def self.attr_volatile(*names)
16+
names.each do |name|
17+
18+
ivar = :"@volatile_#{name}"
19+
20+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
21+
def #{name}
22+
instance_variable_get_volatile(:#{ivar})
23+
end
24+
25+
def #{name}=(value)
26+
instance_variable_set_volatile(:#{ivar}, value)
27+
end
28+
RUBY
29+
30+
end
31+
names.map { |n| [n, :"#{n}="] }.flatten
32+
end
33+
34+
end
35+
end
36+
end
37+
end

0 commit comments

Comments
 (0)