Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1608)

Unified Diff: test/mjsunit/harmony/futex.js

Issue 1208933006: Atomics Futex API (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: TODO about busy-waiting Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « test/cctest/test-api.cc ('k') | tools/gyp/v8.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/mjsunit/harmony/futex.js
diff --git a/test/mjsunit/harmony/futex.js b/test/mjsunit/harmony/futex.js
new file mode 100644
index 0000000000000000000000000000000000000000..c7e1f5ce2a86b6fe50b9609781b1eb822f302fec
--- /dev/null
+++ b/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();
+ }
+
+ })();
+
+}
« no previous file with comments | « test/cctest/test-api.cc ('k') | tools/gyp/v8.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698