concurrent-ruby 1.0.5 → 1.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +155 -0
  3. data/Gemfile +37 -0
  4. data/LICENSE.txt +18 -18
  5. data/README.md +260 -103
  6. data/Rakefile +329 -0
  7. data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
  9. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
  10. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
  11. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
  12. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +189 -0
  13. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +307 -0
  14. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
  15. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
  16. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
  17. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
  18. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
  19. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
  20. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
  21. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
  22. data/lib/{concurrent → concurrent-ruby/concurrent}/agent.rb +7 -7
  23. data/lib/concurrent-ruby/concurrent/array.rb +66 -0
  24. data/lib/{concurrent → concurrent-ruby/concurrent}/async.rb +28 -24
  25. data/lib/{concurrent → concurrent-ruby/concurrent}/atom.rb +10 -10
  26. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_boolean.rb +26 -22
  27. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_fixnum.rb +27 -23
  28. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
  29. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +205 -0
  30. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/count_down_latch.rb +7 -7
  31. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/cyclic_barrier.rb +1 -1
  32. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/event.rb +3 -3
  33. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_count_down_latch.rb +9 -6
  34. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_boolean.rb +2 -0
  35. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_count_down_latch.rb +1 -0
  36. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_semaphore.rb +18 -2
  37. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/read_write_lock.rb +2 -1
  38. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/reentrant_read_write_lock.rb +7 -7
  39. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/ruby_thread_local_var.rb +60 -40
  40. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/semaphore.rb +34 -13
  41. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/thread_local_var.rb +8 -8
  42. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/mutex_atomic.rb +3 -8
  43. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/numeric_cas_wrapper.rb +1 -1
  44. data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
  45. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
  46. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/atomic_reference_map_backend.rb +3 -3
  47. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/mri_map_backend.rb +1 -1
  48. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/non_concurrent_map_backend.rb +1 -2
  49. data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
  50. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/non_concurrent_priority_queue.rb +30 -30
  51. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb +11 -1
  52. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/dereferenceable.rb +3 -3
  53. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/logging.rb +6 -1
  54. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/observable.rb +7 -7
  55. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  56. data/lib/{concurrent → concurrent-ruby/concurrent}/configuration.rb +15 -15
  57. data/lib/{concurrent → concurrent-ruby/concurrent}/constants.rb +1 -1
  58. data/lib/{concurrent → concurrent-ruby/concurrent}/dataflow.rb +2 -1
  59. data/lib/{concurrent → concurrent-ruby/concurrent}/delay.rb +9 -7
  60. data/lib/{concurrent → concurrent-ruby/concurrent}/exchanger.rb +21 -25
  61. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/abstract_executor_service.rb +35 -38
  62. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/cached_thread_pool.rb +5 -5
  63. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/executor_service.rb +17 -17
  64. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/fixed_thread_pool.rb +47 -33
  65. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_executor_service.rb +20 -17
  66. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_single_thread_executor.rb +4 -3
  67. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_thread_pool_executor.rb +29 -9
  68. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_executor_service.rb +10 -6
  69. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_single_thread_executor.rb +0 -1
  70. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_thread_pool_executor.rb +46 -42
  71. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/safe_task_executor.rb +5 -5
  72. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/simple_executor_service.rb +1 -1
  73. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/single_thread_executor.rb +3 -2
  74. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/thread_pool_executor.rb +7 -6
  75. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/timer_set.rb +14 -17
  76. data/lib/{concurrent → concurrent-ruby/concurrent}/future.rb +4 -1
  77. data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
  78. data/lib/{concurrent → concurrent-ruby/concurrent}/immutable_struct.rb +9 -1
  79. data/lib/{concurrent → concurrent-ruby/concurrent}/ivar.rb +5 -6
  80. data/lib/concurrent-ruby/concurrent/map.rb +346 -0
  81. data/lib/{concurrent → concurrent-ruby/concurrent}/maybe.rb +1 -1
  82. data/lib/{concurrent → concurrent-ruby/concurrent}/mutable_struct.rb +27 -16
  83. data/lib/{concurrent → concurrent-ruby/concurrent}/mvar.rb +2 -2
  84. data/lib/{concurrent → concurrent-ruby/concurrent}/promise.rb +54 -21
  85. data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
  86. data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
  87. data/lib/{concurrent → concurrent-ruby/concurrent}/scheduled_task.rb +29 -16
  88. data/lib/concurrent-ruby/concurrent/set.rb +74 -0
  89. data/lib/{concurrent → concurrent-ruby/concurrent}/settable_struct.rb +12 -1
  90. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_lockable_object.rb +5 -5
  91. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_struct.rb +18 -4
  92. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/condition.rb +2 -0
  93. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_object.rb +1 -0
  94. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lock.rb +2 -0
  95. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lockable_object.rb +8 -10
  96. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mri_object.rb +1 -0
  97. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +88 -0
  98. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/object.rb +53 -23
  99. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_lockable_object.rb +6 -0
  100. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_object.rb +1 -0
  101. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
  102. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/volatile.rb +11 -9
  103. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization.rb +4 -5
  104. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +88 -0
  105. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/striped64.rb +9 -4
  106. data/lib/{concurrent → concurrent-ruby/concurrent}/timer_task.rb +15 -35
  107. data/lib/{concurrent → concurrent-ruby/concurrent}/tuple.rb +1 -1
  108. data/lib/{concurrent → concurrent-ruby/concurrent}/tvar.rb +21 -58
  109. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/engine.rb +4 -4
  110. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -0
  111. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
  112. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/processor_counter.rb +5 -35
  113. data/lib/concurrent-ruby/concurrent/version.rb +3 -0
  114. data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
  115. data/lib/{concurrent.rb → concurrent-ruby/concurrent.rb} +24 -20
  116. metadata +149 -134
  117. data/lib/concurrent/array.rb +0 -39
  118. data/lib/concurrent/atomic/atomic_reference.rb +0 -51
  119. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +0 -8
  120. data/lib/concurrent/atomic_reference/direct_update.rb +0 -81
  121. data/lib/concurrent/atomic_reference/jruby+truffle.rb +0 -2
  122. data/lib/concurrent/atomic_reference/jruby.rb +0 -16
  123. data/lib/concurrent/atomic_reference/rbx.rb +0 -22
  124. data/lib/concurrent/atomic_reference/ruby.rb +0 -32
  125. data/lib/concurrent/atomics.rb +0 -53
  126. data/lib/concurrent/edge.rb +0 -26
  127. data/lib/concurrent/hash.rb +0 -36
  128. data/lib/concurrent/lazy_register.rb +0 -81
  129. data/lib/concurrent/map.rb +0 -240
  130. data/lib/concurrent/synchronization/mri_lockable_object.rb +0 -71
  131. data/lib/concurrent/synchronization/truffle_lockable_object.rb +0 -9
  132. data/lib/concurrent/synchronization/truffle_object.rb +0 -31
  133. data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +0 -30
  134. data/lib/concurrent/utility/at_exit.rb +0 -97
  135. data/lib/concurrent/utility/monotonic_time.rb +0 -58
  136. data/lib/concurrent/utility/native_extension_loader.rb +0 -73
  137. data/lib/concurrent/version.rb +0 -4
  138. /data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/abstract_thread_local_var.rb +0 -0
  139. /data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_thread_local_var.rb +0 -0
  140. /data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_fixnum.rb +0 -0
  141. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_notify_observer_set.rb +0 -0
  142. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_write_observer_set.rb +0 -0
  143. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/java_non_concurrent_priority_queue.rb +0 -0
  144. /data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/synchronized_map_backend.rb +0 -0
  145. /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/deprecation.rb +0 -0
  146. /data/lib/{concurrent → concurrent-ruby/concurrent}/concern/obligation.rb +0 -0
  147. /data/lib/{concurrent → concurrent-ruby/concurrent}/errors.rb +0 -0
  148. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/immediate_executor.rb +0 -0
  149. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/indirect_immediate_executor.rb +0 -0
  150. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serial_executor_service.rb +0 -0
  151. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution.rb +0 -0
  152. /data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution_delegator.rb +0 -0
  153. /data/lib/{concurrent → concurrent-ruby/concurrent}/executors.rb +0 -0
  154. /data/lib/{concurrent → concurrent-ruby/concurrent}/options.rb +0 -0
  155. /data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_object.rb +0 -0
  156. /data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_lockable_object.rb +0 -0
  157. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/synchronized_delegator.rb +0 -0
  158. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/adder.rb +0 -0
  159. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/cheap_lockable.rb +0 -0
  160. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/power_of_two_tuple.rb +0 -0
  161. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/volatile.rb +0 -0
  162. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/xor_shift_random.rb +0 -0
  163. /data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util.rb +0 -0
  164. /data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_integer.rb +0 -0
@@ -0,0 +1,307 @@
1
+ package com.concurrent_ruby.ext;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.RubyBasicObject;
5
+ import org.jruby.RubyClass;
6
+ import org.jruby.RubyModule;
7
+ import org.jruby.RubyObject;
8
+ import org.jruby.RubyThread;
9
+ import org.jruby.anno.JRubyClass;
10
+ import org.jruby.anno.JRubyMethod;
11
+ import org.jruby.runtime.Block;
12
+ import org.jruby.runtime.ObjectAllocator;
13
+ import org.jruby.runtime.ThreadContext;
14
+ import org.jruby.runtime.Visibility;
15
+ import org.jruby.runtime.builtin.IRubyObject;
16
+ import org.jruby.runtime.load.Library;
17
+ import sun.misc.Unsafe;
18
+
19
+ import java.io.IOException;
20
+ import java.lang.reflect.Field;
21
+ import java.lang.reflect.Method;
22
+
23
+ public class SynchronizationLibrary implements Library {
24
+
25
+ private static final Unsafe UNSAFE = loadUnsafe();
26
+ private static final boolean FULL_FENCE = supportsFences();
27
+
28
+ private static Unsafe loadUnsafe() {
29
+ try {
30
+ Class ncdfe = Class.forName("sun.misc.Unsafe");
31
+ Field f = ncdfe.getDeclaredField("theUnsafe");
32
+ f.setAccessible(true);
33
+ return (Unsafe) f.get((java.lang.Object) null);
34
+ } catch (Exception var2) {
35
+ return null;
36
+ } catch (NoClassDefFoundError var3) {
37
+ return null;
38
+ }
39
+ }
40
+
41
+ private static boolean supportsFences() {
42
+ if (UNSAFE == null) {
43
+ return false;
44
+ } else {
45
+ try {
46
+ Method m = UNSAFE.getClass().getDeclaredMethod("fullFence", new Class[0]);
47
+ if (m != null) {
48
+ return true;
49
+ }
50
+ } catch (Exception var1) {
51
+ // nothing
52
+ }
53
+
54
+ return false;
55
+ }
56
+ }
57
+
58
+ private static final ObjectAllocator JRUBY_OBJECT_ALLOCATOR = new ObjectAllocator() {
59
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
60
+ return new JRubyObject(runtime, klazz);
61
+ }
62
+ };
63
+
64
+ private static final ObjectAllocator OBJECT_ALLOCATOR = new ObjectAllocator() {
65
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
66
+ return new Object(runtime, klazz);
67
+ }
68
+ };
69
+
70
+ private static final ObjectAllocator ABSTRACT_LOCKABLE_OBJECT_ALLOCATOR = new ObjectAllocator() {
71
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
72
+ return new AbstractLockableObject(runtime, klazz);
73
+ }
74
+ };
75
+
76
+ private static final ObjectAllocator JRUBY_LOCKABLE_OBJECT_ALLOCATOR = new ObjectAllocator() {
77
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
78
+ return new JRubyLockableObject(runtime, klazz);
79
+ }
80
+ };
81
+
82
+ public void load(Ruby runtime, boolean wrap) throws IOException {
83
+ RubyModule synchronizationModule = runtime.
84
+ defineModule("Concurrent").
85
+ defineModuleUnder("Synchronization");
86
+
87
+ RubyModule jrubyAttrVolatileModule = synchronizationModule.defineModuleUnder("JRubyAttrVolatile");
88
+ jrubyAttrVolatileModule.defineAnnotatedMethods(JRubyAttrVolatile.class);
89
+
90
+ defineClass(runtime, synchronizationModule, "AbstractObject", "JRubyObject",
91
+ JRubyObject.class, JRUBY_OBJECT_ALLOCATOR);
92
+
93
+ defineClass(runtime, synchronizationModule, "JRubyObject", "Object",
94
+ Object.class, OBJECT_ALLOCATOR);
95
+
96
+ defineClass(runtime, synchronizationModule, "Object", "AbstractLockableObject",
97
+ AbstractLockableObject.class, ABSTRACT_LOCKABLE_OBJECT_ALLOCATOR);
98
+
99
+ defineClass(runtime, synchronizationModule, "AbstractLockableObject", "JRubyLockableObject",
100
+ JRubyLockableObject.class, JRUBY_LOCKABLE_OBJECT_ALLOCATOR);
101
+
102
+ defineClass(runtime, synchronizationModule, "Object", "JRuby",
103
+ JRuby.class, new ObjectAllocator() {
104
+ @Override
105
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
106
+ return new JRuby(runtime, klazz);
107
+ }
108
+ });
109
+ }
110
+
111
+ private RubyClass defineClass(
112
+ Ruby runtime,
113
+ RubyModule namespace,
114
+ String parentName,
115
+ String name,
116
+ Class javaImplementation,
117
+ ObjectAllocator allocator) {
118
+ final RubyClass parentClass = namespace.getClass(parentName);
119
+
120
+ if (parentClass == null) {
121
+ System.out.println("not found " + parentName);
122
+ throw runtime.newRuntimeError(namespace.toString() + "::" + parentName + " is missing");
123
+ }
124
+
125
+ final RubyClass newClass = namespace.defineClassUnder(name, parentClass, allocator);
126
+ newClass.defineAnnotatedMethods(javaImplementation);
127
+ return newClass;
128
+ }
129
+
130
+ // Facts:
131
+ // - all ivar reads are without any synchronisation of fences see
132
+ // https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/runtime/ivars/VariableAccessor.java#L110-110
133
+ // - writes depend on UnsafeHolder.U, null -> SynchronizedVariableAccessor, !null -> StampedVariableAccessor
134
+ // SynchronizedVariableAccessor wraps with synchronized block, StampedVariableAccessor uses fullFence or
135
+ // volatilePut
136
+ // TODO (pitr 16-Sep-2015): what do we do in Java 9 ?
137
+
138
+ // module JRubyAttrVolatile
139
+ public static class JRubyAttrVolatile {
140
+
141
+ // volatile threadContext is used as a memory barrier per the JVM memory model happens-before semantic
142
+ // on volatile fields. any volatile field could have been used but using the thread context is an
143
+ // attempt to avoid code elimination.
144
+ private static volatile int volatileField;
145
+
146
+ @JRubyMethod(name = "full_memory_barrier", visibility = Visibility.PUBLIC)
147
+ public static IRubyObject fullMemoryBarrier(ThreadContext context, IRubyObject self) {
148
+ // Prevent reordering of ivar writes with publication of this instance
149
+ if (!FULL_FENCE) {
150
+ // Assuming that following volatile read and write is not eliminated it simulates fullFence.
151
+ // If it's eliminated it'll cause problems only on non-x86 platforms.
152
+ // http://shipilev.net/blog/2014/jmm-pragmatics/#_happens_before_test_your_understanding
153
+ final int volatileRead = volatileField;
154
+ volatileField = context.getLine();
155
+ } else {
156
+ UNSAFE.fullFence();
157
+ }
158
+ return context.nil;
159
+ }
160
+
161
+ @JRubyMethod(name = "instance_variable_get_volatile", visibility = Visibility.PUBLIC)
162
+ public static IRubyObject instanceVariableGetVolatile(
163
+ ThreadContext context,
164
+ IRubyObject self,
165
+ IRubyObject name) {
166
+ // Ensure we ses latest value with loadFence
167
+ if (!FULL_FENCE) {
168
+ // piggybacking on volatile read, simulating loadFence
169
+ final int volatileRead = volatileField;
170
+ return ((RubyBasicObject) self).instance_variable_get(context, name);
171
+ } else {
172
+ UNSAFE.loadFence();
173
+ return ((RubyBasicObject) self).instance_variable_get(context, name);
174
+ }
175
+ }
176
+
177
+ @JRubyMethod(name = "instance_variable_set_volatile", visibility = Visibility.PUBLIC)
178
+ public static IRubyObject InstanceVariableSetVolatile(
179
+ ThreadContext context,
180
+ IRubyObject self,
181
+ IRubyObject name,
182
+ IRubyObject value) {
183
+ // Ensure we make last update visible
184
+ if (!FULL_FENCE) {
185
+ // piggybacking on volatile write, simulating storeFence
186
+ final IRubyObject result = ((RubyBasicObject) self).instance_variable_set(name, value);
187
+ volatileField = context.getLine();
188
+ return result;
189
+ } else {
190
+ // JRuby uses StampedVariableAccessor which calls fullFence
191
+ // so no additional steps needed.
192
+ // See https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/runtime/ivars/StampedVariableAccessor.java#L151-L159
193
+ return ((RubyBasicObject) self).instance_variable_set(name, value);
194
+ }
195
+ }
196
+ }
197
+
198
+ @JRubyClass(name = "JRubyObject", parent = "AbstractObject")
199
+ public static class JRubyObject extends RubyObject {
200
+
201
+ public JRubyObject(Ruby runtime, RubyClass metaClass) {
202
+ super(runtime, metaClass);
203
+ }
204
+ }
205
+
206
+ @JRubyClass(name = "Object", parent = "JRubyObject")
207
+ public static class Object extends JRubyObject {
208
+
209
+ public Object(Ruby runtime, RubyClass metaClass) {
210
+ super(runtime, metaClass);
211
+ }
212
+ }
213
+
214
+ @JRubyClass(name = "AbstractLockableObject", parent = "Object")
215
+ public static class AbstractLockableObject extends Object {
216
+
217
+ public AbstractLockableObject(Ruby runtime, RubyClass metaClass) {
218
+ super(runtime, metaClass);
219
+ }
220
+ }
221
+
222
+ @JRubyClass(name = "JRubyLockableObject", parent = "AbstractLockableObject")
223
+ public static class JRubyLockableObject extends JRubyObject {
224
+
225
+ public JRubyLockableObject(Ruby runtime, RubyClass metaClass) {
226
+ super(runtime, metaClass);
227
+ }
228
+
229
+ @JRubyMethod(name = "synchronize", visibility = Visibility.PROTECTED)
230
+ public IRubyObject rubySynchronize(ThreadContext context, Block block) {
231
+ synchronized (this) {
232
+ return block.yield(context, null);
233
+ }
234
+ }
235
+
236
+ @JRubyMethod(name = "ns_wait", optional = 1, visibility = Visibility.PROTECTED)
237
+ public IRubyObject nsWait(ThreadContext context, IRubyObject[] args) {
238
+ Ruby runtime = context.runtime;
239
+ if (args.length > 1) {
240
+ throw runtime.newArgumentError(args.length, 1);
241
+ }
242
+ Double timeout = null;
243
+ if (args.length > 0 && !args[0].isNil()) {
244
+ timeout = args[0].convertToFloat().getDoubleValue();
245
+ if (timeout < 0) {
246
+ throw runtime.newArgumentError("time interval must be positive");
247
+ }
248
+ }
249
+ if (Thread.interrupted()) {
250
+ throw runtime.newConcurrencyError("thread interrupted");
251
+ }
252
+ boolean success = false;
253
+ try {
254
+ success = context.getThread().wait_timeout(this, timeout);
255
+ } catch (InterruptedException ie) {
256
+ throw runtime.newConcurrencyError(ie.getLocalizedMessage());
257
+ } finally {
258
+ // An interrupt or timeout may have caused us to miss
259
+ // a notify that we consumed, so do another notify in
260
+ // case someone else is available to pick it up.
261
+ if (!success) {
262
+ this.notify();
263
+ }
264
+ }
265
+ return this;
266
+ }
267
+
268
+ @JRubyMethod(name = "ns_signal", visibility = Visibility.PROTECTED)
269
+ public IRubyObject nsSignal(ThreadContext context) {
270
+ notify();
271
+ return this;
272
+ }
273
+
274
+ @JRubyMethod(name = "ns_broadcast", visibility = Visibility.PROTECTED)
275
+ public IRubyObject nsBroadcast(ThreadContext context) {
276
+ notifyAll();
277
+ return this;
278
+ }
279
+ }
280
+
281
+ @JRubyClass(name = "JRuby")
282
+ public static class JRuby extends RubyObject {
283
+ public JRuby(Ruby runtime, RubyClass metaClass) {
284
+ super(runtime, metaClass);
285
+ }
286
+
287
+ @JRubyMethod(name = "sleep_interruptibly", visibility = Visibility.PUBLIC, module = true)
288
+ public static IRubyObject sleepInterruptibly(final ThreadContext context, IRubyObject receiver, final Block block) {
289
+ try {
290
+ context.getThread().executeBlockingTask(new RubyThread.BlockingTask() {
291
+ @Override
292
+ public void run() throws InterruptedException {
293
+ block.call(context);
294
+ }
295
+
296
+ @Override
297
+ public void wakeup() {
298
+ context.getThread().getNativeThread().interrupt();
299
+ }
300
+ });
301
+ } catch (InterruptedException e) {
302
+ throw context.runtime.newThreadError("interrupted in Concurrent::Synchronization::JRuby.sleep_interruptibly");
303
+ }
304
+ return context.nil;
305
+ }
306
+ }
307
+ }
@@ -0,0 +1,31 @@
1
+ package com.concurrent_ruby.ext.jsr166e;
2
+
3
+ import java.util.Map;
4
+ import java.util.Set;
5
+
6
+ public interface ConcurrentHashMap<K, V> {
7
+ /** Interface describing a function of one argument */
8
+ public interface Fun<A,T> { T apply(A a); }
9
+ /** Interface describing a function of two arguments */
10
+ public interface BiFun<A,B,T> { T apply(A a, B b); }
11
+
12
+ public V get(K key);
13
+ public V put(K key, V value);
14
+ public V putIfAbsent(K key, V value);
15
+ public V computeIfAbsent(K key, Fun<? super K, ? extends V> mf);
16
+ public V computeIfPresent(K key, BiFun<? super K, ? super V, ? extends V> mf);
17
+ public V compute(K key, BiFun<? super K, ? super V, ? extends V> mf);
18
+ public V merge(K key, V value, BiFun<? super V, ? super V, ? extends V> mf);
19
+ public boolean replace(K key, V oldVal, V newVal);
20
+ public V replace(K key, V value);
21
+ public boolean containsKey(K key);
22
+ public boolean remove(Object key, Object value);
23
+ public V remove(K key);
24
+ public void clear();
25
+ public Set<Map.Entry<K,V>> entrySet();
26
+ public int size();
27
+ public V getValueOrDefault(Object key, V defaultValue);
28
+
29
+ public boolean containsValue(V value);
30
+ public K findKey(V value);
31
+ }