[Atomics] Rename Atomics.futex*, remove Atomics.futexWakeOrRequeue
* Rename Atomics.futexWait -> Atomics.wait * Rename Atomics.futexWake -> Atomics.wake * Remove Atomics.futexWakeOrRequeue * Return value of Atomics.wait is now a string: "ok", "not-equal" or "timed-out" * Update comments that reference URL for ecmascript_sharedmem to https://github.com/tc39/ecmascript_sharedmem Review-Url: https://codereview.chromium.org/2143443002 Cr-Commit-Position: refs/heads/master@{#37727}
This commit is contained in:
parent
906cb204d0
commit
a16ca012e0
@ -84,7 +84,7 @@ Object* FutexEmulation::Wait(Isolate* isolate,
|
||||
base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer());
|
||||
|
||||
if (*p != value) {
|
||||
return Smi::FromInt(Result::kNotEqual);
|
||||
return isolate->heap()->not_equal();
|
||||
}
|
||||
|
||||
FutexWaitListNode* node = isolate->futex_wait_list_node();
|
||||
@ -157,7 +157,7 @@ Object* FutexEmulation::Wait(Isolate* isolate,
|
||||
}
|
||||
|
||||
if (!node->waiting_) {
|
||||
result = Smi::FromInt(Result::kOk);
|
||||
result = isolate->heap()->ok();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -165,7 +165,7 @@ Object* FutexEmulation::Wait(Isolate* isolate,
|
||||
if (use_timeout) {
|
||||
current_time = base::TimeTicks::Now();
|
||||
if (current_time >= timeout_time) {
|
||||
result = Smi::FromInt(Result::kTimedOut);
|
||||
result = isolate->heap()->timed_out();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -213,44 +213,6 @@ Object* FutexEmulation::Wake(Isolate* isolate,
|
||||
}
|
||||
|
||||
|
||||
Object* FutexEmulation::WakeOrRequeue(Isolate* isolate,
|
||||
Handle<JSArrayBuffer> array_buffer,
|
||||
size_t addr, int num_waiters_to_wake,
|
||||
int32_t value, size_t addr2) {
|
||||
DCHECK(addr < NumberToSize(isolate, array_buffer->byte_length()));
|
||||
DCHECK(addr2 < NumberToSize(isolate, array_buffer->byte_length()));
|
||||
|
||||
void* backing_store = array_buffer->backing_store();
|
||||
int32_t* p =
|
||||
reinterpret_cast<int32_t*>(static_cast<int8_t*>(backing_store) + addr);
|
||||
|
||||
base::LockGuard<base::Mutex> lock_guard(mutex_.Pointer());
|
||||
if (*p != value) {
|
||||
return Smi::FromInt(Result::kNotEqual);
|
||||
}
|
||||
|
||||
// Wake |num_waiters_to_wake|
|
||||
int waiters_woken = 0;
|
||||
FutexWaitListNode* node = wait_list_.Pointer()->head_;
|
||||
while (node) {
|
||||
if (backing_store == node->backing_store_ && addr == node->wait_addr_) {
|
||||
if (num_waiters_to_wake > 0) {
|
||||
node->waiting_ = false;
|
||||
node->cond_.NotifyOne();
|
||||
--num_waiters_to_wake;
|
||||
waiters_woken++;
|
||||
} else {
|
||||
node->wait_addr_ = addr2;
|
||||
}
|
||||
}
|
||||
|
||||
node = node->next_;
|
||||
}
|
||||
|
||||
return Smi::FromInt(waiters_woken);
|
||||
}
|
||||
|
||||
|
||||
Object* FutexEmulation::NumWaitersForTesting(Isolate* isolate,
|
||||
Handle<JSArrayBuffer> array_buffer,
|
||||
size_t addr) {
|
||||
|
@ -21,7 +21,7 @@
|
||||
// variables for consistency.
|
||||
//
|
||||
// This is used by the Futex API defined in the SharedArrayBuffer draft spec,
|
||||
// found here: https://github.com/lars-t-hansen/ecmascript_sharedmem
|
||||
// found here: https://github.com/tc39/ecmascript_sharedmem
|
||||
|
||||
namespace v8 {
|
||||
|
||||
@ -81,18 +81,11 @@ class FutexWaitList {
|
||||
|
||||
class FutexEmulation : public AllStatic {
|
||||
public:
|
||||
// These must match the values in src/harmony-atomics.js
|
||||
enum Result {
|
||||
kOk = 0,
|
||||
kNotEqual = -1,
|
||||
kTimedOut = -2,
|
||||
};
|
||||
|
||||
// Check that array_buffer[addr] == value, and return kNotEqual if not. If
|
||||
// Check that array_buffer[addr] == value, and return "not-equal" if not. If
|
||||
// they are equal, block execution on |isolate|'s thread until woken via
|
||||
// |Wake|, or when the time given in |rel_timeout_ms| elapses. Note that
|
||||
// |rel_timeout_ms| can be Infinity.
|
||||
// If woken, return kOk, otherwise return kTimedOut. The initial check and
|
||||
// If woken, return "ok", otherwise return "timed-out". The initial check and
|
||||
// the decision to wait happen atomically.
|
||||
static Object* Wait(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
|
||||
size_t addr, int32_t value, double rel_timeout_ms);
|
||||
@ -103,16 +96,6 @@ class FutexEmulation : public AllStatic {
|
||||
static Object* Wake(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
|
||||
size_t addr, int num_waiters_to_wake);
|
||||
|
||||
// Check that array_buffer[addr] == value, and return kNotEqual if not. If
|
||||
// they are equal, wake |num_waiters_to_wake| threads that are waiting on the
|
||||
// given |addr|. The rest of the waiters will continue to wait, but will now
|
||||
// be waiting on |addr2| instead of |addr|. The return value is the number of
|
||||
// woken waiters or kNotEqual as described above.
|
||||
static Object* WakeOrRequeue(Isolate* isolate,
|
||||
Handle<JSArrayBuffer> array_buffer, size_t addr,
|
||||
int num_waiters_to_wake, int32_t value,
|
||||
size_t addr2);
|
||||
|
||||
// Return the number of threads waiting on |addr|. Should only be used for
|
||||
// testing.
|
||||
static Object* NumWaitersForTesting(Isolate* isolate,
|
||||
|
@ -97,12 +97,14 @@
|
||||
V(name_string, "name") \
|
||||
V(nan_string, "NaN") \
|
||||
V(next_string, "next") \
|
||||
V(not_equal, "not-equal") \
|
||||
V(null_string, "null") \
|
||||
V(null_to_string, "[object Null]") \
|
||||
V(number_string, "number") \
|
||||
V(Number_string, "Number") \
|
||||
V(object_string, "object") \
|
||||
V(Object_string, "Object") \
|
||||
V(ok, "ok") \
|
||||
V(ownKeys_string, "ownKeys") \
|
||||
V(position_string, "position") \
|
||||
V(preventExtensions_string, "preventExtensions") \
|
||||
@ -129,6 +131,7 @@
|
||||
V(Symbol_string, "Symbol") \
|
||||
V(this_string, "this") \
|
||||
V(throw_string, "throw") \
|
||||
V(timed_out, "timed-out") \
|
||||
V(toJSON_string, "toJSON") \
|
||||
V(toString_string, "toString") \
|
||||
V(true_string, "true") \
|
||||
|
@ -108,9 +108,7 @@ function AtomicsIsLockFreeJS(size) {
|
||||
return %_AtomicsIsLockFree(size);
|
||||
}
|
||||
|
||||
// Futexes
|
||||
|
||||
function AtomicsFutexWaitJS(ia, index, value, timeout) {
|
||||
function AtomicsWaitJS(ia, index, value, timeout) {
|
||||
CheckSharedInteger32TypedArray(ia);
|
||||
index = ValidateIndex(index, %_TypedArrayGetLength(ia));
|
||||
if (IS_UNDEFINED(timeout)) {
|
||||
@ -123,27 +121,14 @@ function AtomicsFutexWaitJS(ia, index, value, timeout) {
|
||||
timeout = MaxSimple(0, timeout);
|
||||
}
|
||||
}
|
||||
return %AtomicsFutexWait(ia, index, value, timeout);
|
||||
return %AtomicsWait(ia, index, value, timeout);
|
||||
}
|
||||
|
||||
function AtomicsFutexWakeJS(ia, index, count) {
|
||||
function AtomicsWakeJS(ia, index, count) {
|
||||
CheckSharedInteger32TypedArray(ia);
|
||||
index = ValidateIndex(index, %_TypedArrayGetLength(ia));
|
||||
count = MaxSimple(0, TO_INTEGER(count));
|
||||
return %AtomicsFutexWake(ia, index, count);
|
||||
}
|
||||
|
||||
function AtomicsFutexWakeOrRequeueJS(ia, index1, count, value, index2) {
|
||||
CheckSharedInteger32TypedArray(ia);
|
||||
index1 = ValidateIndex(index1, %_TypedArrayGetLength(ia));
|
||||
count = MaxSimple(0, TO_INTEGER(count));
|
||||
value = TO_INT32(value);
|
||||
index2 = ValidateIndex(index2, %_TypedArrayGetLength(ia));
|
||||
if (index1 < 0 || index1 >= %_TypedArrayGetLength(ia) ||
|
||||
index2 < 0 || index2 >= %_TypedArrayGetLength(ia)) {
|
||||
return UNDEFINED;
|
||||
}
|
||||
return %AtomicsFutexWakeOrRequeue(ia, index1, count, value, index2);
|
||||
return %AtomicsWake(ia, index, count);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
@ -154,13 +139,6 @@ var Atomics = global.Atomics;
|
||||
|
||||
%AddNamedProperty(Atomics, toStringTagSymbol, "Atomics", READ_ONLY | DONT_ENUM);
|
||||
|
||||
// These must match the values in src/futex-emulation.h
|
||||
utils.InstallConstants(Atomics, [
|
||||
"OK", 0,
|
||||
"NOTEQUAL", -1,
|
||||
"TIMEDOUT", -2,
|
||||
]);
|
||||
|
||||
utils.InstallFunctions(Atomics, DONT_ENUM, [
|
||||
// TODO(binji): remove the rest of the (non futex) Atomics functions as they
|
||||
// become builtins.
|
||||
@ -172,9 +150,8 @@ utils.InstallFunctions(Atomics, DONT_ENUM, [
|
||||
"xor", AtomicsXorJS,
|
||||
"exchange", AtomicsExchangeJS,
|
||||
"isLockFree", AtomicsIsLockFreeJS,
|
||||
"futexWait", AtomicsFutexWaitJS,
|
||||
"futexWake", AtomicsFutexWakeJS,
|
||||
"futexWakeOrRequeue", AtomicsFutexWakeOrRequeueJS,
|
||||
"wait", AtomicsWaitJS,
|
||||
"wake", AtomicsWakeJS,
|
||||
]);
|
||||
|
||||
})
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
// Implement Atomic accesses to SharedArrayBuffers as defined in the
|
||||
// SharedArrayBuffer draft spec, found here
|
||||
// https://github.com/lars-t-hansen/ecmascript_sharedmem
|
||||
// https://github.com/tc39/ecmascript_sharedmem
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -12,12 +12,12 @@
|
||||
|
||||
// Implement Futex API for SharedArrayBuffers as defined in the
|
||||
// SharedArrayBuffer draft spec, found here:
|
||||
// https://github.com/lars-t-hansen/ecmascript_sharedmem
|
||||
// https://github.com/tc39/ecmascript_sharedmem
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_AtomicsFutexWait) {
|
||||
RUNTIME_FUNCTION(Runtime_AtomicsWait) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 4);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
|
||||
@ -35,8 +35,7 @@ RUNTIME_FUNCTION(Runtime_AtomicsFutexWait) {
|
||||
return FutexEmulation::Wait(isolate, array_buffer, addr, value, timeout);
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_AtomicsFutexWake) {
|
||||
RUNTIME_FUNCTION(Runtime_AtomicsWake) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 3);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
|
||||
@ -52,30 +51,7 @@ RUNTIME_FUNCTION(Runtime_AtomicsFutexWake) {
|
||||
return FutexEmulation::Wake(isolate, array_buffer, addr, count);
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_AtomicsFutexWakeOrRequeue) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 5);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
|
||||
CONVERT_SIZE_ARG_CHECKED(index1, 1);
|
||||
CONVERT_INT32_ARG_CHECKED(count, 2);
|
||||
CONVERT_INT32_ARG_CHECKED(value, 3);
|
||||
CONVERT_SIZE_ARG_CHECKED(index2, 4);
|
||||
CHECK(sta->GetBuffer()->is_shared());
|
||||
CHECK_LT(index1, NumberToSize(isolate, sta->length()));
|
||||
CHECK_LT(index2, NumberToSize(isolate, sta->length()));
|
||||
CHECK_EQ(sta->type(), kExternalInt32Array);
|
||||
|
||||
Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
|
||||
size_t addr1 = (index1 << 2) + NumberToSize(isolate, sta->byte_offset());
|
||||
size_t addr2 = (index2 << 2) + NumberToSize(isolate, sta->byte_offset());
|
||||
|
||||
return FutexEmulation::WakeOrRequeue(isolate, array_buffer, addr1, count,
|
||||
value, addr2);
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_AtomicsFutexNumWaitersForTesting) {
|
||||
RUNTIME_FUNCTION(Runtime_AtomicsNumWaitersForTesting) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
|
||||
|
@ -64,13 +64,10 @@ namespace internal {
|
||||
F(AtomicsOr, 3, 1) \
|
||||
F(AtomicsXor, 3, 1) \
|
||||
F(AtomicsExchange, 3, 1) \
|
||||
F(AtomicsIsLockFree, 1, 1)
|
||||
|
||||
#define FOR_EACH_INTRINSIC_FUTEX(F) \
|
||||
F(AtomicsFutexWait, 4, 1) \
|
||||
F(AtomicsFutexWake, 3, 1) \
|
||||
F(AtomicsFutexWakeOrRequeue, 5, 1) \
|
||||
F(AtomicsFutexNumWaitersForTesting, 2, 1)
|
||||
F(AtomicsIsLockFree, 1, 1) \
|
||||
F(AtomicsWait, 4, 1) \
|
||||
F(AtomicsWake, 3, 1) \
|
||||
F(AtomicsNumWaitersForTesting, 2, 1)
|
||||
|
||||
#define FOR_EACH_INTRINSIC_CLASSES(F) \
|
||||
F(ThrowNonMethodError, 0, 1) \
|
||||
@ -966,7 +963,6 @@ namespace internal {
|
||||
FOR_EACH_INTRINSIC_FORIN(F) \
|
||||
FOR_EACH_INTRINSIC_INTERPRETER(F) \
|
||||
FOR_EACH_INTRINSIC_FUNCTION(F) \
|
||||
FOR_EACH_INTRINSIC_FUTEX(F) \
|
||||
FOR_EACH_INTRINSIC_GENERATOR(F) \
|
||||
FOR_EACH_INTRINSIC_I18N(F) \
|
||||
FOR_EACH_INTRINSIC_INTERNAL(F) \
|
||||
|
@ -25043,7 +25043,7 @@ TEST(FutexInterruption) {
|
||||
CompileRun(
|
||||
"var ab = new SharedArrayBuffer(4);"
|
||||
"var i32a = new Int32Array(ab);"
|
||||
"Atomics.futexWait(i32a, 0, 0);");
|
||||
"Atomics.wait(i32a, 0, 0);");
|
||||
CHECK(try_catch.HasTerminated());
|
||||
timeout_thread.Join();
|
||||
}
|
||||
|
@ -19,9 +19,8 @@
|
||||
|
||||
[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); });
|
||||
assertThrows(function() { Atomics.wait(ta, 0, 0); });
|
||||
assertThrows(function() { Atomics.wake(ta, 0, 1); });
|
||||
});
|
||||
})();
|
||||
|
||||
@ -39,9 +38,8 @@
|
||||
|
||||
[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); });
|
||||
assertThrows(function() { Atomics.wait(ta, 0, 0); });
|
||||
assertThrows(function() { Atomics.wake(ta, 0, 1); });
|
||||
});
|
||||
})();
|
||||
|
||||
@ -52,35 +50,23 @@
|
||||
// Valid indexes are 0-3.
|
||||
[-1, 4, 100].forEach(function(invalidIndex) {
|
||||
assertThrows(function() {
|
||||
Atomics.futexWait(i32a, invalidIndex, 0);
|
||||
Atomics.wait(i32a, invalidIndex, 0);
|
||||
}, RangeError);
|
||||
assertThrows(function() {
|
||||
Atomics.futexWake(i32a, invalidIndex, 0);
|
||||
Atomics.wake(i32a, invalidIndex, 0);
|
||||
}, RangeError);
|
||||
var validIndex = 0;
|
||||
assertThrows(function() {
|
||||
Atomics.futexWakeOrRequeue(i32a, invalidIndex, 0, 0, validIndex);
|
||||
}, RangeError);
|
||||
assertThrows(function() {
|
||||
Atomics.futexWakeOrRequeue(i32a, validIndex, 0, 0, invalidIndex);
|
||||
}, RangeError);
|
||||
});
|
||||
|
||||
i32a = new Int32Array(sab, 8);
|
||||
[-1, 2, 100].forEach(function(invalidIndex) {
|
||||
assertThrows(function() {
|
||||
Atomics.futexWait(i32a, invalidIndex, 0);
|
||||
Atomics.wait(i32a, invalidIndex, 0);
|
||||
}, RangeError);
|
||||
assertThrows(function() {
|
||||
Atomics.futexWake(i32a, invalidIndex, 0);
|
||||
Atomics.wake(i32a, invalidIndex, 0);
|
||||
}, RangeError);
|
||||
var validIndex = 0;
|
||||
assertThrows(function() {
|
||||
Atomics.futexWakeOrRequeue(i32a, invalidIndex, 0, 0, validIndex);
|
||||
}, RangeError);
|
||||
assertThrows(function() {
|
||||
Atomics.futexWakeOrRequeue(i32a, validIndex, 0, 0, invalidIndex);
|
||||
}, RangeError);
|
||||
});
|
||||
})();
|
||||
|
||||
@ -88,7 +74,7 @@
|
||||
var i32a = new Int32Array(new SharedArrayBuffer(16));
|
||||
var waitMs = 100;
|
||||
var startTime = new Date();
|
||||
assertEquals(Atomics.TIMEDOUT, Atomics.futexWait(i32a, 0, 0, waitMs));
|
||||
assertEquals("timed-out", Atomics.wait(i32a, 0, 0, waitMs));
|
||||
var endTime = new Date();
|
||||
assertTrue(endTime - startTime >= waitMs);
|
||||
})();
|
||||
@ -96,17 +82,17 @@
|
||||
(function TestWaitNotEqual() {
|
||||
var sab = new SharedArrayBuffer(16);
|
||||
var i32a = new Int32Array(sab);
|
||||
assertEquals(Atomics.NOTEQUAL, Atomics.futexWait(i32a, 0, 42));
|
||||
assertEquals("not-equal", Atomics.wait(i32a, 0, 42));
|
||||
|
||||
i32a = new Int32Array(sab, 8);
|
||||
i32a[0] = 1;
|
||||
assertEquals(Atomics.NOTEQUAL, Atomics.futexWait(i32a, 0, 0));
|
||||
assertEquals("not-equal", Atomics.wait(i32a, 0, 0));
|
||||
})();
|
||||
|
||||
(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));
|
||||
assertEquals("timed-out", Atomics.wait(i32a, 0, 0, -1));
|
||||
assertEquals("timed-out", Atomics.wait(i32a, 0, 0, -Infinity));
|
||||
})();
|
||||
|
||||
//// WORKER ONLY TESTS
|
||||
@ -120,7 +106,7 @@ if (this.Worker) {
|
||||
var workerScript =
|
||||
`onmessage = function(msg) {
|
||||
var i32a = new Int32Array(msg.sab, msg.offset);
|
||||
var result = Atomics.futexWait(i32a, 0, 0, ${timeout});
|
||||
var result = Atomics.wait(i32a, 0, 0, ${timeout});
|
||||
postMessage(result);
|
||||
};`;
|
||||
|
||||
@ -128,10 +114,10 @@ if (this.Worker) {
|
||||
worker.postMessage({sab: sab, offset: offset}, [sab]);
|
||||
|
||||
// Spin until the worker is waiting on the futex.
|
||||
while (%AtomicsFutexNumWaitersForTesting(i32a, 0) != 1) {}
|
||||
while (%AtomicsNumWaitersForTesting(i32a, 0) != 1) {}
|
||||
|
||||
Atomics.futexWake(i32a, 0, 1);
|
||||
assertEquals(Atomics.OK, worker.getMessage());
|
||||
Atomics.wake(i32a, 0, 1);
|
||||
assertEquals("ok", worker.getMessage());
|
||||
worker.terminate();
|
||||
|
||||
var worker2 = new Worker(workerScript);
|
||||
@ -140,9 +126,9 @@ if (this.Worker) {
|
||||
worker2.postMessage({sab: sab, offset: offset}, [sab]);
|
||||
|
||||
// Spin until the worker is waiting on the futex.
|
||||
while (%AtomicsFutexNumWaitersForTesting(i32a2, 0) != 1) {}
|
||||
Atomics.futexWake(i32a2, 0, 1);
|
||||
assertEquals(Atomics.OK, worker2.getMessage());
|
||||
while (%AtomicsNumWaitersForTesting(i32a2, 0) != 1) {}
|
||||
Atomics.wake(i32a2, 0, 1);
|
||||
assertEquals("ok", worker2.getMessage());
|
||||
worker2.terminate();
|
||||
|
||||
// Futex should work when index and buffer views are different, but
|
||||
@ -152,9 +138,9 @@ if (this.Worker) {
|
||||
worker3.postMessage({sab: sab, offset: 8}, [sab]);
|
||||
|
||||
// Spin until the worker is waiting on the futex.
|
||||
while (%AtomicsFutexNumWaitersForTesting(i32a2, 1) != 1) {}
|
||||
Atomics.futexWake(i32a2, 1, 1);
|
||||
assertEquals(Atomics.OK, worker3.getMessage());
|
||||
while (%AtomicsNumWaitersForTesting(i32a2, 1) != 1) {}
|
||||
Atomics.wake(i32a2, 1, 1);
|
||||
assertEquals("ok", worker3.getMessage());
|
||||
worker3.terminate();
|
||||
};
|
||||
|
||||
@ -184,7 +170,7 @@ if (this.Worker) {
|
||||
var i32a = new Int32Array(msg.sab);
|
||||
|
||||
// Wait on i32a[4] (should be zero).
|
||||
var result = Atomics.futexWait(i32a, 4, 0);
|
||||
var result = Atomics.wait(i32a, 4, 0);
|
||||
// Set i32a[id] to 1 to notify the main thread which workers were
|
||||
// woken up.
|
||||
Atomics.store(i32a, id, 1);
|
||||
@ -199,10 +185,10 @@ if (this.Worker) {
|
||||
}
|
||||
|
||||
// Spin until all workers are waiting on the futex.
|
||||
while (%AtomicsFutexNumWaitersForTesting(i32a, 4) != 4) {}
|
||||
while (%AtomicsNumWaitersForTesting(i32a, 4) != 4) {}
|
||||
|
||||
// Wake up three waiters.
|
||||
assertEquals(3, Atomics.futexWake(i32a, 4, 3));
|
||||
assertEquals(3, Atomics.wake(i32a, 4, 3));
|
||||
|
||||
var wokenCount = 0;
|
||||
var waitingId = 0 + 1 + 2 + 3;
|
||||
@ -211,7 +197,7 @@ if (this.Worker) {
|
||||
// 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());
|
||||
assertEquals("ok", workers[id].getMessage());
|
||||
workers[id].terminate();
|
||||
waitingId -= id;
|
||||
wokenCount++;
|
||||
@ -221,131 +207,14 @@ if (this.Worker) {
|
||||
|
||||
assertEquals(3, wokenCount);
|
||||
assertEquals(0, Atomics.load(i32a, waitingId));
|
||||
assertEquals(1, %AtomicsFutexNumWaitersForTesting(i32a, 4));
|
||||
assertEquals(1, %AtomicsNumWaitersForTesting(i32a, 4));
|
||||
|
||||
// Finally wake the last waiter.
|
||||
assertEquals(1, Atomics.futexWake(i32a, 4, 1));
|
||||
assertEquals(Atomics.OK, workers[waitingId].getMessage());
|
||||
assertEquals(1, Atomics.wake(i32a, 4, 1));
|
||||
assertEquals("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());
|
||||
}
|
||||
|
||||
// Test futexWakeOrRequeue on offset typed array
|
||||
var offset = 16;
|
||||
sab = new SharedArrayBuffer(24);
|
||||
i32a = new Int32Array(sab);
|
||||
var i32a2 = new Int32Array(sab, offset);
|
||||
|
||||
for (id = 0; id < 4; id++) {
|
||||
workers[id].postMessage({sab: sab, id: id}, [sab]);
|
||||
}
|
||||
|
||||
while (%AtomicsFutexNumWaitersForTesting(i32a2, 0) != 4) { }
|
||||
|
||||
index1 = 0;
|
||||
index2 = 1;
|
||||
assertEquals(4, %AtomicsFutexNumWaitersForTesting(i32a2, index1));
|
||||
assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a2, index2));
|
||||
|
||||
assertEquals(2, Atomics.futexWakeOrRequeue(i32a2, index1, 2, 0, index2));
|
||||
assertEquals(2, %AtomicsFutexNumWaitersForTesting(i32a2, index2));
|
||||
assertEquals(0, %AtomicsFutexNumWaitersForTesting(i32a2, index1));
|
||||
|
||||
assertEquals(2, Atomics.futexWake(i32a2, index2, 2));
|
||||
|
||||
for (id = 0; id < 4; ++id) {
|
||||
assertEquals(Atomics.OK, workers[id].getMessage());
|
||||
workers[id].terminate();
|
||||
}
|
||||
assertEquals(0, %AtomicsNumWaitersForTesting(i32a, 4));
|
||||
|
||||
})();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user