// Detach from the process being debugged, optionally killing it. func (dbp *Process) Detach(kill bool) (err error) { if dbp.Running() { if err = dbp.Halt(); err != nil { return } } if !kill { // Clean up any breakpoints we've set. for _, bp := range dbp.Breakpoints { if bp != nil { _, err := dbp.ClearBreakpoint(bp.Addr) if err != nil { return err } } } } dbp.execPtraceFunc(func() { err = PtraceDetach(dbp.Pid, 0) if err != nil { return } if kill { err = sys.Kill(dbp.Pid, sys.SIGINT) } }) return }
func (d *Debugger) Restart() error { if !d.process.Exited() { if d.process.Running() { d.process.Halt() } // Ensure the process is in a PTRACE_STOP. if err := sys.Kill(d.ProcessPid(), sys.SIGSTOP); err != nil { return err } if err := d.Detach(true); err != nil { return err } } p, err := proc.Launch(d.config.ProcessArgs) if err != nil { return fmt.Errorf("could not launch process: %s", err) } for addr, bp := range d.process.Breakpoints { if bp.Temp { continue } if _, err := p.SetBreakpoint(addr); err != nil { return err } } d.process = p return nil }
func (dbp *Process) Kill() (err error) { if !stopped(dbp.Pid) { return errors.New("process must be stopped in order to kill it") } err = sys.Kill(dbp.Pid, sys.SIGKILL) if err != nil { return errors.New("could not deliver signal " + err.Error()) } _, _, err = wait(-1, dbp.Pid, 0) if err != nil { return } dbp.exited = true return }
func (dbp *Process) Kill() (err error) { if dbp.exited { return nil } if !dbp.Threads[dbp.Pid].Stopped() { return errors.New("process must be stopped in order to kill it") } if err = sys.Kill(-dbp.Pid, sys.SIGKILL); err != nil { return errors.New("could not deliver signal " + err.Error()) } if _, _, err = wait(dbp.Pid, dbp.Pid, 0); err != nil { return } dbp.exited = true return }
func (dbp *Process) Kill() (err error) { err = sys.Kill(dbp.Pid, sys.SIGKILL) if err != nil { return errors.New("could not deliver signal: " + err.Error()) } for port := range dbp.Threads { if C.thread_resume(C.thread_act_t(port)) != C.KERN_SUCCESS { return errors.New("could not resume task") } } for { port := C.mach_port_wait(dbp.os.portSet) if port == dbp.os.notificationPort { break } } dbp.exited = true return }
func (d *Debugger) Restart() error { if !d.process.Exited() { if d.process.Running() { d.process.Halt() } // Ensure the process is in a PTRACE_STOP. if err := sys.Kill(d.ProcessPid(), sys.SIGSTOP); err != nil { return err } if err := d.Detach(true); err != nil { return err } } p, err := proc.Launch(d.config.ProcessArgs) if err != nil { return fmt.Errorf("could not launch process: %s", err) } d.process = p return nil }
func (dbp *Process) requestManualStop() (err error) { return sys.Kill(dbp.Pid, sys.SIGTRAP) }
func killProcess(pid int) error { return sys.Kill(pid, sys.SIGINT) }
func TerminateProcess(pid int) { unix.Kill(pid, unix.SIGTERM) }
func SuspendProcess(pid int) { unix.Kill(pid, unix.SIGSTOP) }
func ContinueProcess(pid int) { unix.Kill(pid, unix.SIGCONT) }
func stopProcess(pid int) error { return sys.Kill(pid, sys.SIGSTOP) }
func (p *process) handleSigkilledShim(rst int, rerr error) (int, error) { if p.cmd == nil || p.cmd.Process == nil { e := unix.Kill(p.pid, 0) if e == syscall.ESRCH { return rst, rerr } // If it's not the same process, just mark it stopped and set // the status to 255 if same, err := p.isSameProcess(); !same { logrus.Warnf("containerd: %s:%s (pid %d) is not the same process anymore (%v)", p.container.id, p.id, p.pid, err) p.stateLock.Lock() p.state = Stopped p.stateLock.Unlock() // Create the file so we get the exit event generated once monitor kicks in // without going to this all process again rerr = ioutil.WriteFile(filepath.Join(p.root, ExitStatusFile), []byte("255"), 0644) return 255, nil } ppid, err := readProcStatField(p.pid, 4) if err != nil { return rst, fmt.Errorf("could not check process ppid: %v (%v)", err, rerr) } if ppid == "1" { logrus.Warnf("containerd: %s:%s shim died, killing associated process", p.container.id, p.id) unix.Kill(p.pid, syscall.SIGKILL) // wait for the process to die for { e := unix.Kill(p.pid, 0) if e == syscall.ESRCH { break } time.Sleep(10 * time.Millisecond) } rst = 128 + int(syscall.SIGKILL) // Create the file so we get the exit event generated once monitor kicks in // without going to this all process again rerr = ioutil.WriteFile(filepath.Join(p.root, ExitStatusFile), []byte(fmt.Sprintf("%d", rst)), 0644) } return rst, rerr } // Possible that the shim was SIGKILLED e := unix.Kill(p.cmd.Process.Pid, 0) if e != syscall.ESRCH { return rst, rerr } // Ensure we got the shim ProcessState <-p.cmdDoneCh shimStatus := p.cmd.ProcessState.Sys().(syscall.WaitStatus) if shimStatus.Signaled() && shimStatus.Signal() == syscall.SIGKILL { logrus.Debugf("containerd: ExitStatus(container: %s, process: %s): shim was SIGKILL'ed reaping its child with pid %d", p.container.id, p.id, p.pid) var ( status unix.WaitStatus rusage unix.Rusage wpid int ) // Some processes change their PR_SET_PDEATHSIG, so force kill them unix.Kill(p.pid, syscall.SIGKILL) for wpid == 0 { wpid, e = unix.Wait4(p.pid, &status, unix.WNOHANG, &rusage) if e != nil { logrus.Debugf("containerd: ExitStatus(container: %s, process: %s): Wait4(%d): %v", p.container.id, p.id, p.pid, rerr) return rst, rerr } } if wpid == p.pid { rerr = nil rst = 128 + int(shimStatus.Signal()) } else { logrus.Errorf("containerd: ExitStatus(container: %s, process: %s): unexpected returned pid from wait4 %v (expected %v)", p.container.id, p.id, wpid, p.pid) } p.stateLock.Lock() p.state = Stopped p.stateLock.Unlock() } return rst, rerr }
func TestReap_ReapChildren(t *testing.T) { pids := make(PidCh, 1) errors := make(ErrorCh, 1) done := make(chan struct{}, 1) var reapLock sync.RWMutex didExit := make(chan struct{}, 1) go func() { ReapChildren(pids, errors, done, &reapLock) didExit <- struct{}{} }() killAndCheck := func() { cmd := exec.Command("sleep", "5") if err := cmd.Start(); err != nil { t.Fatalf("err: %v", err) } childPid := cmd.Process.Pid if err := cmd.Process.Kill(); err != nil { t.Fatalf("err: %v", err) } select { case pid := <-pids: if pid != childPid { t.Fatalf("unexpected pid: %d != %d", pid, childPid) } case err := <-errors: t.Fatalf("err: %v", err) case <-time.After(1 * time.Second): t.Fatalf("should have reaped %d", childPid) } } // Kill a child process and make sure it gets detected. killAndCheck() // Fire off a subprocess. cmd := exec.Command("sleep", "5") if err := cmd.Start(); err != nil { t.Fatalf("err: %v", err) } // Send a spurious SIGCHLD. if err := unix.Kill(os.Getpid(), unix.SIGCHLD); err != nil { t.Fatalf("err: %v", err) } // Make sure the reaper didn't report anything. select { case pid := <-pids: t.Fatalf("unexpected pid: %d", pid) case err := <-errors: t.Fatalf("err: %v", err) case <-time.After(1 * time.Second): // Good - nothing was sent to the channels. } // Take the reap lock. reapLock.RLock() // Now kill the child subprocess. childPid := cmd.Process.Pid if err := cmd.Process.Kill(); err != nil { t.Fatalf("err: %v", err) } // Make sure the reaper didn't report anything. select { case pid := <-pids: t.Fatalf("unexpected pid: %d", pid) case err := <-errors: t.Fatalf("err: %v", err) case <-time.After(1 * time.Second): // Good - nothing was sent to the channels. } // Give up the reap lock. reapLock.RUnlock() // Make sure the reaper sees it. select { case pid := <-pids: if pid != childPid { t.Fatalf("unexpected pid: %d != %d", pid, childPid) } case err := <-errors: t.Fatalf("err: %v", err) case <-time.After(1 * time.Second): t.Fatalf("should have reaped %d", childPid) } // Run a few more cycles to make sure things work. killAndCheck() killAndCheck() killAndCheck() // Shut it down. close(done) select { case <-didExit: // Good - the goroutine shut down. case <-time.After(1 * time.Second): t.Fatalf("should have shut down") } }