PR-URL: https://github.com/nodejs/node/pull/54077 Reviewed-By: Jiawen Geng <technicalcute@gmail.com> Reviewed-By: Richard Lau <rlau@redhat.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
100 lines
3.5 KiB
JavaScript
100 lines
3.5 KiB
JavaScript
// Copyright 2024 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: --harmony-struct --allow-natives-syntax --expose-gc
|
|
// Flags: --no-lazy-compile-dispatcher --no-concurrent-recompilation
|
|
|
|
if (this.Worker) {
|
|
(function TestRealmWithAsyncWaiterDisposed() {
|
|
let workerScript = `onmessage = function({data:msg}) {
|
|
let {mutex, cv, sharedObj} = msg;
|
|
Atomics.Mutex.lock(mutex, function() {
|
|
postMessage('Lock acquired');
|
|
Atomics.Condition.wait(cv, mutex);
|
|
sharedObj.counter++;
|
|
});
|
|
postMessage('Stopped waiting');
|
|
};
|
|
postMessage('started');`;
|
|
|
|
let realmScript = `
|
|
Atomics.Mutex.lockAsync(Realm.shared.mutex, async function() {
|
|
await Atomics.Condition.waitAsync(Realm.shared.cv, Realm.shared.mutex);
|
|
Realm.shared.sharedObj.counter++;
|
|
});`;
|
|
|
|
let worker1 = new Worker(workerScript, {type: 'string'});
|
|
assertEquals('started', worker1.getMessage());
|
|
let worker2 = new Worker(workerScript, {type: 'string'});
|
|
assertEquals('started', worker2.getMessage());
|
|
let realm = Realm.create();
|
|
|
|
let mutex = new Atomics.Mutex;
|
|
let cv = new Atomics.Condition;
|
|
let SharedType = new SharedStructType(['counter']);
|
|
let sharedObj = new SharedType();
|
|
sharedObj.counter = 0;
|
|
let lock_msg = {mutex, cv, sharedObj};
|
|
Realm.shared = {mutex, cv, sharedObj};
|
|
|
|
worker1.postMessage(lock_msg);
|
|
assertEquals('Lock acquired', worker1.getMessage())
|
|
// Wait until the cv waiter is queued.
|
|
while (%AtomicsSynchronizationPrimitiveNumWaitersForTesting(cv) !== 1) {
|
|
}
|
|
|
|
Realm.eval(realm, realmScript);
|
|
|
|
// Flush microtask queue, the async lock is taken and waitAsync is called.
|
|
setTimeout(() => {
|
|
assertEquals(
|
|
2, %AtomicsSynchronizationPrimitiveNumWaitersForTesting(cv));
|
|
worker2.postMessage(lock_msg);
|
|
assertEquals('Lock acquired', worker2.getMessage());
|
|
// Wait until the cv waiter is queued.
|
|
while (%AtomicsSynchronizationPrimitiveNumWaitersForTesting(cv) !== 3) {
|
|
}
|
|
|
|
Realm.dispose(realm);
|
|
// Cleanup the realm's native context.
|
|
let collected = false;
|
|
gc({type: 'major', execution: 'async'})
|
|
.then(() => {collected = true}, (e) => {
|
|
throw e;
|
|
});
|
|
|
|
let executeAsserts = () => {
|
|
// The realm was disposed but the waiter nodes created for both: the
|
|
// asyncLock and the asyncWait are still in the isolate's async waiter
|
|
// list.
|
|
assertEquals(
|
|
2, %AtomicsSychronizationNumAsyncWaitersInIsolateForTesting());
|
|
// There are still 3 waiters in the cv queue.
|
|
assertEquals(
|
|
3, %AtomicsSynchronizationPrimitiveNumWaitersForTesting(cv));
|
|
assertEquals(0, sharedObj.counter);
|
|
Atomics.Condition.notify(cv, 3);
|
|
setTimeout(() => {
|
|
assertEquals('Stopped waiting', worker1.getMessage());
|
|
assertEquals('Stopped waiting', worker2.getMessage());
|
|
assertEquals(
|
|
0, %AtomicsSynchronizationPrimitiveNumWaitersForTesting(cv));
|
|
// The notification for the async waiter was processed but execution
|
|
// didn't continue.
|
|
assertEquals(2, sharedObj.counter);
|
|
}, 0);
|
|
};
|
|
|
|
let asyncLoop = () => {
|
|
if (!collected) {
|
|
setTimeout(asyncLoop, 0);
|
|
return;
|
|
}
|
|
executeAsserts();
|
|
};
|
|
asyncLoop();
|
|
}, 0);
|
|
})();
|
|
}
|