zhangmeng
2020-01-21 9d9cd1d3b93613071d1dffc1c82c4515d2a65af6
app/master/reaper.go
@@ -2,73 +2,18 @@
import (
   "analysis/logo"
   "context"
   "os"
   "os/exec"
   "os/signal"
   "syscall"
   "time"
)
type procInfo struct {
   cmd *exec.Cmd
   env string
// ExitInfo info
type ExitInfo struct {
   Pid      int
   ExitCode int
}
var (
   procMap = make(map[int]*procInfo)
)
func restartProc(ctxt context.Context, pid int) {
   info, ok := procMap[pid]
   if ok {
      err := info.cmd.Wait()
      if err != nil {
         logo.Errorln("pid : [", pid, "] quit error: ", err)
      } else {
         logo.Infoln("pid : [", pid, "] quit")
      }
      delete(procMap, pid)
      runProc(ctxt, info.cmd.Path, info.cmd.Args[1:], info.env)
   } else {
      logo.Errorln(pid, " doesn't exist")
   }
}
func quitProc(pid int) {
   info, ok := procMap[pid]
   if ok {
      delete(procMap, pid)
      syscall.Kill(pid, syscall.SIGINT)
      info.cmd.Wait()
   } else {
      logo.Errorln(pid, " doesn't exist")
   }
}
func runProc(ctxt context.Context, bin string, args []string, env string) (int, error) {
   cmd := exec.CommandContext(ctxt, bin, args...)
   rEnv := ""
   if len(env) != 0 {
      rEnv = "LD_LIBRARY_PATH=" + env
      logo.Infoln("Env String: ", rEnv)
      cmd.Env = os.Environ()
      cmd.Env = append(cmd.Env, rEnv)
   }
   pid := -1
   cmd.Stdout = os.Stdout
   cmd.Stderr = os.Stderr
   err := cmd.Start()
   if err == nil {
      pid = cmd.Process.Pid
      procMap[pid] = &procInfo{cmd, rEnv}
   }
   return pid, err
}
// Config conf
// Config config
type Config struct {
   Pid              int
   Options          int
@@ -80,6 +25,7 @@
func sigChildHandler(notifications chan os.Signal) {
   sigs := make(chan os.Signal, 3)
   signal.Notify(sigs, syscall.SIGCHLD)
   signal.Ignore(syscall.SIGPIPE)
   for {
      sig := <-sigs
@@ -98,7 +44,7 @@
} /*  End of function  sigChildHandler.  */
//  Be a good parent - clean up behind the children.
func reapChildren(config Config, pidChan chan<- int) {
func reapChildren(config Config, info chan<- ExitInfo) {
   notifications := make(chan os.Signal, 1)
   go sigChildHandler(notifications)
@@ -117,10 +63,10 @@
          *  Plants vs. Zombies!!
          */
         pid, err := syscall.Wait4(pid, &wstatus, opts, nil)
         pidChan <- pid
         info <- ExitInfo{pid, wstatus.ExitStatus()}
         for syscall.EINTR == err {
            pid, err = syscall.Wait4(pid, &wstatus, opts, nil)
            pidChan <- pid
            info <- ExitInfo{pid, wstatus.ExitStatus()}
         }
         if syscall.ECHILD == err {
@@ -145,7 +91,7 @@
//  background inside a goroutine.
// Reap reap
func Reap(pidChan chan<- int) {
func Reap(info chan<- ExitInfo) {
   /*
    *  Only reap processes if we are taking over init's duties aka
    *  we are running as pid 1 inside a docker container. The default
@@ -155,7 +101,7 @@
      Pid:              -1,
      Options:          0,
      DisablePid1Check: true,
   }, pidChan)
   }, info)
} /*  End of [exported] function  Reap.  */
@@ -164,7 +110,7 @@
//  The child processes are reaped in the background inside a goroutine.
// Start start
func Start(config Config, pidChan chan<- int) {
func Start(config Config, info chan<- ExitInfo) {
   /*
    *  Start the Reaper with configuration options. This allows you to
    *  reap processes even if the current pid isn't running as pid 1.
@@ -186,20 +132,6 @@
    *  of 'em all, either way we get to play the grim reaper.
    *  You will be missed, Terry Pratchett!! RIP
    */
   go reapChildren(config, pidChan)
   go reapChildren(config, info)
} /*  End of [exported] function  Start.  */
func waitForRestart(ctxt context.Context, pidChan <-chan int) {
   for {
      select {
      case <-ctxt.Done():
         return
      case pid := <-pidChan:
         restartProc(ctxt, pid)
      default:
         time.Sleep(3 * time.Second)
      }
   }
}