func runprog(argv []string) (filesize int64, mem int64, err error) { var attr os.ProcAttr var stat *os.ProcessState var proc *os.Process exepath, err := exec.LookPath(argv[0]) if err != nil { err = errors.New("can't find exe file.") return } proc, err = os.StartProcess(exepath, argv, &attr) if err != nil { return } fi, err := os.Stat(exepath) if err != nil { return } filesize = fi.Size() stat, err = proc.Wait() mem = int64(stat.SysUsage().(*syscall.Rusage).Maxrss) return }
// Wait calls Wait on the underlying exec.Cmd's Process and, if the // operating system supports it, returns the exit status. // // If an error occurs when waiting for the underlying process, the exit // status will be -2, and the error will be returned. If the operating // system does not support determining the exit status, but the program // exited successfully, the exit status will be 0. If the operating // system does not support determining the exit status and the program // exited unsuccessfully, the exit status will be -1. func (p *Proc) Wait() (exitStatus int, err error) { var ps *os.ProcessState ps, err = p.Cmd.Process.Wait() if err != nil { return -2, err } ws, ok := ps.Sys().(syscall.WaitStatus) if ok { return ws.ExitStatus(), nil } if ps.Success() { return 0, nil } return -1, nil }
// Stop the worker process func (w *Worker) Stop(replyChan chan<- CommandReply) { //err := syscall.Kill(worker.Pid, syscall.SIGTERM) proc, err := os.FindProcess(w.Pid) if nil != err { w.Logger.Printf("worker.Stop(): Cannot find worker process %d: %s\n", w.Pid, err) //w.exitChannel <- w.dtoppedCommand(err, state, stalled) replyChan <- CommandReply{Reply: fmt.Sprintf("[%s] worker process %d already stopped", w.Taskname, w.Pid)} return } // attempt stopping the worker with a SIGTERM first err = proc.Signal(syscall.SIGTERM) if err != nil { if err.Error() == "os: process already finished" { w.Logger.Println("worker.Stop() SIGTERM sent to already dead process") } else { w.Logger.Printf("worker.Stop(): Error sending SIGTERM to worker process %d: %s\n", w.Pid, err) } } var msg string var cmd Command var state *os.ProcessState gracePeriod := time.Duration(w.GracePeriod) * time.Millisecond // wait until the process returns gracefully from the SIGTERM, or times out + is killed after a grace period select { case <-time.After(gracePeriod): w.Logger.Printf("Grace Period (%s) expired, killing worker process %d", gracePeriod, w.Pid) err = proc.Kill() msg = fmt.Sprintf("Worker process %d was still around after %s, killed.", w.Pid, gracePeriod) if nil != err { msg = fmt.Sprintf("worker.Stop(): Failed to kill process %d - %s", w.Pid, err.Error()) } cmd = <-w.exitChannel // coming from waitOnProcess() cmd.Params["killed"] = true case cmd = <-w.exitChannel: // wait for the original waitpid() syscall in waitOnProcess() to return cmd.Params["killed"] = false err = nil msg = fmt.Sprintf("Worker process %d terminated gracefully", w.Pid) if state2, ok := cmd.Params["state"]; ok { state, ok = state2.(*os.ProcessState) } if err2, ok := cmd.Params["error"]; ok { if err, ok = err2.(error); ok { msg = fmt.Sprintf("Worker process %d terminated with error: (%T) %#v (%s)", w.Pid, err, err, state.String()) } } } cmd.Params["stalled"] = w.HasStalled() //w.Logger.Println(msg) replyChan <- CommandReply{Reply: msg, Error: err} w.TaskFeedbackChannel <- cmd }
func getExitCode(state *os.ProcessState) int { return state.Sys().(syscall.WaitStatus).ExitStatus() }
func exitStatus(p *os.ProcessState) int { ws := p.Sys().(syscall.WaitStatus) return ws.ExitStatus() }
func GetErrorLevel(processState *os.ProcessState) (int, bool) { if processState.Success() { return 0, true } else if t, ok := processState.Sys().(syscall.WaitStatus); ok { return t.ExitStatus(), true } else { return 255, false } }