Skip to content

Commit 9a80cbb

Browse files
move attr_volatile impl into module
1 parent c65962c commit 9a80cbb

File tree

4 files changed

+103
-76
lines changed

4 files changed

+103
-76
lines changed

ext/com/concurrent_ruby/ext/SynchronizationLibrary.java

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.jruby.RubyClass;
77
import org.jruby.RubyModule;
88
import org.jruby.RubyObject;
9+
import org.jruby.RubyBasicObject;
910
import org.jruby.anno.JRubyClass;
1011
import org.jruby.anno.JRubyMethod;
1112
import org.jruby.runtime.ObjectAllocator;
@@ -47,6 +48,9 @@ public void load(Ruby runtime, boolean wrap) throws IOException {
4748
defineModule("Concurrent").
4849
defineModuleUnder("Synchronization");
4950

51+
RubyModule jrubyAttrVolatileModule = synchronizationModule.defineModuleUnder("JRubyAttrVolatile");
52+
jrubyAttrVolatileModule.defineAnnotatedMethods(JRubyAttrVolatile.class);
53+
5054
defineClass(runtime, synchronizationModule, "AbstractObject", "JRubyObject",
5155
JRubyObject.class, JRUBY_OBJECT_ALLOCATOR);
5256

@@ -81,21 +85,12 @@ private RubyClass defineClass(Ruby runtime, RubyModule namespace, String parentN
8185
// SynchronizedVariableAccessor wraps with synchronized block, StampedVariableAccessor uses fullFence or
8286
// volatilePut
8387

84-
@JRubyClass(name = "JRubyObject", parent = "AbstractObject")
85-
public static class JRubyObject extends RubyObject {
88+
// module JRubyAttrVolatile
89+
public static class JRubyAttrVolatile {
8690
private static volatile ThreadContext threadContext = null;
8791

88-
public JRubyObject(Ruby runtime, RubyClass metaClass) {
89-
super(runtime, metaClass);
90-
}
91-
92-
@JRubyMethod
93-
public IRubyObject initialize(ThreadContext context) {
94-
return this;
95-
}
96-
9792
@JRubyMethod(name = "full_memory_barrier", visibility = Visibility.PRIVATE)
98-
public IRubyObject fullMemoryBarrier(ThreadContext context) {
93+
public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject self) {
9994
// Prevent reordering of ivar writes with publication of this instance
10095
if (UnsafeHolder.U == null || !UnsafeHolder.SUPPORTS_FENCES) {
10196
// Assuming that following volatile read and write is not eliminated it simulates fullFence.
@@ -109,35 +104,43 @@ public IRubyObject fullMemoryBarrier(ThreadContext context) {
109104
}
110105

111106
@JRubyMethod(name = "instance_variable_get_volatile", visibility = Visibility.PROTECTED)
112-
public IRubyObject instanceVariableGetVolatile(ThreadContext context, IRubyObject name) {
107+
public static IRubyObject instanceVariableGetVolatile(ThreadContext context, IRubyObject self, IRubyObject name) {
113108
// Ensure we ses latest value with loadFence
114109
if (UnsafeHolder.U == null || !UnsafeHolder.SUPPORTS_FENCES) {
115110
// piggybacking on volatile read, simulating loadFence
116111
final ThreadContext oldContext = threadContext;
117-
return instance_variable_get(context, name);
112+
return ((RubyBasicObject)self).instance_variable_get(context, name);
118113
} else {
119114
UnsafeHolder.loadFence();
120-
return instance_variable_get(context, name);
115+
return ((RubyBasicObject)self).instance_variable_get(context, name);
121116
}
122117
}
123118

124119
@JRubyMethod(name = "instance_variable_set_volatile", visibility = Visibility.PROTECTED)
125-
public IRubyObject InstanceVariableSetVolatile(ThreadContext context, IRubyObject name, IRubyObject value) {
120+
public static IRubyObject InstanceVariableSetVolatile(ThreadContext context, IRubyObject self, IRubyObject name, IRubyObject value) {
126121
// Ensure we make last update visible
127122
if (UnsafeHolder.U == null || !UnsafeHolder.SUPPORTS_FENCES) {
128123
// piggybacking on volatile write, simulating storeFence
129-
final IRubyObject result = instance_variable_set(name, value);
124+
final IRubyObject result = ((RubyBasicObject)self).instance_variable_set(name, value);
130125
threadContext = context;
131126
return result;
132127
} else {
133128
// JRuby uses StampedVariableAccessor which calls fullFence
134129
// so no additional steps needed.
135130
// 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);
131+
return ((RubyBasicObject)self).instance_variable_set(name, value);
137132
}
138133
}
139134
}
140135

136+
@JRubyClass(name = "JRubyObject", parent = "AbstractObject")
137+
public static class JRubyObject extends RubyObject {
138+
139+
public JRubyObject(Ruby runtime, RubyClass metaClass) {
140+
super(runtime, metaClass);
141+
}
142+
}
143+
141144
@JRubyClass(name = "Object", parent = "JRubyObject")
142145
public static class Object extends JRubyObject {
143146

lib/concurrent/synchronization/jruby_object.rb

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,41 @@ module Synchronization
33

44
if Concurrent.on_jruby?
55

6-
# @!visibility private
7-
# @!macro internal_implementation_note
8-
class JRubyObject < AbstractObject
9-
10-
def initialize
11-
# nothing to do
6+
module JRubyAttrVolatile
7+
def self.included(base)
8+
base.extend(ClassMethods)
129
end
1310

14-
def self.attr_volatile(*names)
15-
names.each do |name|
11+
module ClassMethods
12+
def attr_volatile(*names)
13+
names.each do |name|
1614

17-
ivar = :"@volatile_#{name}"
15+
ivar = :"@volatile_#{name}"
1816

19-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
20-
def #{name}
21-
instance_variable_get_volatile(:#{ivar})
22-
end
17+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
18+
def #{name}
19+
instance_variable_get_volatile(:#{ivar})
20+
end
2321
24-
def #{name}=(value)
25-
instance_variable_set_volatile(:#{ivar}, value)
26-
end
27-
RUBY
22+
def #{name}=(value)
23+
instance_variable_set_volatile(:#{ivar}, value)
24+
end
25+
RUBY
2826

27+
end
28+
names.map { |n| [n, :"#{n}="] }.flatten
2929
end
30-
names.map { |n| [n, :"#{n}="] }.flatten
3130
end
31+
end
3232

33+
# @!visibility private
34+
# @!macro internal_implementation_note
35+
class JRubyObject < AbstractObject
36+
include JRubyAttrVolatile
37+
38+
def initialize
39+
# nothing to do
40+
end
3341
end
3442
end
3543
end
Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,43 @@
11
module Concurrent
22
module Synchronization
33

4-
# @!visibility private
5-
# @!macro internal_implementation_note
6-
class MriObject < AbstractObject
4+
module MriAttrVolatile
5+
def self.included(base)
6+
base.extend(ClassMethods)
7+
end
78

8-
def initialize
9-
# nothing to do
9+
module ClassMethods
10+
def attr_volatile(*names)
11+
names.each do |name|
12+
ivar = :"@volatile_#{name}"
13+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
14+
def #{name}
15+
#{ivar}
16+
end
17+
18+
def #{name}=(value)
19+
#{ivar} = value
20+
end
21+
RUBY
22+
end
23+
names.map { |n| [n, :"#{n}="] }.flatten
24+
end
1025
end
1126

1227
def full_memory_barrier
1328
# relying on undocumented behavior of CRuby, GVL acquire has lock which ensures visibility of ivars
1429
# https://github.com/ruby/ruby/blob/ruby_2_2/thread_pthread.c#L204-L211
1530
end
31+
end
1632

17-
def self.attr_volatile(*names)
18-
names.each do |name|
19-
ivar = :"@volatile_#{name}"
20-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
21-
def #{name}
22-
#{ivar}
23-
end
33+
# @!visibility private
34+
# @!macro internal_implementation_note
35+
class MriObject < AbstractObject
36+
include MriAttrVolatile
2437

25-
def #{name}=(value)
26-
#{ivar} = value
27-
end
28-
RUBY
29-
end
30-
names.map { |n| [n, :"#{n}="] }.flatten
38+
def initialize
39+
# nothing to do
3140
end
3241
end
33-
3442
end
3543
end
Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,45 @@
11
module Concurrent
22
module Synchronization
33

4+
module RbxAttrVolatile
5+
def self.included(base)
6+
base.extend(ClassMethods)
7+
end
48

5-
# @!visibility private
6-
# @!macro internal_implementation_note
7-
class RbxObject < AbstractObject
8-
def initialize
9-
# nothing to do
9+
module ClassMethods
10+
def attr_volatile(*names)
11+
names.each do |name|
12+
ivar = :"@volatile_#{name}"
13+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
14+
def #{name}
15+
Rubinius.memory_barrier
16+
#{ivar}
17+
end
18+
19+
def #{name}=(value)
20+
#{ivar} = value
21+
Rubinius.memory_barrier
22+
end
23+
RUBY
24+
end
25+
names.map { |n| [n, :"#{n}="] }.flatten
26+
end
1027
end
1128

1229
def full_memory_barrier
1330
# Rubinius instance variables are not volatile so we need to insert barrier
1431
Rubinius.memory_barrier
1532
end
33+
end
1634

17-
def self.attr_volatile *names
18-
names.each do |name|
19-
ivar = :"@volatile_#{name}"
20-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
21-
def #{name}
22-
Rubinius.memory_barrier
23-
#{ivar}
24-
end
35+
# @!visibility private
36+
# @!macro internal_implementation_note
37+
class RbxObject < AbstractObject
38+
include RbxAttrVolatile
2539

26-
def #{name}=(value)
27-
#{ivar} = value
28-
Rubinius.memory_barrier
29-
end
30-
RUBY
31-
end
32-
names.map { |n| [n, :"#{n}="] }.flatten
40+
def initialize
41+
# nothing to do
3342
end
3443
end
35-
3644
end
3745
end

0 commit comments

Comments
 (0)