Skip to content

Commit

Permalink
fix Atomics locks
Browse files Browse the repository at this point in the history
  • Loading branch information
JakobJingleheimer committed Sep 19, 2022
1 parent a805c67 commit 2265b79
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 8 deletions.
8 changes: 5 additions & 3 deletions lib/internal/modules/esm/public_loader_proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const commsChannel = new SharedArrayBuffer(2048);
* The lock/unlock segment of the shared memory. Atomics require this to be a Int32Array. This
* segment is used to tell the main to sleep when the worker is worker, and vice verse (for the
* worker to sleep whilst the main is working).
* 0 → main sleeps
* 1 → worker sleeps
*/
const lock = new Int32Array(commsChannel, 0, 4);
/**
Expand All @@ -24,15 +26,15 @@ const worker = new Worker('./worker.js', {
});
worker.unref(); // ! Allows the process to eventually exit when worker is in its final sleep.

Atomics.wait(lock, 0, 1); // ! Block this module until the worker is ready.
Atomics.wait(lock, 0, 0); // ! Block this module until the worker is ready.

function makeRequest(type, data) {
requestResponseData.fill(0); // Erase any previous request/response (it's already been handled)
Atomics.store(lock, 0, 1); // Send request to worker
const request = serialize({ data, type });
requestResponseData.set(request);
Atomics.store(lock, 0, 0); // Send request to worker
Atomics.notify(lock, 0); // Notify worker of new request
Atomics.wait(lock, 0, 1); // Sleep until worker responds
Atomics.wait(lock, 0, 0); // Sleep until worker responds
return deserialize(requestResponseData);
}

Expand Down
12 changes: 7 additions & 5 deletions lib/internal/modules/esm/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ const { workerData } = require('internal/worker_threads');
const { deserialize, serialize } = require('v8');

const { commsChannel } = workerData;
// lock = 0 → main sleeps
// lock = 1 → worker sleeps
const lock = new Int32Array(commsChannel, 0, 4); // Required by Atomics
const requestResponseData = new Uint8Array(commsChannel, 4, 2044); // for TextEncoder/Decoder

const publicESMLoader = new ESMLoader();

Atomics.store(lock, 0, 0); // Send 'ready' signal to main
Atomics.notify(lock, 0); // Notify main of signal

const types = {
'addCustomLoaders': publicESMLoader.addCustomLoaders,
'cjsCache.delete': publicESMLoader.cjsCache.delete,
Expand All @@ -21,13 +20,16 @@ const types = {
'resolve': publicESMLoader.resolve,
};

Atomics.store(lock, 0, 1); // Send 'ready' signal to main
Atomics.notify(lock, 0); // Notify main of signal

while (true) { // event loop
Atomics.wait(lock, 0, 0); // This pauses the while loop
Atomics.wait(lock, 0, 1); // This pauses the while loop
// Worker is now active and main is sleeping
const { data, type } = deserialize(requestResponseData);
const response = await types[type](data);
requestResponseData.fill(0);
Atomics.store(lock, 0, 0); // Send response to main
requestResponseData.set(serialize(response));
Atomics.store(lock, 0, 1); // Send response to main
Atomics.notify(lock, 0); // Notify main of new response
};

0 comments on commit 2265b79

Please sign in to comment.