diff --git a/Go-latest.vsix b/Go-latest.vsix index 450b5c439..442ca6578 100644 Binary files a/Go-latest.vsix and b/Go-latest.vsix differ diff --git a/package.json b/package.json index 5c7d7b73a..23f5d3fee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Go", - "version": "0.6.86-beta.3", + "version": "0.6.86-beta.4", "publisher": "ms-vscode", "description": "Rich Go language support for Visual Studio Code", "author": { diff --git a/src/debugAdapter/goDebug.ts b/src/debugAdapter/goDebug.ts index 055fd660f..55b7c0baa 100644 --- a/src/debugAdapter/goDebug.ts +++ b/src/debugAdapter/goDebug.ts @@ -460,26 +460,39 @@ class Delve { close(): Thenable { verbose('HaltRequest'); - return this.callPromise('Command', [{ name: 'halt' }]).then(out => { - verbose('HaltResponse'); - if (!this.debugProcess) { - verbose('RestartRequest'); - return this.callPromise('Restart', this.isApiV1 ? [] : [{ position: '', resetArgs: false, newArgs: [] }]).then(null, err => { - verbose('RestartResponse'); - if (err) return logError('Failed to restart'); - }); - } - }, err => { - verbose('HaltResponse'); - if (!this.debugProcess && err) { - return logError('Failed to halt - ' + err.toString()); + + const haltPromise = new Promise((resolve, reject) => { + if (this.debugProcess) { + setTimeout(() => { + verbose('Killing debug process manually as we didnt hear back from delve in time'); + killTree(this.debugProcess.pid); + reject(); + }, 1000); } - }).then(() => { + + this.callPromise('Command', [{ name: 'halt' }]).then(() => { + verbose('HaltResponse'); + if (!this.debugProcess) { + verbose('RestartRequest'); + return this.callPromise('Restart', this.isApiV1 ? [] : [{ position: '', resetArgs: false, newArgs: [] }]).then(null, err => { + verbose('RestartResponse'); + if (err) return logError('Failed to restart'); + }); + } + }, err => { + verbose('HaltResponse'); + if (!this.debugProcess && err) { + return logError('Failed to halt - ' + err.toString()); + } + }).then(() => resolve(), reject); + }); + + return haltPromise.then(() => { if (this.debugProcess) { verbose('DetachRequest'); return this.callPromise('Detach', [this.isApiV1 ? true : { Kill: true }]).then(() => verbose('DetachResponse')); } - }); + }, null); } } @@ -1034,4 +1047,24 @@ function random(low: number, high: number): number { return Math.floor(Math.random() * (high - low) + low); } +function killTree(processId: number): void { + if (process.platform === 'win32') { + const TASK_KILL = 'C:\\Windows\\System32\\taskkill.exe'; + + // when killing a process in Windows its child processes are *not* killed but become root processes. + // Therefore we use TASKKILL.EXE + try { + execSync(`${TASK_KILL} /F /T /PID ${processId}`); + } catch (err) { + } + } else { + // on linux and OS X we kill all direct and indirect child processes as well + try { + const cmd = path.join(__dirname, '../../../scripts/terminateProcess.sh'); + spawnSync(cmd, [processId.toString()]); + } catch (err) { + } + } +} + DebugSession.run(GoDebugSession);