package runc import ( "os/exec" "syscall" "time" ) var Monitor ProcessMonitor = &defaultMonitor{} type Exit struct { Timestamp time.Time Pid int Status int } // ProcessMonitor is an interface for process monitoring // // It allows daemons using go-runc to have a SIGCHLD handler // to handle exits without introducing races between the handler // and go's exec.Cmd // These methods should match the methods exposed by exec.Cmd to provide // a consistent experience for the caller type ProcessMonitor interface { Start(*exec.Cmd) (chan Exit, error) Wait(*exec.Cmd, chan Exit) (int, error) } type defaultMonitor struct { } func (m *defaultMonitor) Start(c *exec.Cmd) (chan Exit, error) { if err := c.Start(); err != nil { return nil, err } ec := make(chan Exit, 1) go func() { var status int if err := c.Wait(); err != nil { status = 255 if exitErr, ok := err.(*exec.ExitError); ok { if ws, ok := exitErr.Sys().(syscall.WaitStatus); ok { status = ws.ExitStatus() } } } ec <- Exit{ Timestamp: time.Now(), Pid: c.Process.Pid, Status: status, } close(ec) }() return ec, nil } func (m *defaultMonitor) Wait(c *exec.Cmd, ec chan Exit) (int, error) { e := <-ec return e.Status, nil }