From dca1dad52cf298cceea9e328eff5f561e4e0b802 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Fri, 20 Dec 2024 16:36:00 +1100 Subject: [PATCH] Interrupt child procs when interrupting kernel (#16319) --- .../raw/launcher/kernelProcess.node.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/kernels/raw/launcher/kernelProcess.node.ts b/src/kernels/raw/launcher/kernelProcess.node.ts index e2571f88a09..ea38f1329c9 100644 --- a/src/kernels/raw/launcher/kernelProcess.node.ts +++ b/src/kernels/raw/launcher/kernelProcess.node.ts @@ -152,6 +152,7 @@ export class KernelProcess extends ObservableDisposable implements IKernelProces ) { logger.info('Interrupting kernel via SIGINT'); if (this._process.pid) { + await this.interruptChildProcesses(this._process.pid); kill(this._process.pid, 'SIGINT'); } } else if ( @@ -407,6 +408,33 @@ export class KernelProcess extends ObservableDisposable implements IKernelProces } } + private async interruptChildProcesses(pid: number) { + // Do not remove this code, in in unit tests we end up running this, + // then we run into the danger of kill all of the processes on the machine. + // because calling `pidtree` without a pid will return all pids and hence everything ends up getting killed. + if (!ProcessService.isAlive(pid)) { + return; + } + try { + if (this.platform.isWindows) { + return; + } else { + await new Promise((resolve) => { + pidtree(pid, (ex: unknown, pids: number[]) => { + if (ex) { + logger.warn(`Failed to interrupt children for ${pid}`, ex); + } else { + pids.forEach((procId) => kill(procId, 'SIGINT')); + } + resolve(); + }); + }); + } + } catch (ex) { + logger.warn(`Failed to interrupt children for ${pid}`, ex); + } + } + private sendToOutput(data: string) { if (this.outputChannel) { this.outputChannel.append(data);