github.com/sdibtacm/sandbox@v0.0.0-20200320120712-60470cf803dc/exec/process.go (about) 1 // +build linux 2 3 package exec 4 5 import ( 6 "errors" 7 "os" 8 "runtime" 9 "sync" 10 "sync/atomic" 11 "syscall" 12 ) 13 14 // process helper 15 // because will use ptrace to trace process, the golang function have some insufficient 16 17 // ProcessState stores information about a process, as reported by Wait. 18 type ProcessState struct { 19 pid int // The process's id. 20 status syscall.WaitStatus // System-dependent status info. 21 rusage *syscall.Rusage 22 } 23 24 // Pid returns the process id of the exited process. 25 func (p *ProcessState) Pid() int { 26 return p.pid 27 } 28 29 func (p *ProcessState) Exited() bool { 30 return p.status.Exited() 31 } 32 33 func (p *ProcessState) Success() bool { 34 return p.status.ExitStatus() == 0 35 } 36 37 func (p *ProcessState) Sys() syscall.WaitStatus { 38 return p.status 39 } 40 41 func (p *ProcessState) SysUsage() *syscall.Rusage { 42 return p.rusage 43 } 44 45 func (p *ProcessState) String() string { 46 if p == nil { 47 return "<nil>" 48 } 49 status := p.status 50 res := "" 51 switch { 52 case status.Exited(): 53 res = "exit status " + itoa(status.ExitStatus()) 54 case status.Signaled(): 55 res = "signal: " + status.Signal().String() 56 case status.Stopped(): 57 res = "stop signal: " + status.StopSignal().String() 58 if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != 0 { 59 res += " (trap " + itoa(status.TrapCause()) + ")" 60 } 61 case status.Continued(): 62 res = "continued" 63 } 64 if status.CoreDump() { 65 res += " (core dumped)" 66 } 67 return res 68 } 69 70 // ExitCode returns the exit code of the exited process, or -1 71 // if the process hasn't exited or was terminated by a signal. 72 func (p *ProcessState) ExitCode() int { 73 // return -1 if the process hasn't started. 74 if p == nil { 75 return -1 76 } 77 return p.status.ExitStatus() 78 } 79 80 // Process stores the information about a process created by StartProcess. 81 type Process struct { 82 Pid int 83 handle uintptr // handle is accessed atomically on Windows 84 isdone uint32 // process has been successfully waited on, non zero if true 85 sigMu sync.RWMutex // avoid race between wait and signal 86 } 87 88 var errFinished = errors.New("os: process already finished") 89 90 func (p *Process) SignalGroup(sig os.Signal) error { 91 if p.Pid == -1 { 92 return errors.New("os: process already released") 93 } 94 if p.Pid == 0 { 95 return errors.New("os: process not initialized") 96 } 97 p.sigMu.RLock() 98 defer p.sigMu.RUnlock() 99 if p.done() { 100 return errFinished 101 } 102 s, ok := sig.(syscall.Signal) 103 if !ok { 104 return errors.New("os: unsupported signal type") 105 } 106 if e := syscall.Kill(-p.Pid, s); e != nil { 107 if e == syscall.ESRCH { 108 return errFinished 109 } 110 return e 111 } 112 return nil 113 } 114 115 func (p *Process) Signal(sig os.Signal) error { 116 if p.Pid == -1 { 117 return errors.New("os: process already released") 118 } 119 if p.Pid == 0 { 120 return errors.New("os: process not initialized") 121 } 122 p.sigMu.RLock() 123 defer p.sigMu.RUnlock() 124 if p.done() { 125 return errFinished 126 } 127 s, ok := sig.(syscall.Signal) 128 if !ok { 129 return errors.New("os: unsupported signal type") 130 } 131 if e := syscall.Kill(p.Pid, s); e != nil { 132 if e == syscall.ESRCH { 133 return errFinished 134 } 135 return e 136 } 137 return nil 138 } 139 140 func newProcess(pid int, handle uintptr) *Process { 141 p := &Process{Pid: pid, handle: handle} 142 runtime.SetFinalizer(p, (*Process).Release) 143 return p 144 } 145 146 func (p *Process) Release() error { 147 // NOOP for unix. 148 p.Pid = -1 149 // no need for a finalizer anymore 150 runtime.SetFinalizer(p, nil) 151 return nil 152 } 153 154 func (p *Process) Kill() error { 155 return p.Signal(os.Kill) 156 } 157 158 func (p *Process) KillGroup() error { 159 return p.Signal(os.Kill) 160 } 161 162 func (p *Process) setDone() { 163 atomic.StoreUint32(&p.isdone, 1) 164 } 165 166 func (p *Process) done() bool { 167 return atomic.LoadUint32(&p.isdone) > 0 168 } 169 170 func (p *Process) SetDone() { 171 p.setDone() 172 } 173 174 func (p *Process) Done() bool { 175 return p.done() 176 }