summaryrefslogtreecommitdiff
path: root/ext/node/polyfills/worker_threads.ts
AgeCommit message (Collapse)Author
2024-10-04fix(node): fix worker_threads issues blocking Angular support (#26024)Nathan Whitaker
Fixes #22995. Fixes #23000. There were a handful of bugs here causing the hang (each with a corresponding minimized test): - We were canceling recv futures when `receiveMessageOnPort` was called, but this caused the "receive loop" in the message port to exit. This was due to the fact that `CancelHandle`s are never reset (i.e., once you `cancel` a `CancelHandle`, it remains cancelled). That meant that after `receieveMessageOnPort` was called, the subsequent calls to `op_message_port_recv_message` would throw `Interrupted` exceptions, and we would exit the loop. The cancellation, however, isn't actually necessary. `op_message_port_recv_message` only borrows the underlying port for long enough to poll the receiver, so the borrow there could never overlap with `op_message_port_recv_message_sync`. - Calling `MessagePort.unref()` caused the "receive loop" in the message port to exit. This was because we were setting `messageEventListenerCount` to 0 on unref. Not only does that break the counter when multiple `MessagePort`s are present in the same thread, but we also exited the "receive loop" whenever the listener count was 0. I assume this was to prevent the recv promise from keeping the event loop open. Instead of this, I chose to just unref the recv promise as needed to control the event loop. - The last bug causing the hang (which was a doozy to debug) ended up being an unfortunate interaction between how we implement our messageport "receive loop" and a pattern found in `npm:piscina` (which angular uses). The gist of it is that piscina uses an atomic wait loop along with `receiveMessageOnPort` in its worker threads, and as the worker is getting started, the following incredibly convoluted series of events occurs: 1. Parent sends a MessagePort `p` to worker 2. Parent sends a message `m` to the port `p` 3. Parent notifies the worker with `Atomics.notify` that a new message is available 4. Worker receives message, adds "message" listener to port `p` 5. Adding the listener triggers `MessagePort.start()` on `p` 6. Receive loop in MessagePort.start receives the message `m`, but then hits an await point and yields (before dispatching the "message" event) 7. Worker continues execution, starts the atomic wait loop, and immediately receives the existing notification from the parent that a message is available 8. Worker attempts to receive the new message `m` with `receiveMessageOnPort`, but this returns `undefined` because the receive loop already took the message in 6 9. Atomic wait loop continues to next iteration, waiting for the next message with `Atomic.wait` 10. `Atomic.wait` blocks the worker thread, which prevents the receive loop from continuing and dispatching the "message" event for the received message 11. The parent waits for the worker to respond to the first message, and waits 12. The thread can't make any more progress, and the whole process hangs The fix I've chosen here (which I don't particularly love, but it works) is to just delay the `MessagePort.start` call until the end of the event loop turn, so that the atomic wait loop receives the message first. This prevents the hang. --- Those were the main issues causing the hang. There ended up being a few other small bugs as well, namely `exit` being emitted multiple times, and not patching up the message port when it's received by `receiveMessageOnPort`.
2024-09-06fix(runtime): use more null proto objects again (#25040)Kenta Moriuchi
proceed with #23921 This PR is a preparation for https://github.com/denoland/deno_lint/pull/1307 --------- Signed-off-by: Kenta Moriuchi <moriken@kimamass.com> Co-authored-by: Luca Casonato <hello@lcas.dev>
2024-08-28fix(ext/node): emit `online` event after worker thread is initialized (#25243)Nathan Whitaker
Fixes #23281. Part of #20613. We were emitting the `online` event in the constructor, so the caller could never receive it (since there was no time for them to add a listener). Instead, emit the event where it's intended – after the worker is initialized. --- After this parcel no longer freezes, but still will fail due to other bugs (which will be fixed in other PRs)
2024-08-20chore: enable no-console dlint rule (#25113)David Sherret
2024-07-25fix(node/worker_threads): support `port.once()` (#24725)Marvin Hagemeister
Support `MessagePort.once` in Node mode and enable relevant `worker_threads` test. Noticed that another Node test was passing as well, so I enabled that too.
2024-07-19fix(ext/node): do not expose `self` global in node (#24637)Yoshiya Hinosawa
closes #23727
2024-05-20fix(node): patch MessagePort in worker_thread message (#23871)Marvin Hagemeister
Our `MessagePort` to Node's `MessagePort` conversion logic was missing the case where a `MessagePort` is sent _inside_ the message. This broke `tinypool` which is used by `vitest` as it relies on some node specific methods on `MessagePort`. Fixes https://github.com/denoland/deno/issues/23854 , Fixes https://github.com/denoland/deno/pull/23871
2024-05-15fix(node): wrong `worker_threads.terminate()` return value (#23803)Marvin Hagemeister
<!-- Before submitting a PR, please read https://docs.deno.com/runtime/manual/references/contributing 1. Give the PR a descriptive title. Examples of good title: - fix(std/http): Fix race condition in server - docs(console): Update docstrings - feat(doc): Handle nested reexports Examples of bad title: - fix #7123 - update docs - fix bugs 2. Ensure there is a related issue and it is referenced in the PR text. 3. Ensure there are tests that cover the changes. 4. Ensure `cargo test` passes. 5. Ensure `./tools/format.js` passes without changing files. 6. Ensure `./tools/lint.js` passes. 7. Open as a draft PR if your work is still in progress. The CI won't run all steps, but you can add '[ci]' to a commit message to force it to. 8. If you would like to run the benchmarks on the CI, add the 'ci-bench' label. --> Fixes https://github.com/denoland/deno/issues/23801 --------- Signed-off-by: Marvin Hagemeister <marvinhagemeister50@gmail.com> Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
2024-04-30fix(ext/node): support multiple message listeners on MessagePort (#23600)Satya Rohith
Closes https://github.com/denoland/deno/issues/23561
2024-04-29fix(ext/node): add support for MessagePort.removeListener/off (#23598)Satya Rohith
Closes https://github.com/denoland/deno/issues/23564
2024-04-24fix(ext/node): worker_threads copies env object (#23536)Bartek Iwańczuk
Most common argument to `env` option for `worker_threads.Worker` will be `process.env`. In Deno `process.env` is a `Proxy` which can't be cloned using structured clone algorithm. So to be safe, I'm creating a copy of actual object before it's sent to the worker thread. Ref #23522
2024-04-20fix(ext/node): Support `env` option in worker_thread (#23462)Divy Srivastava
Fixes https://github.com/denoland/deno/issues/23455
2024-04-16fix(ext/node): panic on 'worker_threads.receiveMessageOnPort' (#23386)Bartek Iwańczuk
Closes https://github.com/denoland/deno/issues/23362 Previously we were panicking if there was a pending read on a port and `receiveMessageOnPort` was called. This is now fixed by cancelling the pending read, trying to read a message and resuming reading in a loop.
2024-04-09fix(ext/node): implement MessagePort.unref() (#23278)Satya Rohith
Closes https://github.com/denoland/deno/issues/23252 Closes https://github.com/denoland/deno/issues/23264
2024-04-03refactor(ext/node): remove worker_threads dependency on ext:runtime (#23206)Satya Rohith
2024-04-03fix(ext/node): patch MessagePort if provided as workerData (#23198)Satya Rohith
MessagePort if directly assigned to workerData property instead of embedding it in an object then it is not patched to a NodeMessagePort. This commit fixes the bug.
2024-04-02fix(ext/node): MessagePort works (#22999)Satya Rohith
Closes https://github.com/denoland/deno/issues/22951 Closes https://github.com/denoland/deno/issues/23001 Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com>
2024-03-20fix(ext/node): worker_threads ESM handling (#22841)mash-graz
Fixes #22840 Fixes #22964
2024-03-13fix(ext/node): make worker ids sequential (#22884)Satya Rohith
2024-03-13fix(ext/node): allow automatic worker_thread termination (#22647)Satya Rohith
Co-authored-by: Matt Mastracci <matthew@mastracci.com>
2024-03-11fix(ext/node): make worker setup synchronous (#22815)Bartek Iwańczuk
This commit fixes race condition in "node:worker_threads" module were the first message did a setup of "threadId", "workerData" and "environmentData". Now this data is passed explicitly during workers creation and is set up before any user code is executed. Closes https://github.com/denoland/deno/issues/22783 Closes https://github.com/denoland/deno/issues/22672 --------- Co-authored-by: Satya Rohith <me@satyarohith.com>
2024-03-11fix(ext/node): worker_threads.parentPort is updated on startup (#20794)Bartek Iwańczuk
This addresses https://github.com/denoland/deno/issues/20613#issuecomment-1739962483.
2024-03-11fix(ext/node) implement receiveMessageOnPort for node:worker_threads (#22766)mash-graz
Implementation of `receiveMessageOnPort` for `node:worker_threads` Fixes: #22702
2024-03-08refactor(ext/node): worker_threads.isMainThread setup (#22785)Bartek Iwańczuk
This commit changes how we figure out if we're running on main thread in `node:worker_threads` module. Instead of relying on quirky "magic variable" for a name to check if we're on main thread, we are now explicitly passing this information during bootstrapping of the runtime. As a side effect, `WorkerOptions.name` is more useful and matches what Node.js does more closely (though not fully). Towards https://github.com/denoland/deno/issues/22783
2024-03-08refactor(ext/node): use worker ops directly in worker_threads (#22794)Satya Rohith
2024-03-07feat(ext/node): ref/unref on workers (#22778)Matt Mastracci
Implements ref/unref on worker to fix part of #22629
2024-01-29refactor: Use virtul ops module (#22175)Bartek Iwańczuk
Follow up to #22157. This leaves us with 4 usages of `ensureFastOps()` in `deno` itself. There's also about 150 usages of `Deno.core.ops.<op_name>` left as well.
2024-01-10refactor: use `core.ensureFastOps()` (#21888)Kenta Moriuchi
2024-01-01chore: update copyright to 2024 (#21753)David Sherret
2023-07-02refactor: rename built-in node modules from ext:deno_node/ to node: (#19680)Bartek Iwańczuk
Closes https://github.com/denoland/deno/issues/19510
2023-06-27chore(ext/node): disable prefer-primordials on a per-file basis (#19553)Kenta Moriuchi
2023-06-26fix(ext/node): remove path.toFileUrl (#19536)Ryan Clements
2023-06-15fix(node): Worker constructor doesn't check type: module of package.json ↵Vedant Pandey
(#19480)
2023-05-23fix(ext/node): add basic node:worker_threads support (#19192)Yoshiya Hinosawa
This PR restores `node:worker_threads` implementation and test cases from [`std@0.175.0/node`](https://github.com/denoland/deno_std/blob/0.175.0/node/worker_threads.ts). --------- Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
2023-05-11fix(node): expose channels in worker_threads (#19086)Marvin Hagemeister
This PR ensures that node's `worker_threads` module exports `MessageChannel`, `MessagePort` and the `BroadcastChannel` API. Fixing these won't make `esbuild` work, but brings us one step closer 🎉 Fixes #19028 .
2023-03-08refactor: rename InternalModuleLoader to ExtModuleLoader, use ext: scheme ↵Bartek Iwańczuk
for snapshotted modules (#18041) This commit renames "deno_core::InternalModuleLoader" to "ExtModuleLoader" and changes the specifiers used by the modules loaded from this loader to "ext:". "internal:" scheme was really ambiguous and it's more characters than "ext:", which should result in slightly smaller snapshot size. Closes https://github.com/denoland/deno/issues/18020
2023-03-05refactor(core): include_js_files! 'dir' option doesn't change specifiers ↵Bartek Iwańczuk
(#18019) This commit changes "include_js_files!" macro from "deno_core" in a way that "dir" option doesn't cause specifiers to be rewritten to include it. Example: ``` include_js_files! { dir "js", "hello.js", } ``` The above definition required embedders to use: `import ... from "internal:<ext_name>/js/hello.js"`. But with this change, the "js" directory in which the files are stored is an implementation detail, which for embedders results in: `import ... from "internal:<ext_name>/hello.js"`. The directory the files are stored in, is an implementation detail and in some cases might result in a significant size difference for the snapshot. As an example, in "deno_node" extension, we store the source code in "polyfills" directory; which resulted in each specifier to look like "internal:deno_node/polyfills/<module_name>", but with this change it's "internal:deno_node/<module_name>". Given that "deno_node" has over 100 files, many of them having several import specifiers to the same extension, this change removes 10 characters from each import specifier.
2023-02-14feat(ext/node): embed std/node into the snapshot (#17724)Bartek Iwańczuk
This commit moves "deno_std/node" in "ext/node" crate. The code is transpiled and snapshotted during the build process. During the first pass a minimal amount of work was done to create the snapshot, a lot of code in "ext/node" depends on presence of "Deno" global. This code will be gradually fixed in the follow up PRs to migrate it to import relevant APIs from "internal:" modules. Currently the code from snapshot is not used in any way, and all Node/npm compatibility still uses code from "https://deno.land/std/node" (or from the location specified by "DENO_NODE_COMPAT_URL"). This will also be handled in a follow up PRs. --------- Co-authored-by: crowlkats <crowlkats@toaxl.com> Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com> Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>