From 974a4ffbc56910092c92e673698813803b91b8d2 Mon Sep 17 00:00:00 2001 From: Rick Waldron Date: Tue, 7 Apr 2020 15:43:13 -0400 Subject: [PATCH] Atomics.waitAsync: no spurious wakeup on [operation] --- .../no-spurious-wakeup-no-operation.js | 71 +++++++++++++++++++ .../waitAsync/no-spurious-wakeup-on-add.js | 70 ++++++++++++++++++ .../waitAsync/no-spurious-wakeup-on-and.js | 70 ++++++++++++++++++ .../no-spurious-wakeup-on-compareExchange.js | 70 ++++++++++++++++++ .../no-spurious-wakeup-on-exchange.js | 70 ++++++++++++++++++ .../waitAsync/no-spurious-wakeup-on-or.js | 70 ++++++++++++++++++ .../waitAsync/no-spurious-wakeup-on-store.js | 70 ++++++++++++++++++ .../waitAsync/no-spurious-wakeup-on-sub.js | 71 +++++++++++++++++++ .../waitAsync/no-spurious-wakeup-on-xor.js | 71 +++++++++++++++++++ 9 files changed, 633 insertions(+) create mode 100644 test/built-ins/Atomics/waitAsync/no-spurious-wakeup-no-operation.js create mode 100644 test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-add.js create mode 100644 test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-and.js create mode 100644 test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-compareExchange.js create mode 100644 test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-exchange.js create mode 100644 test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-or.js create mode 100644 test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-store.js create mode 100644 test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-sub.js create mode 100644 test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-xor.js diff --git a/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-no-operation.js b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-no-operation.js new file mode 100644 index 0000000000..175efad849 --- /dev/null +++ b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-no-operation.js @@ -0,0 +1,71 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-atomics.waitasync +description: > + Test that Atomics.waitAsync returns the right result when it timed out and that + the time to time out is reasonable. +info: | + AddWaiter ( WL, waiterRecord ) + + 5. Append waiterRecord as the last element of WL.[[Waiters]] + 6. If waiterRecord.[[Timeout]] is finite, then in parallel, + a. Wait waiterRecord.[[Timeout]] milliseconds. + b. Perform TriggerTimeout(WL, waiterRecord). + + TriggerTimeout( WL, waiterRecord ) + + 3. If waiterRecord is in WL.[[Waiters]], then + a. Set waiterRecord.[[Result]] to "timed-out". + b. Perform RemoveWaiter(WL, waiterRecord). + c. Perform NotifyWaiter(WL, waiterRecord). + 4. Perform LeaveCriticalSection(WL). + +includes: [atomicsHelper.js] +features: [Atomics.waitAsync, SharedArrayBuffer, TypedArray, Atomics] +---*/ + +const RUNNING = 1; +const TIMEOUT = $262.agent.timeouts.small; + +const i32a = new Int32Array( + new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4) +); + +$262.agent.start(` + $262.agent.receiveBroadcast(async (sab, id) => { + const i32a = new Int32Array(sab); + Atomics.add(i32a, ${RUNNING}, 1); + + const before = $262.agent.monotonicNow(); + const unpark = await Atomics.waitAsync(i32a, 0, 0, ${TIMEOUT}).value; + const duration = $262.agent.monotonicNow() - before; + $262.agent.report(duration); + $262.agent.report(unpark); + $262.agent.leaving(); + }); +`); + +$262.agent.safeBroadcast(i32a); +$262.agent.waitUntil(i32a, RUNNING, 1); +$262.agent.tryYield(); + +// NO OPERATION OCCURS HERE! + +assert( + $262.agent.getReport() >= TIMEOUT, + 'The result of `(lapse >= TIMEOUT)` is true' +); + +assert.sameValue( + $262.agent.getReport(), + 'timed-out', + 'await Atomics.wait(i32a, 0, 0, ${TIMEOUT}).value resolves to "timed-out"' +); + +assert.sameValue( + Atomics.notify(i32a, 0), + 0, + 'Atomics.notify(i32a, 0) returns 0' +); diff --git a/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-add.js b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-add.js new file mode 100644 index 0000000000..fcdcf4c824 --- /dev/null +++ b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-add.js @@ -0,0 +1,70 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-atomics.waitasync +description: > + Waiter does not spuriously notify on index which is subject to Add operation +info: | + AddWaiter ( WL, waiterRecord ) + + 5. Append waiterRecord as the last element of WL.[[Waiters]] + 6. If waiterRecord.[[Timeout]] is finite, then in parallel, + a. Wait waiterRecord.[[Timeout]] milliseconds. + b. Perform TriggerTimeout(WL, waiterRecord). + + TriggerTimeout( WL, waiterRecord ) + + 3. If waiterRecord is in WL.[[Waiters]], then + a. Set waiterRecord.[[Result]] to "timed-out". + b. Perform RemoveWaiter(WL, waiterRecord). + c. Perform NotifyWaiter(WL, waiterRecord). + 4. Perform LeaveCriticalSection(WL). + +includes: [atomicsHelper.js] +features: [Atomics.waitAsync, SharedArrayBuffer, TypedArray, Atomics] +---*/ + +const RUNNING = 1; +const TIMEOUT = $262.agent.timeouts.small; + +const i32a = new Int32Array( + new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4) +); + +$262.agent.start(` + $262.agent.receiveBroadcast(async (sab, id) => { + const i32a = new Int32Array(sab); + Atomics.add(i32a, ${RUNNING}, 1); + + const before = $262.agent.monotonicNow(); + const unpark = await Atomics.waitAsync(i32a, 0, 0, ${TIMEOUT}).value; + const duration = $262.agent.monotonicNow() - before; + $262.agent.report(duration); + $262.agent.report(unpark); + $262.agent.leaving(); + }); +`); + +$262.agent.safeBroadcast(i32a); +$262.agent.waitUntil(i32a, RUNNING, 1); +$262.agent.tryYield(); + +Atomics.add(i32a, 0, 1); + +assert( + $262.agent.getReport() >= TIMEOUT, + 'The result of `(lapse >= TIMEOUT)` is true' +); + +assert.sameValue( + $262.agent.getReport(), + 'timed-out', + 'await Atomics.wait(i32a, 0, 0, ${TIMEOUT}).value resolves to "timed-out"' +); + +assert.sameValue( + Atomics.notify(i32a, 0), + 0, + 'Atomics.notify(i32a, 0) returns 0' +); diff --git a/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-and.js b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-and.js new file mode 100644 index 0000000000..fbef19cbcc --- /dev/null +++ b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-and.js @@ -0,0 +1,70 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-atomics.waitasync +description: > + Waiter does not spuriously notify on index which is subject to And operation +info: | + AddWaiter ( WL, waiterRecord ) + + 5. Append waiterRecord as the last element of WL.[[Waiters]] + 6. If waiterRecord.[[Timeout]] is finite, then in parallel, + a. Wait waiterRecord.[[Timeout]] milliseconds. + b. Perform TriggerTimeout(WL, waiterRecord). + + TriggerTimeout( WL, waiterRecord ) + + 3. If waiterRecord is in WL.[[Waiters]], then + a. Set waiterRecord.[[Result]] to "timed-out". + b. Perform RemoveWaiter(WL, waiterRecord). + c. Perform NotifyWaiter(WL, waiterRecord). + 4. Perform LeaveCriticalSection(WL). + +includes: [atomicsHelper.js] +features: [Atomics.waitAsync, SharedArrayBuffer, TypedArray, Atomics] +---*/ + +const RUNNING = 1; +const TIMEOUT = $262.agent.timeouts.small; + +const i32a = new Int32Array( + new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4) +); + +$262.agent.start(` + $262.agent.receiveBroadcast(async (sab, id) => { + const i32a = new Int32Array(sab); + Atomics.add(i32a, ${RUNNING}, 1); + + const before = $262.agent.monotonicNow(); + const unpark = await Atomics.waitAsync(i32a, 0, 0, ${TIMEOUT}).value; + const duration = $262.agent.monotonicNow() - before; + $262.agent.report(duration); + $262.agent.report(unpark); + $262.agent.leaving(); + }); +`); + +$262.agent.safeBroadcast(i32a); +$262.agent.waitUntil(i32a, RUNNING, 1); +$262.agent.tryYield(); + +Atomics.and(i32a, 0, 1); + +assert( + $262.agent.getReport() >= TIMEOUT, + 'The result of `(lapse >= TIMEOUT)` is true' +); + +assert.sameValue( + $262.agent.getReport(), + 'timed-out', + 'await Atomics.wait(i32a, 0, 0, ${TIMEOUT}).value resolves to "timed-out"' +); + +assert.sameValue( + Atomics.notify(i32a, 0), + 0, + 'Atomics.notify(i32a, 0) returns 0' +); diff --git a/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-compareExchange.js b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-compareExchange.js new file mode 100644 index 0000000000..ca2e858032 --- /dev/null +++ b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-compareExchange.js @@ -0,0 +1,70 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-atomics.waitasync +description: > + Waiter does not spuriously notify on index which is subject to compareExchange operation +info: | + AddWaiter ( WL, waiterRecord ) + + 5. Append waiterRecord as the last element of WL.[[Waiters]] + 6. If waiterRecord.[[Timeout]] is finite, then in parallel, + a. Wait waiterRecord.[[Timeout]] milliseconds. + b. Perform TriggerTimeout(WL, waiterRecord). + + TriggerTimeout( WL, waiterRecord ) + + 3. If waiterRecord is in WL.[[Waiters]], then + a. Set waiterRecord.[[Result]] to "timed-out". + b. Perform RemoveWaiter(WL, waiterRecord). + c. Perform NotifyWaiter(WL, waiterRecord). + 4. Perform LeaveCriticalSection(WL). + +includes: [atomicsHelper.js] +features: [Atomics.waitAsync, SharedArrayBuffer, TypedArray, Atomics] +---*/ + +const RUNNING = 1; +const TIMEOUT = $262.agent.timeouts.small; + +const i32a = new Int32Array( + new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4) +); + +$262.agent.start(` + $262.agent.receiveBroadcast(async (sab, id) => { + const i32a = new Int32Array(sab); + Atomics.add(i32a, ${RUNNING}, 1); + + const before = $262.agent.monotonicNow(); + const unpark = await Atomics.waitAsync(i32a, 0, 0, ${TIMEOUT}).value; + const duration = $262.agent.monotonicNow() - before; + $262.agent.report(duration); + $262.agent.report(unpark); + $262.agent.leaving(); + }); +`); + +$262.agent.safeBroadcast(i32a); +$262.agent.waitUntil(i32a, RUNNING, 1); +$262.agent.tryYield(); + +Atomics.compareExchange(i32a, 0, 0, 1); + +assert( + $262.agent.getReport() >= TIMEOUT, + 'The result of `(lapse >= TIMEOUT)` is true' +); + +assert.sameValue( + $262.agent.getReport(), + 'timed-out', + 'await Atomics.wait(i32a, 0, 0, ${TIMEOUT}).value resolves to "timed-out"' +); + +assert.sameValue( + Atomics.notify(i32a, 0), + 0, + 'Atomics.notify(i32a, 0) returns 0' +); diff --git a/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-exchange.js b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-exchange.js new file mode 100644 index 0000000000..a945fef6e8 --- /dev/null +++ b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-exchange.js @@ -0,0 +1,70 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-atomics.waitasync +description: > + Waiter does not spuriously notify on index which is subject to exchange operation +info: | + AddWaiter ( WL, waiterRecord ) + + 5. Append waiterRecord as the last element of WL.[[Waiters]] + 6. If waiterRecord.[[Timeout]] is finite, then in parallel, + a. Wait waiterRecord.[[Timeout]] milliseconds. + b. Perform TriggerTimeout(WL, waiterRecord). + + TriggerTimeout( WL, waiterRecord ) + + 3. If waiterRecord is in WL.[[Waiters]], then + a. Set waiterRecord.[[Result]] to "timed-out". + b. Perform RemoveWaiter(WL, waiterRecord). + c. Perform NotifyWaiter(WL, waiterRecord). + 4. Perform LeaveCriticalSection(WL). + +includes: [atomicsHelper.js] +features: [Atomics.waitAsync, SharedArrayBuffer, TypedArray, Atomics] +---*/ + +const RUNNING = 1; +const TIMEOUT = $262.agent.timeouts.small; + +const i32a = new Int32Array( + new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4) +); + +$262.agent.start(` + $262.agent.receiveBroadcast(async (sab, id) => { + const i32a = new Int32Array(sab); + Atomics.add(i32a, ${RUNNING}, 1); + + const before = $262.agent.monotonicNow(); + const unpark = await Atomics.waitAsync(i32a, 0, 0, ${TIMEOUT}).value; + const duration = $262.agent.monotonicNow() - before; + $262.agent.report(duration); + $262.agent.report(unpark); + $262.agent.leaving(); + }); +`); + +$262.agent.safeBroadcast(i32a); +$262.agent.waitUntil(i32a, RUNNING, 1); +$262.agent.tryYield(); + +Atomics.exchange(i32a, 0, 1); + +assert( + $262.agent.getReport() >= TIMEOUT, + 'The result of `(lapse >= TIMEOUT)` is true' +); + +assert.sameValue( + $262.agent.getReport(), + 'timed-out', + 'await Atomics.wait(i32a, 0, 0, ${TIMEOUT}).value resolves to "timed-out"' +); + +assert.sameValue( + Atomics.notify(i32a, 0), + 0, + 'Atomics.notify(i32a, 0) returns 0' +); diff --git a/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-or.js b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-or.js new file mode 100644 index 0000000000..89cc22af73 --- /dev/null +++ b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-or.js @@ -0,0 +1,70 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-atomics.waitasync +description: > + Waiter does not spuriously notify on index which is subject to Or operation +info: | + AddWaiter ( WL, waiterRecord ) + + 5. Append waiterRecord as the last element of WL.[[Waiters]] + 6. If waiterRecord.[[Timeout]] is finite, then in parallel, + a. Wait waiterRecord.[[Timeout]] milliseconds. + b. Perform TriggerTimeout(WL, waiterRecord). + + TriggerTimeout( WL, waiterRecord ) + + 3. If waiterRecord is in WL.[[Waiters]], then + a. Set waiterRecord.[[Result]] to "timed-out". + b. Perform RemoveWaiter(WL, waiterRecord). + c. Perform NotifyWaiter(WL, waiterRecord). + 4. Perform LeaveCriticalSection(WL). + +includes: [atomicsHelper.js] +features: [Atomics.waitAsync, SharedArrayBuffer, TypedArray, Atomics] +---*/ + +const RUNNING = 1; +const TIMEOUT = $262.agent.timeouts.small; + +const i32a = new Int32Array( + new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4) +); + +$262.agent.start(` + $262.agent.receiveBroadcast(async (sab, id) => { + const i32a = new Int32Array(sab); + Atomics.add(i32a, ${RUNNING}, 1); + + const before = $262.agent.monotonicNow(); + const unpark = await Atomics.waitAsync(i32a, 0, 0, ${TIMEOUT}).value; + const duration = $262.agent.monotonicNow() - before; + $262.agent.report(duration); + $262.agent.report(unpark); + $262.agent.leaving(); + }); +`); + +$262.agent.safeBroadcast(i32a); +$262.agent.waitUntil(i32a, RUNNING, 1); +$262.agent.tryYield(); + +Atomics.or(i32a, 0, 1); + +assert( + $262.agent.getReport() >= TIMEOUT, + 'The result of `(lapse >= TIMEOUT)` is true' +); + +assert.sameValue( + $262.agent.getReport(), + 'timed-out', + 'await Atomics.wait(i32a, 0, 0, ${TIMEOUT}).value resolves to "timed-out"' +); + +assert.sameValue( + Atomics.notify(i32a, 0), + 0, + 'Atomics.notify(i32a, 0) returns 0' +); diff --git a/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-store.js b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-store.js new file mode 100644 index 0000000000..a8907be7a4 --- /dev/null +++ b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-store.js @@ -0,0 +1,70 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-atomics.waitasync +description: > + Waiter does not spuriously notify on index which is subject to Store operation +info: | + AddWaiter ( WL, waiterRecord ) + + 5. Append waiterRecord as the last element of WL.[[Waiters]] + 6. If waiterRecord.[[Timeout]] is finite, then in parallel, + a. Wait waiterRecord.[[Timeout]] milliseconds. + b. Perform TriggerTimeout(WL, waiterRecord). + + TriggerTimeout( WL, waiterRecord ) + + 3. If waiterRecord is in WL.[[Waiters]], then + a. Set waiterRecord.[[Result]] to "timed-out". + b. Perform RemoveWaiter(WL, waiterRecord). + c. Perform NotifyWaiter(WL, waiterRecord). + 4. Perform LeaveCriticalSection(WL). + +includes: [atomicsHelper.js] +features: [Atomics.waitAsync, SharedArrayBuffer, TypedArray, Atomics] +---*/ + +const RUNNING = 1; +const TIMEOUT = $262.agent.timeouts.small; + +const i32a = new Int32Array( + new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4) +); + +$262.agent.start(` + $262.agent.receiveBroadcast(async (sab, id) => { + const i32a = new Int32Array(sab); + Atomics.add(i32a, ${RUNNING}, 1); + + const before = $262.agent.monotonicNow(); + const unpark = await Atomics.waitAsync(i32a, 0, 0, ${TIMEOUT}).value; + const duration = $262.agent.monotonicNow() - before; + $262.agent.report(duration); + $262.agent.report(unpark); + $262.agent.leaving(); + }); +`); + +$262.agent.safeBroadcast(i32a); +$262.agent.waitUntil(i32a, RUNNING, 1); +$262.agent.tryYield(); + +Atomics.store(i32a, 0, 0x111111); + +assert( + $262.agent.getReport() >= TIMEOUT, + 'The result of `(lapse >= TIMEOUT)` is true' +); + +assert.sameValue( + $262.agent.getReport(), + 'timed-out', + 'await Atomics.wait(i32a, 0, 0, ${TIMEOUT}).value resolves to "timed-out"' +); + +assert.sameValue( + Atomics.notify(i32a, 0), + 0, + 'Atomics.notify(i32a, 0) returns 0' +); diff --git a/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-sub.js b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-sub.js new file mode 100644 index 0000000000..a40475170e --- /dev/null +++ b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-sub.js @@ -0,0 +1,71 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-atomics.waitasync +description: > + Waiter does not spuriously notify on index which is subject to Sub operation +info: | + + AddWaiter ( WL, waiterRecord ) + + 5. Append waiterRecord as the last element of WL.[[Waiters]] + 6. If waiterRecord.[[Timeout]] is finite, then in parallel, + a. Wait waiterRecord.[[Timeout]] milliseconds. + b. Perform TriggerTimeout(WL, waiterRecord). + + TriggerTimeout( WL, waiterRecord ) + + 3. If waiterRecord is in WL.[[Waiters]], then + a. Set waiterRecord.[[Result]] to "timed-out". + b. Perform RemoveWaiter(WL, waiterRecord). + c. Perform NotifyWaiter(WL, waiterRecord). + 4. Perform LeaveCriticalSection(WL). + +includes: [atomicsHelper.js] +features: [Atomics.waitAsync, SharedArrayBuffer, TypedArray, Atomics] +---*/ + +const RUNNING = 1; +const TIMEOUT = $262.agent.timeouts.small; + +const i32a = new Int32Array( + new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4) +); + +$262.agent.start(` + $262.agent.receiveBroadcast(async (sab, id) => { + const i32a = new Int32Array(sab); + Atomics.add(i32a, ${RUNNING}, 1); + + const before = $262.agent.monotonicNow(); + const unpark = await Atomics.waitAsync(i32a, 0, 0, ${TIMEOUT}).value; + const duration = $262.agent.monotonicNow() - before; + $262.agent.report(duration); + $262.agent.report(unpark); + $262.agent.leaving(); + }); +`); + +$262.agent.safeBroadcast(i32a); +$262.agent.waitUntil(i32a, RUNNING, 1); +$262.agent.tryYield(); + +Atomics.sub(i32a, 0, 1); + +assert( + $262.agent.getReport() >= TIMEOUT, + 'The result of `(lapse >= TIMEOUT)` is true' +); + +assert.sameValue( + $262.agent.getReport(), + 'timed-out', + 'await Atomics.wait(i32a, 0, 0, ${TIMEOUT}).value resolves to "timed-out"' +); + +assert.sameValue( + Atomics.notify(i32a, 0), + 0, + 'Atomics.notify(i32a, 0) returns 0' +); diff --git a/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-xor.js b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-xor.js new file mode 100644 index 0000000000..66fcdaac9a --- /dev/null +++ b/test/built-ins/Atomics/waitAsync/no-spurious-wakeup-on-xor.js @@ -0,0 +1,71 @@ +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-atomics.waitasync +description: > + Waiter does not spuriously notify on index which is subject to xor operation +info: | + + AddWaiter ( WL, waiterRecord ) + + 5. Append waiterRecord as the last element of WL.[[Waiters]] + 6. If waiterRecord.[[Timeout]] is finite, then in parallel, + a. Wait waiterRecord.[[Timeout]] milliseconds. + b. Perform TriggerTimeout(WL, waiterRecord). + + TriggerTimeout( WL, waiterRecord ) + + 3. If waiterRecord is in WL.[[Waiters]], then + a. Set waiterRecord.[[Result]] to "timed-out". + b. Perform RemoveWaiter(WL, waiterRecord). + c. Perform NotifyWaiter(WL, waiterRecord). + 4. Perform LeaveCriticalSection(WL). + +includes: [atomicsHelper.js] +features: [Atomics.waitAsync, SharedArrayBuffer, TypedArray, Atomics] +---*/ + +const RUNNING = 1; +const TIMEOUT = $262.agent.timeouts.small; + +const i32a = new Int32Array( + new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4) +); + +$262.agent.start(` + $262.agent.receiveBroadcast(async (sab, id) => { + const i32a = new Int32Array(sab); + Atomics.add(i32a, ${RUNNING}, 1); + + const before = $262.agent.monotonicNow(); + const unpark = await Atomics.waitAsync(i32a, 0, 0, ${TIMEOUT}).value; + const duration = $262.agent.monotonicNow() - before; + $262.agent.report(duration); + $262.agent.report(unpark); + $262.agent.leaving(); + }); +`); + +$262.agent.safeBroadcast(i32a); +$262.agent.waitUntil(i32a, RUNNING, 1); +$262.agent.tryYield(); + +Atomics.xor(i32a, 0, 1); + +assert( + $262.agent.getReport() >= TIMEOUT, + 'The result of `(lapse >= TIMEOUT)` is true' +); + +assert.sameValue( + $262.agent.getReport(), + 'timed-out', + 'await Atomics.wait(i32a, 0, 0, ${TIMEOUT}).value resolves to "timed-out"' +); + +assert.sameValue( + Atomics.notify(i32a, 0), + 0, + 'Atomics.notify(i32a, 0) returns 0' +);