1
1
package com .concurrent_ruby .ext ;
2
2
3
3
import java .io .IOException ;
4
- import java .util .concurrent .atomic .AtomicBoolean ;
5
4
6
5
import org .jruby .Ruby ;
7
6
import org .jruby .RubyClass ;
14
13
import org .jruby .runtime .load .Library ;
15
14
import org .jruby .runtime .Block ;
16
15
import org .jruby .runtime .Visibility ;
17
- import org .jruby .RubyBoolean ;
18
- import org .jruby .RubyNil ;
19
16
import org .jruby .runtime .ThreadContext ;
20
17
import org .jruby .util .unsafe .UnsafeHolder ;
21
18
22
19
public class SynchronizationLibrary implements Library {
23
20
24
- private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator () {
21
+ private static final ObjectAllocator JRUBY_OBJECT_ALLOCATOR = new ObjectAllocator () {
25
22
public IRubyObject allocate (Ruby runtime , RubyClass klazz ) {
26
- return new JavaObject (runtime , klazz );
23
+ return new JRubyObject (runtime , klazz );
24
+ }
25
+ };
26
+
27
+ private static final ObjectAllocator OBJECT_ALLOCATOR = new ObjectAllocator () {
28
+ public IRubyObject allocate (Ruby runtime , RubyClass klazz ) {
29
+ return new Object (runtime , klazz );
30
+ }
31
+ };
32
+
33
+ private static final ObjectAllocator ABSTRACT_LOCKABLE_OBJECT_ALLOCATOR = new ObjectAllocator () {
34
+ public IRubyObject allocate (Ruby runtime , RubyClass klazz ) {
35
+ return new AbstractLockableObject (runtime , klazz );
36
+ }
37
+ };
38
+
39
+ private static final ObjectAllocator JRUBY_LOCKABLE_OBJECT_ALLOCATOR = new ObjectAllocator () {
40
+ public IRubyObject allocate (Ruby runtime , RubyClass klazz ) {
41
+ return new JRubyLockableObject (runtime , klazz );
27
42
}
28
43
};
29
44
30
45
public void load (Ruby runtime , boolean wrap ) throws IOException {
31
46
RubyModule synchronizationModule = runtime .
32
47
defineModule ("Concurrent" ).
33
48
defineModuleUnder ("Synchronization" );
34
- RubyClass parentClass = synchronizationModule .getClass ("AbstractObject" );
35
49
36
- if ( parentClass == null )
37
- throw runtime . newRuntimeError ( "Concurrent::Synchronization::AbstractObject is missing" );
50
+ defineClass ( runtime , synchronizationModule , "AbstractObject" , "JRubyObject" ,
51
+ JRubyObject . class , JRUBY_OBJECT_ALLOCATOR );
38
52
39
- RubyClass synchronizedObjectJavaClass =
40
- synchronizationModule . defineClassUnder ( "JavaObject" , parentClass , JRUBYREFERENCE_ALLOCATOR );
53
+ defineClass ( runtime , synchronizationModule , "JRubyObject" , "Object" ,
54
+ Object . class , OBJECT_ALLOCATOR );
41
55
42
- synchronizedObjectJavaClass .defineAnnotatedMethods (JavaObject .class );
56
+ defineClass (runtime , synchronizationModule , "Object" , "AbstractLockableObject" ,
57
+ AbstractLockableObject .class , ABSTRACT_LOCKABLE_OBJECT_ALLOCATOR );
58
+
59
+ defineClass (runtime , synchronizationModule , "AbstractLockableObject" , "JRubyLockableObject" ,
60
+ JRubyLockableObject .class , JRUBY_LOCKABLE_OBJECT_ALLOCATOR );
43
61
}
44
62
45
- @ JRubyClass (name = "JavaObject" , parent = "AbstractObject" )
46
- public static class JavaObject extends RubyObject {
63
+ private RubyClass defineClass (Ruby runtime , RubyModule namespace , String parentName , String name ,
64
+ Class javaImplementation , ObjectAllocator allocator ) {
65
+ final RubyClass parentClass = namespace .getClass (parentName );
47
66
48
- public static final long AN_VOLATILE_FIELD_OFFSET =
49
- UnsafeHolder .fieldOffset (JavaObject .class , "anVolatileField" );
50
- private volatile int anVolatileField = 0 ;
67
+ if (parentClass == null ) {
68
+ System .out .println ("not found " + parentName );
69
+ throw runtime .newRuntimeError (namespace .toString () + "::" + parentName + " is missing" );
70
+ }
51
71
52
- public JavaObject (Ruby runtime , RubyClass metaClass ) {
72
+ final RubyClass newClass = namespace .defineClassUnder (name , parentClass , allocator );
73
+ newClass .defineAnnotatedMethods (javaImplementation );
74
+ return newClass ;
75
+ }
76
+
77
+ @ JRubyClass (name = "JRubyObject" , parent = "AbstractObject" )
78
+ public static class JRubyObject extends RubyObject {
79
+ public JRubyObject (Ruby runtime , RubyClass metaClass ) {
53
80
super (runtime , metaClass );
54
81
}
55
82
@@ -58,6 +85,77 @@ public IRubyObject initialize(ThreadContext context) {
58
85
return this ;
59
86
}
60
87
88
+ @ JRubyMethod (name = "full_memory_barrier" , visibility = Visibility .PRIVATE )
89
+ public IRubyObject fullMemoryBarrier (ThreadContext context ) {
90
+ if (UnsafeHolder .U == null ) {
91
+ // We are screwed
92
+ throw new UnsupportedOperationException ();
93
+ } else if (UnsafeHolder .SUPPORTS_FENCES )
94
+ UnsafeHolder .fullFence ();
95
+ else {
96
+ // TODO (pitr 06-Sep-2015): enforce Java 8
97
+ throw new UnsupportedOperationException ();
98
+ }
99
+ return context .nil ;
100
+ }
101
+
102
+ @ JRubyMethod (name = "instance_variable_get_volatile" , visibility = Visibility .PROTECTED )
103
+ public IRubyObject instanceVariableGetVolatile (ThreadContext context , IRubyObject name ) {
104
+ if (UnsafeHolder .U == null ) {
105
+ synchronized (this ) {
106
+ // TODO (pitr 06-Sep-2015): Possibly dangerous, there may be a deadlock here
107
+ // TODO (pitr 08-Sep-2015): maybe remove the branch since full_memory_barrier is not supported anyway
108
+ return instance_variable_get (context , name );
109
+ }
110
+ } else if (UnsafeHolder .SUPPORTS_FENCES ) {
111
+ // ensure we see latest value
112
+ UnsafeHolder .loadFence ();
113
+ return instance_variable_get (context , name );
114
+ } else {
115
+ throw new UnsupportedOperationException ();
116
+ }
117
+ }
118
+
119
+ @ JRubyMethod (name = "instance_variable_set_volatile" , visibility = Visibility .PROTECTED )
120
+ public IRubyObject InstanceVariableSetVolatile (ThreadContext context , IRubyObject name , IRubyObject value ) {
121
+ if (UnsafeHolder .U == null ) {
122
+ synchronized (this ) {
123
+ return instance_variable_set (name , value );
124
+ }
125
+ } else if (UnsafeHolder .SUPPORTS_FENCES ) {
126
+ final IRubyObject result = instance_variable_set (name , value );
127
+ // ensure we make latest value visible
128
+ UnsafeHolder .storeFence ();
129
+ return result ;
130
+ } else {
131
+ throw new UnsupportedOperationException ();
132
+ }
133
+ }
134
+ }
135
+
136
+ @ JRubyClass (name = "Object" , parent = "JRubyObject" )
137
+ public static class Object extends JRubyObject {
138
+
139
+ public Object (Ruby runtime , RubyClass metaClass ) {
140
+ super (runtime , metaClass );
141
+ }
142
+ }
143
+
144
+ @ JRubyClass (name = "AbstractLockableObject" , parent = "Object" )
145
+ public static class AbstractLockableObject extends Object {
146
+
147
+ public AbstractLockableObject (Ruby runtime , RubyClass metaClass ) {
148
+ super (runtime , metaClass );
149
+ }
150
+ }
151
+
152
+ @ JRubyClass (name = "JRubyLockableObject" , parent = "AbstractLockableObject" )
153
+ public static class JRubyLockableObject extends JRubyObject {
154
+
155
+ public JRubyLockableObject (Ruby runtime , RubyClass metaClass ) {
156
+ super (runtime , metaClass );
157
+ }
158
+
61
159
@ JRubyMethod (name = "synchronize" , visibility = Visibility .PROTECTED )
62
160
public IRubyObject rubySynchronize (ThreadContext context , Block block ) {
63
161
synchronized (this ) {
@@ -108,58 +206,5 @@ public IRubyObject nsBroadcast(ThreadContext context) {
108
206
notifyAll ();
109
207
return this ;
110
208
}
111
-
112
- @ JRubyMethod (name = "ensure_ivar_visibility!" , visibility = Visibility .PROTECTED )
113
- public IRubyObject ensureIvarVisibilityBang (ThreadContext context ) {
114
- if (UnsafeHolder .U == null ) {
115
- // We are screwed
116
- throw new UnsupportedOperationException ();
117
- } else if (UnsafeHolder .SUPPORTS_FENCES )
118
- // We have to prevent ivar writes to reordered with storing of the final instance reference
119
- // Therefore wee need a fullFence to prevent reordering in both directions.
120
- UnsafeHolder .fullFence ();
121
- else {
122
- // Assumption that this is not eliminated, if false it will break non x86 platforms.
123
- UnsafeHolder .U .putIntVolatile (this , AN_VOLATILE_FIELD_OFFSET , 1 );
124
- UnsafeHolder .U .getIntVolatile (this , AN_VOLATILE_FIELD_OFFSET );
125
- }
126
- return context .nil ;
127
- }
128
-
129
- @ JRubyMethod (name = "instance_variable_get_volatile" , visibility = Visibility .PROTECTED )
130
- public IRubyObject instanceVariableGetVolatile (ThreadContext context , IRubyObject name ) {
131
- if (UnsafeHolder .U == null ) {
132
- // TODO: Possibly dangerous, there may be a deadlock on the this
133
- synchronized (this ) {
134
- return instance_variable_get (context , name );
135
- }
136
- } else if (UnsafeHolder .SUPPORTS_FENCES ) {
137
- // ensure we see latest value
138
- UnsafeHolder .loadFence ();
139
- return instance_variable_get (context , name );
140
- } else {
141
- UnsafeHolder .U .getIntVolatile (this , AN_VOLATILE_FIELD_OFFSET );
142
- return instance_variable_get (context , name );
143
- }
144
- }
145
-
146
- @ JRubyMethod (name = "instance_variable_set_volatile" , visibility = Visibility .PROTECTED )
147
- public IRubyObject InstanceVariableSetVolatile (ThreadContext context , IRubyObject name , IRubyObject value ) {
148
- if (UnsafeHolder .U == null ) {
149
- // TODO: Possibly dangerous, there may be a deadlock on the this
150
- synchronized (this ) {
151
- return instance_variable_set (name , value );
152
- }
153
- } else if (UnsafeHolder .SUPPORTS_FENCES ) {
154
- final IRubyObject result = instance_variable_set (name , value );
155
- // ensure we make latest value visible
156
- UnsafeHolder .storeFence ();
157
- return result ;
158
- } else {
159
- final IRubyObject result = instance_variable_set (name , value );
160
- UnsafeHolder .U .putIntVolatile (this , AN_VOLATILE_FIELD_OFFSET , 1 );
161
- return result ;
162
- }
163
- }
164
209
}
165
210
}
0 commit comments