72 lines
2.6 KiB
JavaScript
72 lines
2.6 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.SyncMessenger = void 0;
|
|
/**
|
|
* @param condition Condition to wait for, when true, the function returns.
|
|
* @param ms Maximum time to wait in milliseconds.
|
|
*/
|
|
const sleepUntil = (condition, ms = 100) => {
|
|
const start = Date.now();
|
|
while (!condition()) {
|
|
const now = Date.now();
|
|
if (now - start > ms)
|
|
throw new Error('Timeout');
|
|
}
|
|
};
|
|
/**
|
|
* `SyncMessenger` allows to execute asynchronous code synchronously. The
|
|
* asynchronous code is executed in a Worker thread, while the main thread is
|
|
* blocked until the asynchronous code is finished.
|
|
*
|
|
* First four 4-byte words is the header, where the first word is used for Atomics
|
|
* notifications. The second word is used for spin-locking the main thread until
|
|
* the asynchronous code is finished. The third word is used to specify payload
|
|
* length. The fourth word is currently unused.
|
|
*
|
|
* The maximum payload size is the size of the SharedArrayBuffer minus the
|
|
* header size.
|
|
*/
|
|
class SyncMessenger {
|
|
constructor(sab) {
|
|
this.sab = sab;
|
|
this.int32 = new Int32Array(sab);
|
|
this.uint8 = new Uint8Array(sab);
|
|
this.headerSize = 4 * 4;
|
|
this.dataSize = sab.byteLength - this.headerSize;
|
|
}
|
|
callSync(data) {
|
|
const requestLength = data.length;
|
|
const headerSize = this.headerSize;
|
|
const int32 = this.int32;
|
|
int32[1] = 0;
|
|
int32[2] = requestLength;
|
|
this.uint8.set(data, headerSize);
|
|
Atomics.notify(int32, 0);
|
|
sleepUntil(() => int32[1] === 1);
|
|
const responseLength = int32[2];
|
|
const response = this.uint8.slice(headerSize, headerSize + responseLength);
|
|
return response;
|
|
}
|
|
serveAsync(callback) {
|
|
const headerSize = this.headerSize;
|
|
(async () => {
|
|
try {
|
|
const int32 = this.int32;
|
|
const res = Atomics.wait(int32, 0, 0);
|
|
if (res !== 'ok')
|
|
throw new Error(`Unexpected Atomics.wait result: ${res}`);
|
|
const requestLength = this.int32[2];
|
|
const request = this.uint8.slice(headerSize, headerSize + requestLength);
|
|
const response = await callback(request);
|
|
const responseLength = response.length;
|
|
int32[2] = responseLength;
|
|
this.uint8.set(response, headerSize);
|
|
int32[1] = 1;
|
|
}
|
|
catch (_a) { }
|
|
this.serveAsync(callback);
|
|
})().catch(() => { });
|
|
}
|
|
}
|
|
exports.SyncMessenger = SyncMessenger;
|
|
//# sourceMappingURL=SyncMessenger.js.map
|