multithreading
Version:
The missing standard library for multithreading in JavaScript (Works in the browser, Node.js, Deno, Bun).
121 lines (120 loc) • 6.42 kB
JavaScript
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _MutexGuard_data, _MutexGuard_mutex, _MutexGuard_released, _Mutex_instances, _a, _Mutex_data, _Mutex_lockState, _Mutex_controller, _Mutex_tryLock, _Mutex_unlock, _Mutex_performBlockingLock, _Mutex_performAsyncLock;
import { deserialize, register, Serializable, serialize, toDeserialized, toSerialized, } from "../shared.js";
export const INTERNAL_MUTEX_CONTROLLER = Symbol("Thread.InternalMutexController");
const IDX_LOCK_STATE = 0;
const LOCKED = 1;
const UNLOCKED = 0;
export class MutexGuard {
constructor(data, mutex) {
_MutexGuard_data.set(this, void 0);
_MutexGuard_mutex.set(this, void 0);
_MutexGuard_released.set(this, false);
__classPrivateFieldSet(this, _MutexGuard_data, data, "f");
__classPrivateFieldSet(this, _MutexGuard_mutex, mutex, "f");
}
/**
* Internal accessor for Condvar support
*/
get [(_MutexGuard_data = new WeakMap(), _MutexGuard_mutex = new WeakMap(), _MutexGuard_released = new WeakMap(), INTERNAL_MUTEX_CONTROLLER)]() {
return __classPrivateFieldGet(this, _MutexGuard_mutex, "f");
}
get value() {
if (__classPrivateFieldGet(this, _MutexGuard_released, "f"))
throw new Error("Cannot access released mutex data");
return __classPrivateFieldGet(this, _MutexGuard_data, "f");
}
[Symbol.dispose]() {
if (!__classPrivateFieldGet(this, _MutexGuard_released, "f")) {
__classPrivateFieldSet(this, _MutexGuard_released, true, "f");
__classPrivateFieldGet(this, _MutexGuard_mutex, "f").unlock();
}
}
dispose() {
this[Symbol.dispose]();
}
}
export class Mutex extends Serializable {
constructor(data, _lockBuffer) {
super();
_Mutex_instances.add(this);
_Mutex_data.set(this, void 0);
_Mutex_lockState.set(this, void 0);
_Mutex_controller.set(this, void 0);
__classPrivateFieldSet(this, _Mutex_data, data, "f");
__classPrivateFieldSet(this, _Mutex_lockState, _lockBuffer
? new Int32Array(_lockBuffer)
: new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT)), "f");
__classPrivateFieldSet(this, _Mutex_controller, {
unlock: () => __classPrivateFieldGet(this, _Mutex_instances, "m", _Mutex_unlock).call(this),
blockingLock: () => __classPrivateFieldGet(this, _Mutex_instances, "m", _Mutex_performBlockingLock).call(this),
lock: () => __classPrivateFieldGet(this, _Mutex_instances, "m", _Mutex_performAsyncLock).call(this),
}, "f");
}
blockingLock() {
__classPrivateFieldGet(this, _Mutex_instances, "m", _Mutex_performBlockingLock).call(this);
return new MutexGuard(__classPrivateFieldGet(this, _Mutex_data, "f"), __classPrivateFieldGet(this, _Mutex_controller, "f"));
}
async lock() {
await __classPrivateFieldGet(this, _Mutex_instances, "m", _Mutex_performAsyncLock).call(this);
return new MutexGuard(__classPrivateFieldGet(this, _Mutex_data, "f"), __classPrivateFieldGet(this, _Mutex_controller, "f"));
}
[(_Mutex_data = new WeakMap(), _Mutex_lockState = new WeakMap(), _Mutex_controller = new WeakMap(), _Mutex_instances = new WeakSet(), _Mutex_tryLock = function _Mutex_tryLock() {
return (Atomics.compareExchange(__classPrivateFieldGet(this, _Mutex_lockState, "f"), IDX_LOCK_STATE, UNLOCKED, LOCKED) ===
UNLOCKED);
}, _Mutex_unlock = function _Mutex_unlock() {
if (Atomics.compareExchange(__classPrivateFieldGet(this, _Mutex_lockState, "f"), IDX_LOCK_STATE, LOCKED, UNLOCKED) !==
LOCKED) {
throw new Error("Mutex was not locked or locked by another thread");
}
Atomics.notify(__classPrivateFieldGet(this, _Mutex_lockState, "f"), IDX_LOCK_STATE, 1);
}, _Mutex_performBlockingLock = function _Mutex_performBlockingLock() {
while (true) {
if (__classPrivateFieldGet(this, _Mutex_instances, "m", _Mutex_tryLock).call(this))
return;
Atomics.wait(__classPrivateFieldGet(this, _Mutex_lockState, "f"), IDX_LOCK_STATE, LOCKED);
}
}, _Mutex_performAsyncLock =
/**
* Shared logic for async lock.
* Used by both public lock() and the Controller (for Condvar)
*/
async function _Mutex_performAsyncLock() {
while (true) {
if (__classPrivateFieldGet(this, _Mutex_instances, "m", _Mutex_tryLock).call(this))
return;
const result = Atomics.waitAsync(__classPrivateFieldGet(this, _Mutex_lockState, "f"), IDX_LOCK_STATE, LOCKED);
if (result.async) {
await result.value;
}
}
}, toSerialized)]() {
let serializedData;
let transfer = [];
if (__classPrivateFieldGet(this, _Mutex_data, "f") !== undefined) {
[serializedData, transfer] = serialize(__classPrivateFieldGet(this, _Mutex_data, "f"));
}
return [
[__classPrivateFieldGet(this, _Mutex_lockState, "f").buffer, serializedData],
transfer,
];
}
static [toDeserialized](obj) {
const data = obj[1] !== undefined ? deserialize(obj[1]) : undefined;
return new _a(data, obj[0]);
}
}
_a = Mutex;
(() => {
register(0, _a);
})();