o-concurrent-ruby 1.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +542 -0
  3. data/Gemfile +37 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +404 -0
  6. data/Rakefile +307 -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-ruby/concurrent/agent.rb +587 -0
  23. data/lib/concurrent-ruby/concurrent/array.rb +66 -0
  24. data/lib/concurrent-ruby/concurrent/async.rb +449 -0
  25. data/lib/concurrent-ruby/concurrent/atom.rb +222 -0
  26. data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +66 -0
  27. data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +126 -0
  28. data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +143 -0
  29. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
  30. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +205 -0
  31. data/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb +100 -0
  32. data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +128 -0
  33. data/lib/concurrent-ruby/concurrent/atomic/event.rb +109 -0
  34. data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +42 -0
  35. data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +37 -0
  36. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
  37. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
  38. data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +44 -0
  39. data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +131 -0
  40. data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +254 -0
  41. data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +377 -0
  42. data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +181 -0
  43. data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +166 -0
  44. data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +104 -0
  45. data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +56 -0
  46. data/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
  47. data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
  48. data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
  49. data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +111 -0
  50. data/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
  51. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
  52. data/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
  53. data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +66 -0
  54. data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +140 -0
  55. data/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb +82 -0
  56. data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
  57. data/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
  58. data/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +160 -0
  59. data/lib/concurrent-ruby/concurrent/concern/deprecation.rb +34 -0
  60. data/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb +73 -0
  61. data/lib/concurrent-ruby/concurrent/concern/logging.rb +32 -0
  62. data/lib/concurrent-ruby/concurrent/concern/obligation.rb +220 -0
  63. data/lib/concurrent-ruby/concurrent/concern/observable.rb +110 -0
  64. data/lib/concurrent-ruby/concurrent/configuration.rb +188 -0
  65. data/lib/concurrent-ruby/concurrent/constants.rb +8 -0
  66. data/lib/concurrent-ruby/concurrent/dataflow.rb +81 -0
  67. data/lib/concurrent-ruby/concurrent/delay.rb +199 -0
  68. data/lib/concurrent-ruby/concurrent/errors.rb +69 -0
  69. data/lib/concurrent-ruby/concurrent/exchanger.rb +352 -0
  70. data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +131 -0
  71. data/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb +62 -0
  72. data/lib/concurrent-ruby/concurrent/executor/executor_service.rb +185 -0
  73. data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +220 -0
  74. data/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb +66 -0
  75. data/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb +44 -0
  76. data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +103 -0
  77. data/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb +30 -0
  78. data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +140 -0
  79. data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +82 -0
  80. data/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb +21 -0
  81. data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +368 -0
  82. data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +35 -0
  83. data/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb +34 -0
  84. data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +107 -0
  85. data/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb +28 -0
  86. data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +100 -0
  87. data/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb +57 -0
  88. data/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb +88 -0
  89. data/lib/concurrent-ruby/concurrent/executor/timer_set.rb +172 -0
  90. data/lib/concurrent-ruby/concurrent/executors.rb +20 -0
  91. data/lib/concurrent-ruby/concurrent/future.rb +141 -0
  92. data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
  93. data/lib/concurrent-ruby/concurrent/immutable_struct.rb +101 -0
  94. data/lib/concurrent-ruby/concurrent/ivar.rb +207 -0
  95. data/lib/concurrent-ruby/concurrent/map.rb +346 -0
  96. data/lib/concurrent-ruby/concurrent/maybe.rb +229 -0
  97. data/lib/concurrent-ruby/concurrent/mutable_struct.rb +239 -0
  98. data/lib/concurrent-ruby/concurrent/mvar.rb +242 -0
  99. data/lib/concurrent-ruby/concurrent/options.rb +42 -0
  100. data/lib/concurrent-ruby/concurrent/promise.rb +580 -0
  101. data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
  102. data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
  103. data/lib/concurrent-ruby/concurrent/scheduled_task.rb +331 -0
  104. data/lib/concurrent-ruby/concurrent/set.rb +74 -0
  105. data/lib/concurrent-ruby/concurrent/settable_struct.rb +139 -0
  106. data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +98 -0
  107. data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +24 -0
  108. data/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb +171 -0
  109. data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +60 -0
  110. data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +13 -0
  111. data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +45 -0
  112. data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +36 -0
  113. data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +72 -0
  114. data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +44 -0
  115. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +88 -0
  116. data/lib/concurrent-ruby/concurrent/synchronization/object.rb +183 -0
  117. data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +71 -0
  118. data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +49 -0
  119. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
  120. data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +36 -0
  121. data/lib/concurrent-ruby/concurrent/synchronization.rb +30 -0
  122. data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +50 -0
  123. data/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb +74 -0
  124. data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
  125. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +88 -0
  126. data/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
  127. data/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb +246 -0
  128. data/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb +75 -0
  129. data/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
  130. data/lib/concurrent-ruby/concurrent/thread_safe/util.rb +16 -0
  131. data/lib/concurrent-ruby/concurrent/timer_task.rb +311 -0
  132. data/lib/concurrent-ruby/concurrent/tuple.rb +86 -0
  133. data/lib/concurrent-ruby/concurrent/tvar.rb +221 -0
  134. data/lib/concurrent-ruby/concurrent/utility/engine.rb +56 -0
  135. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -0
  136. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
  137. data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +53 -0
  138. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +130 -0
  139. data/lib/concurrent-ruby/concurrent/version.rb +3 -0
  140. data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
  141. data/lib/concurrent-ruby/concurrent.rb +134 -0
  142. metadata +192 -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
+ }