diff options
Diffstat (limited to 'deps/v8/test/mjsunit/harmony/futex.js')
-rw-r--r-- | deps/v8/test/mjsunit/harmony/futex.js | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/deps/v8/test/mjsunit/harmony/futex.js b/deps/v8/test/mjsunit/harmony/futex.js new file mode 100644 index 0000000000..c7e1f5ce2a --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/futex.js @@ -0,0 +1,274 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --harmony-atomics --harmony-sharedarraybuffer + +(function TestFailsWithNonSharedArray() { + var ab = new ArrayBuffer(16); + + var i8a = new Int8Array(ab); + var i16a = new Int16Array(ab); + var i32a = new Int32Array(ab); + var ui8a = new Uint8Array(ab); + var ui8ca = new Uint8ClampedArray(ab); + var ui16a = new Uint16Array(ab); + var ui32a = new Uint32Array(ab); + var f32a = new Float32Array(ab); + var f64a = new Float64Array(ab); + + [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); }); + }); +})(); + +(function TestFailsWithNonSharedInt32Array() { + var sab = new SharedArrayBuffer(16); + + var i8a = new Int8Array(sab); + var i16a = new Int16Array(sab); + var ui8a = new Uint8Array(sab); + var ui8ca = new Uint8ClampedArray(sab); + var ui16a = new Uint16Array(sab); + var ui32a = new Uint32Array(sab); + var f32a = new Float32Array(sab); + var f64a = new Float64Array(sab); + + [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); }); + }); +})(); + +(function TestInvalidIndex() { + var i32a = new Int32Array(new SharedArrayBuffer(16)); + + // Valid indexes are 0-3. + [-1, 4, 100].forEach(function(invalidIndex) { + assertEquals(undefined, Atomics.futexWait(i32a, invalidIndex, 0)); + assertEquals(undefined, Atomics.futexWake(i32a, invalidIndex, 0)); + var validIndex = 0; + assertEquals(undefined, Atomics.futexWakeOrRequeue(i32a, invalidIndex, 0, 0, + validIndex)); + assertEquals(undefined, Atomics.futexWakeOrRequeue(i32a, validIndex, 0, 0, + invalidIndex)); + }); + +})(); + +(function TestWaitTimeout() { + var i32a = new Int32Array(new SharedArrayBuffer(16)); + var waitMs = 100; + var startTime = new Date(); + assertEquals(Atomics.TIMEDOUT, Atomics.futexWait(i32a, 0, 0, waitMs)); + var endTime = new Date(); + assertTrue(endTime - startTime >= waitMs); +})(); + +(function TestWaitNotEqual() { + var i32a = new Int32Array(new SharedArrayBuffer(16)); + assertEquals(Atomics.NOTEQUAL, Atomics.futexWait(i32a, 0, 42)); +})(); + +(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)); +})(); + +//// WORKER ONLY TESTS + +if (this.Worker) { + + var TestWaitWithTimeout = function(timeout) { + var sab = new SharedArrayBuffer(16); + var i32a = new Int32Array(sab); + + var workerScript = + `onmessage = function(sab) { + var i32a = new Int32Array(sab); + var result = Atomics.futexWait(i32a, 0, 0, ${timeout}); + postMessage(result); + };`; + + var worker = new Worker(workerScript); + worker.postMessage(sab, [sab]); + + // Spin until the worker is waiting on the futex. + while (%AtomicsFutexNumWaitersForTesting(i32a, 0) != 1) {} + + Atomics.futexWake(i32a, 0, 1); + assertEquals(Atomics.OK, worker.getMessage()); + worker.terminate(); + }; + + // Test various infinite timeouts + TestWaitWithTimeout(undefined); + TestWaitWithTimeout(NaN); + TestWaitWithTimeout(Infinity); + + + (function TestWakeMulti() { + var sab = new SharedArrayBuffer(20); + 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 is waiting on this index. + + var workerScript = + `onmessage = function(msg) { + var id = msg.id; + var i32a = new Int32Array(msg.sab); + + // Wait on i32a[4] (should be zero). + var result = Atomics.futexWait(i32a, 4, 0); + // Set i32a[id] to 1 to notify the main thread which workers were + // woken up. + Atomics.store(i32a, id, 1); + postMessage(result); + };`; + + var id; + 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) {} + + // Wake up three waiters. + assertEquals(3, Atomics.futexWake(i32a, 4, 3)); + + var wokenCount = 0; + var waitingId = 0 + 1 + 2 + 3; + while (wokenCount < 3) { + for (id = 0; id < 4; id++) { + // 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()); + workers[id].terminate(); + waitingId -= id; + wokenCount++; + } + } + } + + assertEquals(3, wokenCount); + assertEquals(0, Atomics.load(i32a, waitingId)); + assertEquals(1, %AtomicsFutexNumWaitersForTesting(i32a, 4)); + + // Finally wake the last waiter. + assertEquals(1, Atomics.futexWake(i32a, 4, 1)); + assertEquals(Atomics.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()); + workers[id].terminate(); + } + + })(); + +} |