| 61 | } |
| 62 | |
| 63 | func (r *runner) Kill() error { |
| 64 | if r.command != nil && r.command.Process != nil { |
| 65 | done := make(chan error) |
| 66 | go func() { |
| 67 | r.command.Wait() |
| 68 | close(done) |
| 69 | }() |
| 70 | |
| 71 | //Trying a "soft" kill first |
| 72 | if runtime.GOOS == "windows" { |
| 73 | if err := r.command.Process.Kill(); err != nil { |
| 74 | return err |
| 75 | } |
| 76 | } else if err := r.command.Process.Signal(os.Interrupt); err != nil { |
| 77 | return err |
| 78 | } |
| 79 | |
| 80 | //Wait for our process to die before we return or hard kill after 3 sec |
| 81 | select { |
| 82 | case <-time.After(3 * time.Second): |
| 83 | if err := r.command.Process.Kill(); err != nil { |
| 84 | log.Println("failed to kill: ", err) |
| 85 | } |
| 86 | case <-done: |
| 87 | } |
| 88 | r.command = nil |
| 89 | } |
| 90 | |
| 91 | return nil |
| 92 | } |
| 93 | |
| 94 | func (r *runner) Exited() bool { |
| 95 | return r.command != nil && r.command.ProcessState != nil && r.command.ProcessState.Exited() |