(force: boolean)
| 407 | } |
| 408 | |
| 409 | protected async terminate(force: boolean): Promise<void> { |
| 410 | const signal = force ? "SIGKILL" : "SIGINT"; |
| 411 | const request = force ? "DISC" : "TERM"; |
| 412 | this.log(`${request}: Requested to terminate with ${signal}...`); |
| 413 | if (this.childProcess && !this.processExited) { |
| 414 | this.log(`${request}: Terminating processes...`); |
| 415 | for (const pid of this.additionalPidsToTerminate) { |
| 416 | if (pid === this.childProcess.pid) |
| 417 | continue; |
| 418 | try { |
| 419 | this.log(`${request}: Terminating related process ${pid} with ${signal}...`); |
| 420 | process.kill(pid, signal); |
| 421 | // Don't remove these PIDs from the list as we don't know that they actually quit yet. |
| 422 | } catch (e) { |
| 423 | // Sometimes this process will have already gone away (eg. the app finished/terminated) |
| 424 | // so logging here just results in lots of useless info. |
| 425 | } |
| 426 | } |
| 427 | if (!this.processExited) { |
| 428 | if (this.childProcess.pid) { |
| 429 | try { |
| 430 | this.log(`${request}: Terminating main process with ${signal}...`); |
| 431 | process.kill(this.childProcess.pid, signal); |
| 432 | } catch (e) { |
| 433 | // This tends to throw a lot because the shell process quit when we terminated the related |
| 434 | // VM process above, so just swallow the error. |
| 435 | } |
| 436 | } else { |
| 437 | this.log(`${request}: Process had no PID.`); |
| 438 | } |
| 439 | |
| 440 | // If we didn't quit, it might be because we're paused. |
| 441 | await this.tryRemoveAllBreakpointsAndResumeAllThreads(request); |
| 442 | } else { |
| 443 | this.log(`${request}: Main process had already quit.`); |
| 444 | } |
| 445 | // Don't do this - because the process might ignore our kill (eg. test framework lets the current |
| 446 | // test finish) so we may need to send again it we get another disconnectRequest. |
| 447 | // We also use !childProcess to mean we're attached. |
| 448 | // this.childProcess = undefined; |
| 449 | } else { |
| 450 | this.log(`${request}: Did not need to terminate processes`); |
| 451 | } |
| 452 | |
| 453 | this.log(`${request}: Removing all stored data...`); |
| 454 | this.threadManager.removeAllStoredData(); |
| 455 | |
| 456 | this.log(`${request}: Waiting for process to finish...`); |
| 457 | await this.processExit; |
| 458 | |
| 459 | this.log(`${request}: Disconnecting...`); |
| 460 | } |
| 461 | |
| 462 | // When shutting down, we may need to remove all breakpoints and resume all threads |
| 463 | // to avoid things like waiting for tests to exit that will never exit. We don't wait |
nothing calls this directly
no test coverage detected