blob: 626cff5fdba7554250fb0e67b7bff010369a41de [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Flags: --allow-natives-syntax --harmony-sharedarraybuffer
6
7(function TestFailsWithNonSharedArray() {
8 var ab = new ArrayBuffer(16);
9
10 var i8a = new Int8Array(ab);
11 var i16a = new Int16Array(ab);
12 var i32a = new Int32Array(ab);
13 var ui8a = new Uint8Array(ab);
14 var ui8ca = new Uint8ClampedArray(ab);
15 var ui16a = new Uint16Array(ab);
16 var ui32a = new Uint32Array(ab);
17 var f32a = new Float32Array(ab);
18 var f64a = new Float64Array(ab);
19
20 [i8a, i16a, i32a, ui8a, ui8ca, ui16a, ui32a, f32a, f64a].forEach(function(
21 ta) {
22 assertThrows(function() { Atomics.futexWait(ta, 0, 0); });
23 assertThrows(function() { Atomics.futexWake(ta, 0, 1); });
24 assertThrows(function() { Atomics.futexWakeOrRequeue(ta, 0, 1, 0, 0); });
25 });
26})();
27
28(function TestFailsWithNonSharedInt32Array() {
29 var sab = new SharedArrayBuffer(16);
30
31 var i8a = new Int8Array(sab);
32 var i16a = new Int16Array(sab);
33 var ui8a = new Uint8Array(sab);
34 var ui8ca = new Uint8ClampedArray(sab);
35 var ui16a = new Uint16Array(sab);
36 var ui32a = new Uint32Array(sab);
37 var f32a = new Float32Array(sab);
38 var f64a = new Float64Array(sab);
39
40 [i8a, i16a, ui8a, ui8ca, ui16a, ui32a, f32a, f64a].forEach(function(
41 ta) {
42 assertThrows(function() { Atomics.futexWait(ta, 0, 0); });
43 assertThrows(function() { Atomics.futexWake(ta, 0, 1); });
44 assertThrows(function() { Atomics.futexWakeOrRequeue(ta, 0, 1, 0, 0); });
45 });
46})();
47
48(function TestInvalidIndex() {
49 var sab = new SharedArrayBuffer(16);
50 var i32a = new Int32Array(sab);
51
52 // Valid indexes are 0-3.
53 [-1, 4, 100].forEach(function(invalidIndex) {
Ben Murdochda12d292016-06-02 14:46:10 +010054 assertThrows(function() {
55 Atomics.futexWait(i32a, invalidIndex, 0);
56 }, RangeError);
57 assertThrows(function() {
58 Atomics.futexWake(i32a, invalidIndex, 0);
59 }, RangeError);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000060 var validIndex = 0;
Ben Murdochda12d292016-06-02 14:46:10 +010061 assertThrows(function() {
62 Atomics.futexWakeOrRequeue(i32a, invalidIndex, 0, 0, validIndex);
63 }, RangeError);
64 assertThrows(function() {
65 Atomics.futexWakeOrRequeue(i32a, validIndex, 0, 0, invalidIndex);
66 }, RangeError);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000067 });
68
69 i32a = new Int32Array(sab, 8);
70 [-1, 2, 100].forEach(function(invalidIndex) {
Ben Murdochda12d292016-06-02 14:46:10 +010071 assertThrows(function() {
72 Atomics.futexWait(i32a, invalidIndex, 0);
73 }, RangeError);
74 assertThrows(function() {
75 Atomics.futexWake(i32a, invalidIndex, 0);
76 }, RangeError);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000077 var validIndex = 0;
Ben Murdochda12d292016-06-02 14:46:10 +010078 assertThrows(function() {
79 Atomics.futexWakeOrRequeue(i32a, invalidIndex, 0, 0, validIndex);
80 }, RangeError);
81 assertThrows(function() {
82 Atomics.futexWakeOrRequeue(i32a, validIndex, 0, 0, invalidIndex);
83 }, RangeError);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000084 });
85})();
86
87(function TestWaitTimeout() {
88 var i32a = new Int32Array(new SharedArrayBuffer(16));
89 var waitMs = 100;
90 var startTime = new Date();
91 assertEquals(Atomics.TIMEDOUT, Atomics.futexWait(i32a, 0, 0, waitMs));
92 var endTime = new Date();
93 assertTrue(endTime - startTime >= waitMs);
94})();
95
96(function TestWaitNotEqual() {
97 var sab = new SharedArrayBuffer(16);
98 var i32a = new Int32Array(sab);
99 assertEquals(Atomics.NOTEQUAL, Atomics.futexWait(i32a, 0, 42));
100
101 i32a = new Int32Array(sab, 8);
102 i32a[0] = 1;
103 assertEquals(Atomics.NOTEQUAL, Atomics.futexWait(i32a, 0, 0));
104})();
105
106(function TestWaitNegativeTimeout() {
107 var i32a = new Int32Array(new SharedArrayBuffer(16));
108 assertEquals(Atomics.TIMEDOUT, Atomics.futexWait(i32a, 0, 0, -1));
109 assertEquals(Atomics.TIMEDOUT, Atomics.futexWait(i32a, 0, 0, -Infinity));
110})();
111
112//// WORKER ONLY TESTS
113
114if (this.Worker) {
115
116 var TestWaitWithTimeout = function(timeout) {
117 var sab = new SharedArrayBuffer(16);
118 var i32a = new Int32Array(sab);
119
120 var workerScript =
121 `onmessage = function(msg) {
122 var i32a = new Int32Array(msg.sab, msg.offset);
123 var result = Atomics.futexWait(i32a, 0, 0, ${timeout});
124 postMessage(result);
125 };`;
126
127 var worker = new Worker(workerScript);
128 worker.postMessage({sab: sab, offset: offset}, [sab]);
129
130 // Spin until the worker is waiting on the futex.
131 while (%AtomicsFutexNumWaitersForTesting(i32a, 0) != 1) {}
132
133 Atomics.futexWake(i32a, 0, 1);
134 assertEquals(Atomics.OK, worker.getMessage());
135 worker.terminate();
136
137 var worker2 = new Worker(workerScript);
138 var offset = 8;
139 var i32a2 = new Int32Array(sab, offset);
140 worker2.postMessage({sab: sab, offset: offset}, [sab]);
141
142 // Spin until the worker is waiting on the futex.
143 while (%AtomicsFutexNumWaitersForTesting(i32a2, 0) != 1) {}
144 Atomics.futexWake(i32a2, 0, 1);
145 assertEquals(Atomics.OK, worker2.getMessage());
146 worker2.terminate();
147
148 // Futex should work when index and buffer views are different, but
149 // the real address is the same.
150 var worker3 = new Worker(workerScript);
151 i32a2 = new Int32Array(sab, 4);
152 worker3.postMessage({sab: sab, offset: 8}, [sab]);
153
154 // Spin until the worker is waiting on the futex.
155 while (%AtomicsFutexNumWaitersForTesting(i32a2, 1) != 1) {}
156 Atomics.futexWake(i32a2, 1, 1);
157 assertEquals(Atomics.OK, worker3.getMessage());
158 worker3.terminate();
159 };
160
161 // Test various infinite timeouts
162 TestWaitWithTimeout(undefined);
163 TestWaitWithTimeout(NaN);
164 TestWaitWithTimeout(Infinity);
165
166
167 (function TestWakeMulti() {
168 var sab = new SharedArrayBuffer(20);
169 var i32a = new Int32Array(sab);
170
171 // SAB values:
172 // i32a[id], where id in range [0, 3]:
173 // 0 => Worker |id| is still waiting on the futex
174 // 1 => Worker |id| is not waiting on futex, but has not be reaped by the
175 // main thread.
176 // 2 => Worker |id| has been reaped.
177 //
178 // i32a[4]:
179 // always 0. Each worker is waiting on this index.
180
181 var workerScript =
182 `onmessage = function(msg) {
183 var id = msg.id;
184 var i32a = new Int32Array(msg.sab);
185
186 // Wait on i32a[4] (should be zero).
187 var result = Atomics.futexWait(i32a, 4, 0);
188 // Set i32a[id] to 1 to notify the main thread which workers were
189 // woken up.
190 Atomics.store(i32a, id, 1);
191 postMessage(result);
192 };`;
193
194 var id;
195 var workers = [];
196 for (id = 0; id < 4; id++) {
197 workers[id] = new Worker(workerScript);
198 workers[id].postMessage({sab: sab, id: id}, [sab]);
199 }
200
201 // Spin until all workers are waiting on the futex.
202 while (%AtomicsFutexNumWaitersForTesting(i32a, 4) != 4) {}
203
204 // Wake up three waiters.
205 assertEquals(3, Atomics.futexWake(i32a, 4, 3));
206
207 var wokenCount = 0;
208 var waitingId = 0 + 1 + 2 + 3;
209 while (wokenCount < 3) {
210 for (id = 0; id < 4; id++) {
211 // Look for workers that have not yet been reaped. Set i32a[id] to 2
212 // when they've been processed so we don't look at them again.
213 if (Atomics.compareExchange(i32a, id, 1, 2) == 1) {
214 assertEquals(Atomics.OK, workers[id].getMessage());
215 workers[id].terminate();
216 waitingId -= id;
217 wokenCount++;
218 }
219 }
220 }
221
222 assertEquals(3, wokenCount);
223 assertEquals(0, Atomics.load(i32a, waitingId));
224 assertEquals(1, %AtomicsFutexNumWaitersForTesting(i32a, 4));
225
226 // Finally wake the last waiter.
227 assertEquals(1, Atomics.futexWake(i32a, 4, 1));
228 assertEquals(Atomics.OK, workers[waitingId].getMessage());
229 workers[waitingId].terminate();
230
231 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, 4));
232
233 })();
234
235 (function TestWakeOrRequeue() {
236 var sab = new SharedArrayBuffer(24);
237 var i32a = new Int32Array(sab);
238
239 // SAB values:
240 // i32a[id], where id in range [0, 3]:
241 // 0 => Worker |id| is still waiting on the futex
242 // 1 => Worker |id| is not waiting on futex, but has not be reaped by the
243 // main thread.
244 // 2 => Worker |id| has been reaped.
245 //
246 // i32a[4]:
247 // always 0. Each worker will initially wait on this index.
248 //
249 // i32a[5]:
250 // always 0. Requeued workers will wait on this index.
251
252 var workerScript =
253 `onmessage = function(msg) {
254 var id = msg.id;
255 var i32a = new Int32Array(msg.sab);
256
257 var result = Atomics.futexWait(i32a, 4, 0, Infinity);
258 Atomics.store(i32a, id, 1);
259 postMessage(result);
260 };`;
261
262 var workers = [];
263 for (id = 0; id < 4; id++) {
264 workers[id] = new Worker(workerScript);
265 workers[id].postMessage({sab: sab, id: id}, [sab]);
266 }
267
268 // Spin until all workers are waiting on the futex.
269 while (%AtomicsFutexNumWaitersForTesting(i32a, 4) != 4) {}
270
271 var index1 = 4;
272 var index2 = 5;
273
274 // If futexWakeOrRequeue is called with the incorrect value, it shouldn't
275 // wake any waiters.
276 assertEquals(Atomics.NOTEQUAL,
277 Atomics.futexWakeOrRequeue(i32a, index1, 1, 42, index2));
278
279 assertEquals(4, %AtomicsFutexNumWaitersForTesting(i32a, index1));
280 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index2));
281
282 // Now wake with the correct value.
283 assertEquals(1, Atomics.futexWakeOrRequeue(i32a, index1, 1, 0, index2));
284
285 // The workers that are still waiting should atomically be transferred to
286 // the new index.
287 assertEquals(3, %AtomicsFutexNumWaitersForTesting(i32a, index2));
288
289 // The woken worker may not have been scheduled yet. Look for which thread
290 // has set its i32a value to 1.
291 var wokenCount = 0;
292 while (wokenCount < 1) {
293 for (id = 0; id < 4; id++) {
294 if (Atomics.compareExchange(i32a, id, 1, 2) == 1) {
295 wokenCount++;
296 }
297 }
298 }
299
300 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index1));
301
302 // Wake the remaining waiters.
303 assertEquals(3, Atomics.futexWake(i32a, index2, 3));
304
305 // As above, wait until the workers have been scheduled.
306 wokenCount = 0;
307 while (wokenCount < 3) {
308 for (id = 0; id < 4; id++) {
309 if (Atomics.compareExchange(i32a, id, 1, 2) == 1) {
310 wokenCount++;
311 }
312 }
313 }
314
315 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index1));
316 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index2));
317
318 for (id = 0; id < 4; ++id) {
319 assertEquals(Atomics.OK, workers[id].getMessage());
320 }
321
322 // Test futexWakeOrRequeue on offset typed array
323 var offset = 16;
324 sab = new SharedArrayBuffer(24);
325 i32a = new Int32Array(sab);
326 var i32a2 = new Int32Array(sab, offset);
327
328 for (id = 0; id < 4; id++) {
329 workers[id].postMessage({sab: sab, id: id}, [sab]);
330 }
331
332 while (%AtomicsFutexNumWaitersForTesting(i32a2, 0) != 4) { }
333
334 index1 = 0;
335 index2 = 1;
336 assertEquals(4, %AtomicsFutexNumWaitersForTesting(i32a2, index1));
337 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a2, index2));
338
339 assertEquals(2, Atomics.futexWakeOrRequeue(i32a2, index1, 2, 0, index2));
340 assertEquals(2, %AtomicsFutexNumWaitersForTesting(i32a2, index2));
341 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a2, index1));
342
343 assertEquals(2, Atomics.futexWake(i32a2, index2, 2));
344
345 for (id = 0; id < 4; ++id) {
346 assertEquals(Atomics.OK, workers[id].getMessage());
347 workers[id].terminate();
348 }
349
350 })();
351
352}