OLD | NEW |
(Empty) | |
| 1 // 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-atomics --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 i32a = new Int32Array(new SharedArrayBuffer(16)); |
| 50 |
| 51 // Valid indexes are 0-3. |
| 52 [-1, 4, 100].forEach(function(invalidIndex) { |
| 53 assertEquals(undefined, Atomics.futexWait(i32a, invalidIndex, 0)); |
| 54 assertEquals(undefined, Atomics.futexWake(i32a, invalidIndex, 0)); |
| 55 var validIndex = 0; |
| 56 assertEquals(undefined, Atomics.futexWakeOrRequeue(i32a, invalidIndex, 0, 0, |
| 57 validIndex)); |
| 58 assertEquals(undefined, Atomics.futexWakeOrRequeue(i32a, validIndex, 0, 0, |
| 59 invalidIndex)); |
| 60 }); |
| 61 |
| 62 })(); |
| 63 |
| 64 (function TestWaitTimeout() { |
| 65 var i32a = new Int32Array(new SharedArrayBuffer(16)); |
| 66 var waitMs = 100; |
| 67 var startTime = new Date(); |
| 68 assertEquals(Atomics.TIMEDOUT, Atomics.futexWait(i32a, 0, 0, waitMs)); |
| 69 var endTime = new Date(); |
| 70 assertTrue(endTime - startTime >= waitMs); |
| 71 })(); |
| 72 |
| 73 (function TestWaitNotEqual() { |
| 74 var i32a = new Int32Array(new SharedArrayBuffer(16)); |
| 75 assertEquals(Atomics.NOTEQUAL, Atomics.futexWait(i32a, 0, 42)); |
| 76 })(); |
| 77 |
| 78 (function TestWaitNegativeTimeout() { |
| 79 var i32a = new Int32Array(new SharedArrayBuffer(16)); |
| 80 assertEquals(Atomics.TIMEDOUT, Atomics.futexWait(i32a, 0, 0, -1)); |
| 81 assertEquals(Atomics.TIMEDOUT, Atomics.futexWait(i32a, 0, 0, -Infinity)); |
| 82 })(); |
| 83 |
| 84 //// WORKER ONLY TESTS |
| 85 |
| 86 if (this.Worker) { |
| 87 |
| 88 var TestWaitWithTimeout = function(timeout) { |
| 89 var sab = new SharedArrayBuffer(16); |
| 90 var i32a = new Int32Array(sab); |
| 91 |
| 92 var workerScript = |
| 93 `onmessage = function(sab) { |
| 94 var i32a = new Int32Array(sab); |
| 95 var result = Atomics.futexWait(i32a, 0, 0, ${timeout}); |
| 96 postMessage(result); |
| 97 };`; |
| 98 |
| 99 var worker = new Worker(workerScript); |
| 100 worker.postMessage(sab, [sab]); |
| 101 |
| 102 // Spin until the worker is waiting on the futex. |
| 103 while (%AtomicsFutexNumWaitersForTesting(i32a, 0) != 1) {} |
| 104 |
| 105 Atomics.futexWake(i32a, 0, 1); |
| 106 assertEquals(Atomics.OK, worker.getMessage()); |
| 107 worker.terminate(); |
| 108 }; |
| 109 |
| 110 // Test various infinite timeouts |
| 111 TestWaitWithTimeout(undefined); |
| 112 TestWaitWithTimeout(NaN); |
| 113 TestWaitWithTimeout(Infinity); |
| 114 |
| 115 |
| 116 (function TestWakeMulti() { |
| 117 var sab = new SharedArrayBuffer(20); |
| 118 var i32a = new Int32Array(sab); |
| 119 |
| 120 // SAB values: |
| 121 // i32a[id], where id in range [0, 3]: |
| 122 // 0 => Worker |id| is still waiting on the futex |
| 123 // 1 => Worker |id| is not waiting on futex, but has not be reaped by the |
| 124 // main thread. |
| 125 // 2 => Worker |id| has been reaped. |
| 126 // |
| 127 // i32a[4]: |
| 128 // always 0. Each worker is waiting on this index. |
| 129 |
| 130 var workerScript = |
| 131 `onmessage = function(msg) { |
| 132 var id = msg.id; |
| 133 var i32a = new Int32Array(msg.sab); |
| 134 |
| 135 // Wait on i32a[4] (should be zero). |
| 136 var result = Atomics.futexWait(i32a, 4, 0); |
| 137 // Set i32a[id] to 1 to notify the main thread which workers were |
| 138 // woken up. |
| 139 Atomics.store(i32a, id, 1); |
| 140 postMessage(result); |
| 141 };`; |
| 142 |
| 143 var id; |
| 144 var workers = []; |
| 145 for (id = 0; id < 4; id++) { |
| 146 workers[id] = new Worker(workerScript); |
| 147 workers[id].postMessage({sab: sab, id: id}, [sab]); |
| 148 } |
| 149 |
| 150 // Spin until all workers are waiting on the futex. |
| 151 while (%AtomicsFutexNumWaitersForTesting(i32a, 4) != 4) {} |
| 152 |
| 153 // Wake up three waiters. |
| 154 assertEquals(3, Atomics.futexWake(i32a, 4, 3)); |
| 155 |
| 156 var wokenCount = 0; |
| 157 var waitingId = 0 + 1 + 2 + 3; |
| 158 while (wokenCount < 3) { |
| 159 for (id = 0; id < 4; id++) { |
| 160 // Look for workers that have not yet been reaped. Set i32a[id] to 2 |
| 161 // when they've been processed so we don't look at them again. |
| 162 if (Atomics.compareExchange(i32a, id, 1, 2) == 1) { |
| 163 assertEquals(Atomics.OK, workers[id].getMessage()); |
| 164 workers[id].terminate(); |
| 165 waitingId -= id; |
| 166 wokenCount++; |
| 167 } |
| 168 } |
| 169 } |
| 170 |
| 171 assertEquals(3, wokenCount); |
| 172 assertEquals(0, Atomics.load(i32a, waitingId)); |
| 173 assertEquals(1, %AtomicsFutexNumWaitersForTesting(i32a, 4)); |
| 174 |
| 175 // Finally wake the last waiter. |
| 176 assertEquals(1, Atomics.futexWake(i32a, 4, 1)); |
| 177 assertEquals(Atomics.OK, workers[waitingId].getMessage()); |
| 178 workers[waitingId].terminate(); |
| 179 |
| 180 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, 4)); |
| 181 |
| 182 })(); |
| 183 |
| 184 (function TestWakeOrRequeue() { |
| 185 var sab = new SharedArrayBuffer(24); |
| 186 var i32a = new Int32Array(sab); |
| 187 |
| 188 // SAB values: |
| 189 // i32a[id], where id in range [0, 3]: |
| 190 // 0 => Worker |id| is still waiting on the futex |
| 191 // 1 => Worker |id| is not waiting on futex, but has not be reaped by the |
| 192 // main thread. |
| 193 // 2 => Worker |id| has been reaped. |
| 194 // |
| 195 // i32a[4]: |
| 196 // always 0. Each worker will initially wait on this index. |
| 197 // |
| 198 // i32a[5]: |
| 199 // always 0. Requeued workers will wait on this index. |
| 200 |
| 201 var workerScript = |
| 202 `onmessage = function(msg) { |
| 203 var id = msg.id; |
| 204 var i32a = new Int32Array(msg.sab); |
| 205 |
| 206 var result = Atomics.futexWait(i32a, 4, 0, Infinity); |
| 207 Atomics.store(i32a, id, 1); |
| 208 postMessage(result); |
| 209 };`; |
| 210 |
| 211 var workers = []; |
| 212 for (id = 0; id < 4; id++) { |
| 213 workers[id] = new Worker(workerScript); |
| 214 workers[id].postMessage({sab: sab, id: id}, [sab]); |
| 215 } |
| 216 |
| 217 // Spin until all workers are waiting on the futex. |
| 218 while (%AtomicsFutexNumWaitersForTesting(i32a, 4) != 4) {} |
| 219 |
| 220 var index1 = 4; |
| 221 var index2 = 5; |
| 222 |
| 223 // If futexWakeOrRequeue is called with the incorrect value, it shouldn't |
| 224 // wake any waiters. |
| 225 assertEquals(Atomics.NOTEQUAL, |
| 226 Atomics.futexWakeOrRequeue(i32a, index1, 1, 42, index2)); |
| 227 |
| 228 assertEquals(4, %AtomicsFutexNumWaitersForTesting(i32a, index1)); |
| 229 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index2)); |
| 230 |
| 231 // Now wake with the correct value. |
| 232 assertEquals(1, Atomics.futexWakeOrRequeue(i32a, index1, 1, 0, index2)); |
| 233 |
| 234 // The workers that are still waiting should atomically be transferred to |
| 235 // the new index. |
| 236 assertEquals(3, %AtomicsFutexNumWaitersForTesting(i32a, index2)); |
| 237 |
| 238 // The woken worker may not have been scheduled yet. Look for which thread |
| 239 // has set its i32a value to 1. |
| 240 var wokenCount = 0; |
| 241 while (wokenCount < 1) { |
| 242 for (id = 0; id < 4; id++) { |
| 243 if (Atomics.compareExchange(i32a, id, 1, 2) == 1) { |
| 244 wokenCount++; |
| 245 } |
| 246 } |
| 247 } |
| 248 |
| 249 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index1)); |
| 250 |
| 251 // Wake the remaining waiters. |
| 252 assertEquals(3, Atomics.futexWake(i32a, index2, 3)); |
| 253 |
| 254 // As above, wait until the workers have been scheduled. |
| 255 wokenCount = 0; |
| 256 while (wokenCount < 3) { |
| 257 for (id = 0; id < 4; id++) { |
| 258 if (Atomics.compareExchange(i32a, id, 1, 2) == 1) { |
| 259 wokenCount++; |
| 260 } |
| 261 } |
| 262 } |
| 263 |
| 264 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index1)); |
| 265 assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a, index2)); |
| 266 |
| 267 for (id = 0; id < 4; ++id) { |
| 268 assertEquals(Atomics.OK, workers[id].getMessage()); |
| 269 workers[id].terminate(); |
| 270 } |
| 271 |
| 272 })(); |
| 273 |
| 274 } |
OLD | NEW |