summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/tests/integration/run_tests.rs5
-rw-r--r--cli/tests/worker_close_race.js14
-rw-r--r--cli/tests/worker_close_race.js.out0
-rw-r--r--cli/tests/workers/close_race_worker.js6
-rw-r--r--runtime/ops/worker_host.rs36
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(())
}