From a16ca012e0ac4240a6f24489e1c8b6cbc35567cc Mon Sep 17 00:00:00 2001 From: binji Date: Wed, 13 Jul 2016 11:29:48 -0700 Subject: [PATCH] [Atomics] Rename Atomics.futex*, remove Atomics.futexWakeOrRequeue * Rename Atomics.futexWait -> Atomics.wait * Rename Atomics.futexWake -> Atomics.wake * Remove Atomics.futexWakeOrRequeue * Return value of Atomics.wait is now a string: "ok", "not-equal" or "timed-out" * Update comments that reference URL for ecmascript_sharedmem to https://github.com/tc39/ecmascript_sharedmem Review-Url: https://codereview.chromium.org/2143443002 Cr-Commit-Position: refs/heads/master@{#37727} --- src/futex-emulation.cc | 44 +------- src/futex-emulation.h | 23 +--- src/heap-symbols.h | 3 + src/js/harmony-atomics.js | 35 +----- src/runtime/runtime-atomics.cc | 2 +- src/runtime/runtime-futex.cc | 32 +----- src/runtime/runtime.h | 12 +- test/cctest/test-api.cc | 2 +- test/mjsunit/harmony/futex.js | 193 ++++++--------------------------- 9 files changed, 56 insertions(+), 290 deletions(-) diff --git a/src/futex-emulation.cc b/src/futex-emulation.cc index 1f7e8a6d73..57894f14d3 100644 --- a/src/futex-emulation.cc +++ b/src/futex-emulation.cc @@ -84,7 +84,7 @@ Object* FutexEmulation::Wait(Isolate* isolate, base::LockGuard lock_guard(mutex_.Pointer()); if (*p != value) { - return Smi::FromInt(Result::kNotEqual); + return isolate->heap()->not_equal(); } FutexWaitListNode* node = isolate->futex_wait_list_node(); @@ -157,7 +157,7 @@ Object* FutexEmulation::Wait(Isolate* isolate, } if (!node->waiting_) { - result = Smi::FromInt(Result::kOk); + result = isolate->heap()->ok(); break; } @@ -165,7 +165,7 @@ Object* FutexEmulation::Wait(Isolate* isolate, if (use_timeout) { current_time = base::TimeTicks::Now(); if (current_time >= timeout_time) { - result = Smi::FromInt(Result::kTimedOut); + result = isolate->heap()->timed_out(); break; } @@ -213,44 +213,6 @@ Object* FutexEmulation::Wake(Isolate* isolate, } -Object* FutexEmulation::WakeOrRequeue(Isolate* isolate, - Handle array_buffer, - size_t addr, int num_waiters_to_wake, - int32_t value, size_t addr2) { - DCHECK(addr < NumberToSize(isolate, array_buffer->byte_length())); - DCHECK(addr2 < NumberToSize(isolate, array_buffer->byte_length())); - - void* backing_store = array_buffer->backing_store(); - int32_t* p = - reinterpret_cast(static_cast(backing_store) + addr); - - base::LockGuard lock_guard(mutex_.Pointer()); - if (*p != value) { - return Smi::FromInt(Result::kNotEqual); - } - - // Wake |num_waiters_to_wake| - int waiters_woken = 0; - FutexWaitListNode* node = wait_list_.Pointer()->head_; - while (node) { - if (backing_store == node->backing_store_ && addr == node->wait_addr_) { - if (num_waiters_to_wake > 0) { - node->waiting_ = false; - node->cond_.NotifyOne(); - --num_waiters_to_wake; - waiters_woken++; - } else { - node->wait_addr_ = addr2; - } - } - - node = node->next_; - } - - return Smi::FromInt(waiters_woken); -} - - Object* FutexEmulation::NumWaitersForTesting(Isolate* isolate, Handle array_buffer, size_t addr) { diff --git a/src/futex-emulation.h b/src/futex-emulation.h index 9949bdf44f..a0e2b18bdc 100644 --- a/src/futex-emulation.h +++ b/src/futex-emulation.h @@ -21,7 +21,7 @@ // variables for consistency. // // This is used by the Futex API defined in the SharedArrayBuffer draft spec, -// found here: https://github.com/lars-t-hansen/ecmascript_sharedmem +// found here: https://github.com/tc39/ecmascript_sharedmem namespace v8 { @@ -81,18 +81,11 @@ class FutexWaitList { class FutexEmulation : public AllStatic { public: - // These must match the values in src/harmony-atomics.js - enum Result { - kOk = 0, - kNotEqual = -1, - kTimedOut = -2, - }; - - // Check that array_buffer[addr] == value, and return kNotEqual if not. If + // Check that array_buffer[addr] == value, and return "not-equal" if not. If // they are equal, block execution on |isolate|'s thread until woken via // |Wake|, or when the time given in |rel_timeout_ms| elapses. Note that // |rel_timeout_ms| can be Infinity. - // If woken, return kOk, otherwise return kTimedOut. The initial check and + // If woken, return "ok", otherwise return "timed-out". The initial check and // the decision to wait happen atomically. static Object* Wait(Isolate* isolate, Handle array_buffer, size_t addr, int32_t value, double rel_timeout_ms); @@ -103,16 +96,6 @@ class FutexEmulation : public AllStatic { static Object* Wake(Isolate* isolate, Handle array_buffer, size_t addr, int num_waiters_to_wake); - // Check that array_buffer[addr] == value, and return kNotEqual if not. If - // they are equal, wake |num_waiters_to_wake| threads that are waiting on the - // given |addr|. The rest of the waiters will continue to wait, but will now - // be waiting on |addr2| instead of |addr|. The return value is the number of - // woken waiters or kNotEqual as described above. - static Object* WakeOrRequeue(Isolate* isolate, - Handle array_buffer, size_t addr, - int num_waiters_to_wake, int32_t value, - size_t addr2); - // Return the number of threads waiting on |addr|. Should only be used for // testing. static Object* NumWaitersForTesting(Isolate* isolate, diff --git a/src/heap-symbols.h b/src/heap-symbols.h index 94bfd226bb..8f8051bf7d 100644 --- a/src/heap-symbols.h +++ b/src/heap-symbols.h @@ -97,12 +97,14 @@ V(name_string, "name") \ V(nan_string, "NaN") \ V(next_string, "next") \ + V(not_equal, "not-equal") \ V(null_string, "null") \ V(null_to_string, "[object Null]") \ V(number_string, "number") \ V(Number_string, "Number") \ V(object_string, "object") \ V(Object_string, "Object") \ + V(ok, "ok") \ V(ownKeys_string, "ownKeys") \ V(position_string, "position") \ V(preventExtensions_string, "preventExtensions") \ @@ -129,6 +131,7 @@ V(Symbol_string, "Symbol") \ V(this_string, "this") \ V(throw_string, "throw") \ + V(timed_out, "timed-out") \ V(toJSON_string, "toJSON") \ V(toString_string, "toString") \ V(true_string, "true") \ diff --git a/src/js/harmony-atomics.js b/src/js/harmony-atomics.js index 8372903b29..5af55c2109 100644 --- a/src/js/harmony-atomics.js +++ b/src/js/harmony-atomics.js @@ -108,9 +108,7 @@ function AtomicsIsLockFreeJS(size) { return %_AtomicsIsLockFree(size); } -// Futexes - -function AtomicsFutexWaitJS(ia, index, value, timeout) { +function AtomicsWaitJS(ia, index, value, timeout) { CheckSharedInteger32TypedArray(ia); index = ValidateIndex(index, %_TypedArrayGetLength(ia)); if (IS_UNDEFINED(timeout)) { @@ -123,27 +121,14 @@ function AtomicsFutexWaitJS(ia, index, value, timeout) { timeout = MaxSimple(0, timeout); } } - return %AtomicsFutexWait(ia, index, value, timeout); + return %AtomicsWait(ia, index, value, timeout); } -function AtomicsFutexWakeJS(ia, index, count) { +function AtomicsWakeJS(ia, index, count) { CheckSharedInteger32TypedArray(ia); index = ValidateIndex(index, %_TypedArrayGetLength(ia)); count = MaxSimple(0, TO_INTEGER(count)); - return %AtomicsFutexWake(ia, index, count); -} - -function AtomicsFutexWakeOrRequeueJS(ia, index1, count, value, index2) { - CheckSharedInteger32TypedArray(ia); - index1 = ValidateIndex(index1, %_TypedArrayGetLength(ia)); - count = MaxSimple(0, TO_INTEGER(count)); - value = TO_INT32(value); - index2 = ValidateIndex(index2, %_TypedArrayGetLength(ia)); - if (index1 < 0 || index1 >= %_TypedArrayGetLength(ia) || - index2 < 0 || index2 >= %_TypedArrayGetLength(ia)) { - return UNDEFINED; - } - return %AtomicsFutexWakeOrRequeue(ia, index1, count, value, index2); + return %AtomicsWake(ia, index, count); } // ------------------------------------------------------------------- @@ -154,13 +139,6 @@ var Atomics = global.Atomics; %AddNamedProperty(Atomics, toStringTagSymbol, "Atomics", READ_ONLY | DONT_ENUM); -// These must match the values in src/futex-emulation.h -utils.InstallConstants(Atomics, [ - "OK", 0, - "NOTEQUAL", -1, - "TIMEDOUT", -2, -]); - utils.InstallFunctions(Atomics, DONT_ENUM, [ // TODO(binji): remove the rest of the (non futex) Atomics functions as they // become builtins. @@ -172,9 +150,8 @@ utils.InstallFunctions(Atomics, DONT_ENUM, [ "xor", AtomicsXorJS, "exchange", AtomicsExchangeJS, "isLockFree", AtomicsIsLockFreeJS, - "futexWait", AtomicsFutexWaitJS, - "futexWake", AtomicsFutexWakeJS, - "futexWakeOrRequeue", AtomicsFutexWakeOrRequeueJS, + "wait", AtomicsWaitJS, + "wake", AtomicsWakeJS, ]); }) diff --git a/src/runtime/runtime-atomics.cc b/src/runtime/runtime-atomics.cc index 28a8741883..ca6e6ebaa7 100644 --- a/src/runtime/runtime-atomics.cc +++ b/src/runtime/runtime-atomics.cc @@ -12,7 +12,7 @@ // Implement Atomic accesses to SharedArrayBuffers as defined in the // SharedArrayBuffer draft spec, found here -// https://github.com/lars-t-hansen/ecmascript_sharedmem +// https://github.com/tc39/ecmascript_sharedmem namespace v8 { namespace internal { diff --git a/src/runtime/runtime-futex.cc b/src/runtime/runtime-futex.cc index a966412519..b738a1d081 100644 --- a/src/runtime/runtime-futex.cc +++ b/src/runtime/runtime-futex.cc @@ -12,12 +12,12 @@ // Implement Futex API for SharedArrayBuffers as defined in the // SharedArrayBuffer draft spec, found here: -// https://github.com/lars-t-hansen/ecmascript_sharedmem +// https://github.com/tc39/ecmascript_sharedmem namespace v8 { namespace internal { -RUNTIME_FUNCTION(Runtime_AtomicsFutexWait) { +RUNTIME_FUNCTION(Runtime_AtomicsWait) { HandleScope scope(isolate); DCHECK(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); @@ -35,8 +35,7 @@ RUNTIME_FUNCTION(Runtime_AtomicsFutexWait) { return FutexEmulation::Wait(isolate, array_buffer, addr, value, timeout); } - -RUNTIME_FUNCTION(Runtime_AtomicsFutexWake) { +RUNTIME_FUNCTION(Runtime_AtomicsWake) { HandleScope scope(isolate); DCHECK(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); @@ -52,30 +51,7 @@ RUNTIME_FUNCTION(Runtime_AtomicsFutexWake) { return FutexEmulation::Wake(isolate, array_buffer, addr, count); } - -RUNTIME_FUNCTION(Runtime_AtomicsFutexWakeOrRequeue) { - HandleScope scope(isolate); - DCHECK(args.length() == 5); - CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); - CONVERT_SIZE_ARG_CHECKED(index1, 1); - CONVERT_INT32_ARG_CHECKED(count, 2); - CONVERT_INT32_ARG_CHECKED(value, 3); - CONVERT_SIZE_ARG_CHECKED(index2, 4); - CHECK(sta->GetBuffer()->is_shared()); - CHECK_LT(index1, NumberToSize(isolate, sta->length())); - CHECK_LT(index2, NumberToSize(isolate, sta->length())); - CHECK_EQ(sta->type(), kExternalInt32Array); - - Handle array_buffer = sta->GetBuffer(); - size_t addr1 = (index1 << 2) + NumberToSize(isolate, sta->byte_offset()); - size_t addr2 = (index2 << 2) + NumberToSize(isolate, sta->byte_offset()); - - return FutexEmulation::WakeOrRequeue(isolate, array_buffer, addr1, count, - value, addr2); -} - - -RUNTIME_FUNCTION(Runtime_AtomicsFutexNumWaitersForTesting) { +RUNTIME_FUNCTION(Runtime_AtomicsNumWaitersForTesting) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index eeeced303e..695f0e8070 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -64,13 +64,10 @@ namespace internal { F(AtomicsOr, 3, 1) \ F(AtomicsXor, 3, 1) \ F(AtomicsExchange, 3, 1) \ - F(AtomicsIsLockFree, 1, 1) - -#define FOR_EACH_INTRINSIC_FUTEX(F) \ - F(AtomicsFutexWait, 4, 1) \ - F(AtomicsFutexWake, 3, 1) \ - F(AtomicsFutexWakeOrRequeue, 5, 1) \ - F(AtomicsFutexNumWaitersForTesting, 2, 1) + F(AtomicsIsLockFree, 1, 1) \ + F(AtomicsWait, 4, 1) \ + F(AtomicsWake, 3, 1) \ + F(AtomicsNumWaitersForTesting, 2, 1) #define FOR_EACH_INTRINSIC_CLASSES(F) \ F(ThrowNonMethodError, 0, 1) \ @@ -966,7 +963,6 @@ namespace internal { FOR_EACH_INTRINSIC_FORIN(F) \ FOR_EACH_INTRINSIC_INTERPRETER(F) \ FOR_EACH_INTRINSIC_FUNCTION(F) \ - FOR_EACH_INTRINSIC_FUTEX(F) \ FOR_EACH_INTRINSIC_GENERATOR(F) \ FOR_EACH_INTRINSIC_I18N(F) \ FOR_EACH_INTRINSIC_INTERNAL(F) \ diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 5bfbd930a2..cbc4d44dfe 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -25043,7 +25043,7 @@ TEST(FutexInterruption) { CompileRun( "var ab = new SharedArrayBuffer(4);" "var i32a = new Int32Array(ab);" - "Atomics.futexWait(i32a, 0, 0);"); + "Atomics.wait(i32a, 0, 0);"); CHECK(try_catch.HasTerminated()); timeout_thread.Join(); } diff --git a/test/mjsunit/harmony/futex.js b/test/mjsunit/harmony/futex.js index 626cff5fdb..f90b773aa3 100644 --- a/test/mjsunit/harmony/futex.js +++ b/test/mjsunit/harmony/futex.js @@ -19,9 +19,8 @@ [i8a, i16a, i32a, ui8a, ui8ca, ui16a, ui32a, f32a, f64a].forEach(function( ta) { - assertThrows(function() { Atomics.futexWait(ta, 0, 0); }); - assertThrows(function() { Atomics.futexWake(ta, 0, 1); }); - assertThrows(function() { Atomics.futexWakeOrRequeue(ta, 0, 1, 0, 0); }); + assertThrows(function() { Atomics.wait(ta, 0, 0); }); + assertThrows(function() { Atomics.wake(ta, 0, 1); }); }); })(); @@ -39,9 +38,8 @@ [i8a, i16a, ui8a, ui8ca, ui16a, ui32a, f32a, f64a].forEach(function( ta) { - assertThrows(function() { Atomics.futexWait(ta, 0, 0); }); - assertThrows(function() { Atomics.futexWake(ta, 0, 1); }); - assertThrows(function() { Atomics.futexWakeOrRequeue(ta, 0, 1, 0, 0); }); + assertThrows(function() { Atomics.wait(ta, 0, 0); }); + assertThrows(function() { Atomics.wake(ta, 0, 1); }); }); })(); @@ -52,35 +50,23 @@ // Valid indexes are 0-3. [-1, 4, 100].forEach(function(invalidIndex) { assertThrows(function() { - Atomics.futexWait(i32a, invalidIndex, 0); + Atomics.wait(i32a, invalidIndex, 0); }, RangeError); assertThrows(function() { - Atomics.futexWake(i32a, invalidIndex, 0); + Atomics.wake(i32a, invalidIndex, 0); }, RangeError); var validIndex = 0; - assertThrows(function() { - Atomics.futexWakeOrRequeue(i32a, invalidIndex, 0, 0, validIndex); - }, RangeError); - assertThrows(function() { - Atomics.futexWakeOrRequeue(i32a, validIndex, 0, 0, invalidIndex); - }, RangeError); }); i32a = new Int32Array(sab, 8); [-1, 2, 100].forEach(function(invalidIndex) { assertThrows(function() { - Atomics.futexWait(i32a, invalidIndex, 0); + Atomics.wait(i32a, invalidIndex, 0); }, RangeError); assertThrows(function() { - Atomics.futexWake(i32a, invalidIndex, 0); + Atomics.wake(i32a, invalidIndex, 0); }, RangeError); var validIndex = 0; - assertThrows(function() { - Atomics.futexWakeOrRequeue(i32a, invalidIndex, 0, 0, validIndex); - }, RangeError); - assertThrows(function() { - Atomics.futexWakeOrRequeue(i32a, validIndex, 0, 0, invalidIndex); - }, RangeError); }); })(); @@ -88,7 +74,7 @@ var i32a = new Int32Array(new SharedArrayBuffer(16)); var waitMs = 100; var startTime = new Date(); - assertEquals(Atomics.TIMEDOUT, Atomics.futexWait(i32a, 0, 0, waitMs)); + assertEquals("timed-out", Atomics.wait(i32a, 0, 0, waitMs)); var endTime = new Date(); assertTrue(endTime - startTime >= waitMs); })(); @@ -96,17 +82,17 @@ (function TestWaitNotEqual() { var sab = new SharedArrayBuffer(16); var i32a = new Int32Array(sab); - assertEquals(Atomics.NOTEQUAL, Atomics.futexWait(i32a, 0, 42)); + assertEquals("not-equal", Atomics.wait(i32a, 0, 42)); i32a = new Int32Array(sab, 8); i32a[0] = 1; - assertEquals(Atomics.NOTEQUAL, Atomics.futexWait(i32a, 0, 0)); + assertEquals("not-equal", Atomics.wait(i32a, 0, 0)); })(); (function TestWaitNegativeTimeout() { var i32a = new Int32Array(new SharedArrayBuffer(16)); - assertEquals(Atomics.TIMEDOUT, Atomics.futexWait(i32a, 0, 0, -1)); - assertEquals(Atomics.TIMEDOUT, Atomics.futexWait(i32a, 0, 0, -Infinity)); + assertEquals("timed-out", Atomics.wait(i32a, 0, 0, -1)); + assertEquals("timed-out", Atomics.wait(i32a, 0, 0, -Infinity)); })(); //// WORKER ONLY TESTS @@ -120,7 +106,7 @@ if (this.Worker) { var workerScript = `onmessage = function(msg) { var i32a = new Int32Array(msg.sab, msg.offset); - var result = Atomics.futexWait(i32a, 0, 0, ${timeout}); + var result = Atomics.wait(i32a, 0, 0, ${timeout}); postMessage(result); };`; @@ -128,10 +114,10 @@ if (this.Worker) { worker.postMessage({sab: sab, offset: offset}, [sab]); // Spin until the worker is waiting on the futex. - while (%AtomicsFutexNumWaitersForTesting(i32a, 0) != 1) {} + while (%AtomicsNumWaitersForTesting(i32a, 0) != 1) {} - Atomics.futexWake(i32a, 0, 1); - assertEquals(Atomics.OK, worker.getMessage()); + Atomics.wake(i32a, 0, 1); + assertEquals("ok", worker.getMessage()); worker.terminate(); var worker2 = new Worker(workerScript); @@ -140,9 +126,9 @@ if (this.Worker) { worker2.postMessage({sab: sab, offset: offset}, [sab]); // Spin until the worker is waiting on the futex. - while (%AtomicsFutexNumWaitersForTesting(i32a2, 0) != 1) {} - Atomics.futexWake(i32a2, 0, 1); - assertEquals(Atomics.OK, worker2.getMessage()); + while (%AtomicsNumWaitersForTesting(i32a2, 0) != 1) {} + Atomics.wake(i32a2, 0, 1); + assertEquals("ok", worker2.getMessage()); worker2.terminate(); // Futex should work when index and buffer views are different, but @@ -152,9 +138,9 @@ if (this.Worker) { worker3.postMessage({sab: sab, offset: 8}, [sab]); // Spin until the worker is waiting on the futex. - while (%AtomicsFutexNumWaitersForTesting(i32a2, 1) != 1) {} - Atomics.futexWake(i32a2, 1, 1); - assertEquals(Atomics.OK, worker3.getMessage()); + while (%AtomicsNumWaitersForTesting(i32a2, 1) != 1) {} + Atomics.wake(i32a2, 1, 1); + assertEquals("ok", worker3.getMessage()); worker3.terminate(); }; @@ -184,7 +170,7 @@ if (this.Worker) { var i32a = new Int32Array(msg.sab); // Wait on i32a[4] (should be zero). - var result = Atomics.futexWait(i32a, 4, 0); + var result = Atomics.wait(i32a, 4, 0); // Set i32a[id] to 1 to notify the main thread which workers were // woken up. Atomics.store(i32a, id, 1); @@ -199,10 +185,10 @@ if (this.Worker) { } // Spin until all workers are waiting on the futex. - while (%AtomicsFutexNumWaitersForTesting(i32a, 4) != 4) {} + while (%AtomicsNumWaitersForTesting(i32a, 4) != 4) {} // Wake up three waiters. - assertEquals(3, Atomics.futexWake(i32a, 4, 3)); + assertEquals(3, Atomics.wake(i32a, 4, 3)); var wokenCount = 0; var waitingId = 0 + 1 + 2 + 3; @@ -211,7 +197,7 @@ if (this.Worker) { // Look for workers that have not yet been reaped. Set i32a[id] to 2 // when they've been processed so we don't look at them again. if (Atomics.compareExchange(i32a, id, 1, 2) == 1) { - assertEquals(Atomics.OK, workers[id].getMessage()); + assertEquals("ok", workers[id].getMessage()); workers[id].terminate(); waitingId -= id; wokenCount++; @@ -221,131 +207,14 @@ if (this.Worker) { assertEquals(3, wokenCount); assertEquals(0, Atomics.load(i32a, waitingId)); - assertEquals(1, %AtomicsFutexNumWaitersForTesting(i32a, 4)); + assertEquals(1, %AtomicsNumWaitersForTesting(i32a, 4)); // Finally wake the last waiter. - assertEquals(1, Atomics.futexWake(i32a, 4, 1)); - assertEquals(Atomics.OK, workers[waitingId].getMessage()); + assertEquals(1, Atomics.wake(i32a, 4, 1)); + assertEquals("ok", workers[waitingId].getMessage()); workers[waitingId].terminate(); - assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, 4)); - - })(); - - (function TestWakeOrRequeue() { - var sab = new SharedArrayBuffer(24); - var i32a = new Int32Array(sab); - - // SAB values: - // i32a[id], where id in range [0, 3]: - // 0 => Worker |id| is still waiting on the futex - // 1 => Worker |id| is not waiting on futex, but has not be reaped by the - // main thread. - // 2 => Worker |id| has been reaped. - // - // i32a[4]: - // always 0. Each worker will initially wait on this index. - // - // i32a[5]: - // always 0. Requeued workers will wait on this index. - - var workerScript = - `onmessage = function(msg) { - var id = msg.id; - var i32a = new Int32Array(msg.sab); - - var result = Atomics.futexWait(i32a, 4, 0, Infinity); - Atomics.store(i32a, id, 1); - postMessage(result); - };`; - - var workers = []; - for (id = 0; id < 4; id++) { - workers[id] = new Worker(workerScript); - workers[id].postMessage({sab: sab, id: id}, [sab]); - } - - // Spin until all workers are waiting on the futex. - while (%AtomicsFutexNumWaitersForTesting(i32a, 4) != 4) {} - - var index1 = 4; - var index2 = 5; - - // If futexWakeOrRequeue is called with the incorrect value, it shouldn't - // wake any waiters. - assertEquals(Atomics.NOTEQUAL, - Atomics.futexWakeOrRequeue(i32a, index1, 1, 42, index2)); - - assertEquals(4, %AtomicsFutexNumWaitersForTesting(i32a, index1)); - assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index2)); - - // Now wake with the correct value. - assertEquals(1, Atomics.futexWakeOrRequeue(i32a, index1, 1, 0, index2)); - - // The workers that are still waiting should atomically be transferred to - // the new index. - assertEquals(3, %AtomicsFutexNumWaitersForTesting(i32a, index2)); - - // The woken worker may not have been scheduled yet. Look for which thread - // has set its i32a value to 1. - var wokenCount = 0; - while (wokenCount < 1) { - for (id = 0; id < 4; id++) { - if (Atomics.compareExchange(i32a, id, 1, 2) == 1) { - wokenCount++; - } - } - } - - assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index1)); - - // Wake the remaining waiters. - assertEquals(3, Atomics.futexWake(i32a, index2, 3)); - - // As above, wait until the workers have been scheduled. - wokenCount = 0; - while (wokenCount < 3) { - for (id = 0; id < 4; id++) { - if (Atomics.compareExchange(i32a, id, 1, 2) == 1) { - wokenCount++; - } - } - } - - assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index1)); - assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index2)); - - for (id = 0; id < 4; ++id) { - assertEquals(Atomics.OK, workers[id].getMessage()); - } - - // Test futexWakeOrRequeue on offset typed array - var offset = 16; - sab = new SharedArrayBuffer(24); - i32a = new Int32Array(sab); - var i32a2 = new Int32Array(sab, offset); - - for (id = 0; id < 4; id++) { - workers[id].postMessage({sab: sab, id: id}, [sab]); - } - - while (%AtomicsFutexNumWaitersForTesting(i32a2, 0) != 4) { } - - index1 = 0; - index2 = 1; - assertEquals(4, %AtomicsFutexNumWaitersForTesting(i32a2, index1)); - assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a2, index2)); - - assertEquals(2, Atomics.futexWakeOrRequeue(i32a2, index1, 2, 0, index2)); - assertEquals(2, %AtomicsFutexNumWaitersForTesting(i32a2, index2)); - assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a2, index1)); - - assertEquals(2, Atomics.futexWake(i32a2, index2, 2)); - - for (id = 0; id < 4; ++id) { - assertEquals(Atomics.OK, workers[id].getMessage()); - workers[id].terminate(); - } + assertEquals(0, %AtomicsNumWaitersForTesting(i32a, 4)); })();