From 5ecbe5845cc544440300b2af3345194a459deaeb Mon Sep 17 00:00:00 2001 From: tom-shan Date: Tue, 28 May 2019 18:41:33 +0800 Subject: [PATCH] fix leaking java debug process When start debugging using vscode java-debug extension, the debug process will remain in OS process list and never be killed by theia process if the page is reloaded. When terminate plugin server, kill all child processes of plugin-host process. Signed-off-by: tom-shan --- .../src/hosted/node/hosted-plugin-process.ts | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/plugin-ext/src/hosted/node/hosted-plugin-process.ts b/packages/plugin-ext/src/hosted/node/hosted-plugin-process.ts index e8cda321abfe3..84646da0cc7c0 100644 --- a/packages/plugin-ext/src/hosted/node/hosted-plugin-process.ts +++ b/packages/plugin-ext/src/hosted/node/hosted-plugin-process.ts @@ -17,7 +17,7 @@ import * as path from 'path'; import * as cp from 'child_process'; import { injectable, inject, named } from 'inversify'; -import { ILogger, ConnectionErrorHandler, ContributionProvider } from '@theia/core/lib/common'; +import { ILogger, ConnectionErrorHandler, ContributionProvider, isWindows } from '@theia/core/lib/common'; import { Emitter } from '@theia/core/lib/common/event'; import { createIpcEnv } from '@theia/core/lib/node/messaging/ipc-protocol'; import { HostedPluginClient, ServerPluginRunner, PluginMetadata, PluginHostEnvironmentVariable } from '../../common/plugin-protocol'; @@ -25,6 +25,7 @@ import { RPCProtocolImpl } from '../../api/rpc-protocol'; import { MAIN_RPC_CONTEXT } from '../../api/plugin-api'; import { HostedPluginCliContribution } from './hosted-plugin-cli-contribution'; import {HostedPluginProcessesCache} from './hosted-plugin-processes-cache'; +const psTree = require('ps-tree'); export interface IPCConnectionOptions { readonly serverName: string; @@ -122,11 +123,26 @@ export class HostedPluginProcess implements ServerPluginRunner { const hostedPluginManager = rpc.getProxy(MAIN_RPC_CONTEXT.HOSTED_PLUGIN_MANAGER_EXT); hostedPluginManager.$stopPlugin('').then(() => { emitter.dispose(); - cp.kill(); + this.killProcessTree(cp); }); } + private killProcessTree(parentProcess: cp.ChildProcess): void { + parentProcess.disconnect(); + const parentPid = parentProcess.pid; + if (isWindows) { + cp.spawn('taskkill', ['/F', '/T', '/PID', parentPid.toString()]); + } else { + // tslint:disable-next-line:no-any + psTree(parentPid, (err: Error, children: Array) => { + parentProcess.kill(); + // tslint:disable-next-line:no-any + cp.spawn('kill', children.map((p: any) => p.PID)); + }); + } + } + public runPluginServer(): void { if (this.childProcess) { this.terminatePluginServer();