diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2022-07-22 18:07:20 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-22 18:07:20 +0200 |
commit | 72199303d899b8ddf2ff46ed11bd513ed9cc47e2 (patch) | |
tree | dc44930e29a070de4d0cf535d2958031c27345d1 | |
parent | 4db650ddd57b85475d71c0b9fc84d37becab9d6a (diff) |
fix: Child.unref() unrefs stdio streams properly (#15275)
-rw-r--r-- | cli/tests/unit/spawn_test.ts | 29 | ||||
-rw-r--r-- | runtime/js/40_spawn.js | 5 |
2 files changed, 32 insertions, 2 deletions
diff --git a/cli/tests/unit/spawn_test.ts b/cli/tests/unit/spawn_test.ts index 42df23b1f..51664e3d1 100644 --- a/cli/tests/unit/spawn_test.ts +++ b/cli/tests/unit/spawn_test.ts @@ -723,8 +723,29 @@ Deno.test( const program = ` const child = await Deno.spawnChild(Deno.execPath(), { cwd: Deno.args[0], + stdout: "piped", args: ["run", "-A", "--unstable", Deno.args[1]], }); +const readable = child.stdout.pipeThrough(new TextDecoderStream()); +const reader = readable.getReader(); +// set up an interval that will end after reading a few messages from stdout, +// to verify that stdio streams are properly unrefed +let count = 0; +let interval; +interval = setInterval(async () => { + count += 1; + if (count > 10) { + clearInterval(interval); + console.log("cleared interval"); + } + const res = await reader.read(); + if (res.done) { + throw new Error("stream shouldn't be done"); + } + if (res.value.trim() != "hello from interval") { + throw new Error("invalid message received"); + } +}, 120); console.log("spawned pid", child.pid); child.unref(); `; @@ -740,15 +761,19 @@ setInterval(() => { // In this subprocess we are spawning another subprocess which has // an infite interval set. Following call would never resolve unless // child process gets unrefed. - const { success, stdout } = await Deno.spawn(Deno.execPath(), { + const { success, stdout, stderr } = await Deno.spawn(Deno.execPath(), { cwd, args: ["run", "-A", "--unstable", programFile, cwd, childProgramFile], }); assert(success); const stdoutText = new TextDecoder().decode(stdout); - const pidStr = stdoutText.split(" ").at(-1); + const stderrText = new TextDecoder().decode(stderr); + assert(stderrText.length == 0); + const [line1, line2] = stdoutText.split("\n"); + const pidStr = line1.split(" ").at(-1); assert(pidStr); + assertEquals(line2, "cleared interval"); const pid = Number.parseInt(pidStr, 10); await Deno.remove(cwd, { recursive: true }); // Child process should have been killed when parent process exits. diff --git a/runtime/js/40_spawn.js b/runtime/js/40_spawn.js index a00b8cfda..87db84f4b 100644 --- a/runtime/js/40_spawn.js +++ b/runtime/js/40_spawn.js @@ -75,6 +75,7 @@ class Child { #rid; #waitPromiseId; + #unrefed = false; #pid; get pid() { @@ -132,6 +133,7 @@ this.#stdoutRid = stdoutRid; this.#stdout = readableStreamForRid(stdoutRid, (promise) => { this.#stdoutPromiseId = promise[promiseIdSymbol]; + if (this.#unrefed) core.unrefOp(this.#stdoutPromiseId); }); } @@ -139,6 +141,7 @@ this.#stderrRid = stderrRid; this.#stderr = readableStreamForRid(stderrRid, (promise) => { this.#stderrPromiseId = promise[promiseIdSymbol]; + if (this.#unrefed) core.unrefOp(this.#stderrPromiseId); }); } @@ -204,12 +207,14 @@ } ref() { + this.#unrefed = false; core.refOp(this.#waitPromiseId); if (this.#stdoutPromiseId) core.refOp(this.#stdoutPromiseId); if (this.#stderrPromiseId) core.refOp(this.#stderrPromiseId); } unref() { + this.#unrefed = true; core.unrefOp(this.#waitPromiseId); if (this.#stdoutPromiseId) core.unrefOp(this.#stdoutPromiseId); if (this.#stderrPromiseId) core.unrefOp(this.#stderrPromiseId); |