68 lines
2.3 KiB
JavaScript
68 lines
2.3 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.AtomicCounter = void 0;
|
|
/**
|
|
* A counter that can be atomically incremented and decremented, and which
|
|
* callers can synchronously listen for it becoming non-zero.
|
|
*
|
|
* This can be "open" or "closed"; once it's closed, {@link wait} will no longer
|
|
* emit useful events.
|
|
*/
|
|
class AtomicCounter {
|
|
/**
|
|
* The underlying BigInt64Array.
|
|
*
|
|
* The first BigInt64 represents the current value of the counter. The second
|
|
* BigInt64 is used to track the closed state.
|
|
*/
|
|
buffer;
|
|
constructor(buffer) {
|
|
if (buffer.byteLength !== 16) {
|
|
throw new Error('SharedArrayBuffer must have a byteLength of 16.');
|
|
}
|
|
this.buffer = new BigInt64Array(buffer);
|
|
}
|
|
/** Atomically decrement the current value by one. */
|
|
decrement() {
|
|
Atomics.sub(this.buffer, 0, 1n);
|
|
}
|
|
/** Atomically increment the current value by one. */
|
|
increment() {
|
|
if (Atomics.add(this.buffer, 0, 1n) === 0n) {
|
|
Atomics.notify(this.buffer, 0, 1);
|
|
}
|
|
}
|
|
/**
|
|
* Closes the counter.
|
|
*
|
|
* This will cause any outstanding calls to {@link wait} on any thread to
|
|
* return `true` immediately.
|
|
*/
|
|
close() {
|
|
// The current value is no longer relevant once closed, therefore set it to
|
|
// non-zero to prevent a potential deadlock when `Atomics.notify` is called
|
|
// immediately before `Atomics.wait`.
|
|
if (Atomics.compareExchange(this.buffer, 1, 0n, 1n) === 0n &&
|
|
Atomics.compareExchange(this.buffer, 0, 0n, 1n) === 0n) {
|
|
Atomics.notify(this.buffer, 0);
|
|
}
|
|
}
|
|
/**
|
|
* Waits until the current value is not zero or the counter is closed.
|
|
*
|
|
* Returns `true` when the counter is non-zero *or* when it's closed. Returns
|
|
* `false` if the counter remains zero for `timeout` milliseconds.
|
|
*/
|
|
wait(timeout) {
|
|
while (Atomics.load(this.buffer, 0) === 0n &&
|
|
Atomics.load(this.buffer, 1) === 0n) {
|
|
const result = Atomics.wait(this.buffer, 0, 0n, timeout);
|
|
if (result !== 'ok') {
|
|
return result !== 'timed-out';
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
exports.AtomicCounter = AtomicCounter;
|
|
//# sourceMappingURL=atomic_counter.js.map
|