diff options
-rw-r--r-- | cli/tests/integration/run_tests.rs | 5 | ||||
-rw-r--r-- | cli/tests/worker_close_race.js | 14 | ||||
-rw-r--r-- | cli/tests/worker_close_race.js.out | 0 | ||||
-rw-r--r-- | cli/tests/workers/close_race_worker.js | 6 | ||||
-rw-r--r-- | runtime/ops/worker_host.rs | 36 |
5 files changed, 42 insertions, 19 deletions
diff --git a/cli/tests/integration/run_tests.rs b/cli/tests/integration/run_tests.rs index 2e2b0400c..08e0c8306 100644 --- a/cli/tests/integration/run_tests.rs +++ b/cli/tests/integration/run_tests.rs @@ -1160,6 +1160,11 @@ itest!(worker_event_handler_test { output: "worker_event_handler_test.js.out", }); +itest!(worker_close_race { + args: "run --quiet --reload --allow-read worker_close_race.js", + output: "worker_close_race.js.out", +}); + #[test] fn no_validate_asm() { let output = util::deno_cmd() diff --git a/cli/tests/worker_close_race.js b/cli/tests/worker_close_race.js new file mode 100644 index 000000000..6d5bbe2c3 --- /dev/null +++ b/cli/tests/worker_close_race.js @@ -0,0 +1,14 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +// https://github.com/denoland/deno/issues/11416 +// Test for a race condition between a worker's `close()` and the main thread's +// `Worker.prototype.terminate()`. + +const worker = new Worker( + new URL("./workers/close_race_worker.js", import.meta.url), + { type: "module" }, +); + +worker.onmessage = () => { + worker.terminate(); +}; diff --git a/cli/tests/worker_close_race.js.out b/cli/tests/worker_close_race.js.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/cli/tests/worker_close_race.js.out diff --git a/cli/tests/workers/close_race_worker.js b/cli/tests/workers/close_race_worker.js new file mode 100644 index 000000000..f582a0d99 --- /dev/null +++ b/cli/tests/workers/close_race_worker.js @@ -0,0 +1,6 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +setTimeout(() => { + self.postMessage(""); + self.close(); +}, 500); diff --git a/runtime/ops/worker_host.rs b/runtime/ops/worker_host.rs index 162f9f4f7..2cd9a14ad 100644 --- a/runtime/ops/worker_host.rs +++ b/runtime/ops/worker_host.rs @@ -516,16 +516,16 @@ fn op_host_terminate_worker( id: WorkerId, _: (), ) -> Result<(), AnyError> { - let worker_thread = state - .borrow_mut::<WorkersTable>() - .remove(&id) - .expect("No worker handle found"); - worker_thread.worker_handle.terminate(); - worker_thread - .join_handle - .join() - .expect("Panic in worker thread") - .expect("Panic in worker event loop"); + if let Some(worker_thread) = state.borrow_mut::<WorkersTable>().remove(&id) { + worker_thread.worker_handle.terminate(); + worker_thread + .join_handle + .join() + .expect("Panic in worker thread") + .expect("Panic in worker event loop"); + } else { + debug!("tried to terminate non-existent worker {}", id); + } Ok(()) } @@ -602,14 +602,12 @@ fn op_host_post_message( id: WorkerId, data: JsMessageData, ) -> Result<(), AnyError> { - debug!("post message to worker {}", id); - let worker_handle = { - let worker_thread = state - .borrow::<WorkersTable>() - .get(&id) - .expect("No worker handle found"); - worker_thread.worker_handle.clone() - }; - worker_handle.port.send(state, data)?; + if let Some(worker_thread) = state.borrow::<WorkersTable>().get(&id) { + debug!("post message to worker {}", id); + let worker_handle = worker_thread.worker_handle.clone(); + worker_handle.port.send(state, data)?; + } else { + debug!("tried to post message to non-existent worker {}", id); + } Ok(()) } |