1// Copyright 2009 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package os 6 7import ( 8 "errors" 9 "runtime" 10 "syscall" 11 "time" 12) 13 14// The only signal values guaranteed to be present on all systems 15// are Interrupt (send the process an interrupt) and Kill (force 16// the process to exit). 17var ( 18 Interrupt Signal = syscall.Note("interrupt") 19 Kill Signal = syscall.Note("kill") 20) 21 22func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { 23 sysattr := &syscall.ProcAttr{ 24 Dir: attr.Dir, 25 Env: attr.Env, 26 Sys: attr.Sys, 27 } 28 29 for _, f := range attr.Files { 30 sysattr.Files = append(sysattr.Files, f.Fd()) 31 } 32 33 pid, h, e := syscall.StartProcess(name, argv, sysattr) 34 if e != nil { 35 return nil, &PathError{"fork/exec", name, e} 36 } 37 38 return newProcess(pid, h), nil 39} 40 41func (p *Process) writeProcFile(file string, data string) error { 42 f, e := OpenFile("/proc/"+itoa(p.Pid)+"/"+file, O_WRONLY, 0) 43 if e != nil { 44 return e 45 } 46 defer f.Close() 47 _, e = f.Write([]byte(data)) 48 return e 49} 50 51func (p *Process) signal(sig Signal) error { 52 if p.done() { 53 return errors.New("os: process already finished") 54 } 55 if sig == Kill { 56 // Special-case the kill signal since it doesn't use /proc/$pid/note. 57 return p.Kill() 58 } 59 if e := p.writeProcFile("note", sig.String()); e != nil { 60 return NewSyscallError("signal", e) 61 } 62 return nil 63} 64 65func (p *Process) kill() error { 66 if e := p.writeProcFile("ctl", "kill"); e != nil { 67 return NewSyscallError("kill", e) 68 } 69 return nil 70} 71 72func (p *Process) wait() (ps *ProcessState, err error) { 73 var waitmsg syscall.Waitmsg 74 75 if p.Pid == -1 { 76 return nil, ErrInvalid 77 } 78 err = syscall.WaitProcess(p.Pid, &waitmsg) 79 if err != nil { 80 return nil, NewSyscallError("wait", err) 81 } 82 83 p.setDone() 84 ps = &ProcessState{ 85 pid: waitmsg.Pid, 86 status: &waitmsg, 87 } 88 return ps, nil 89} 90 91func (p *Process) release() error { 92 // NOOP for Plan 9. 93 p.Pid = -1 94 // no need for a finalizer anymore 95 runtime.SetFinalizer(p, nil) 96 return nil 97} 98 99func findProcess(pid int) (p *Process, err error) { 100 // NOOP for Plan 9. 101 return newProcess(pid, 0), nil 102} 103 104// ProcessState stores information about a process, as reported by Wait. 105type ProcessState struct { 106 pid int // The process's id. 107 status *syscall.Waitmsg // System-dependent status info. 108} 109 110// Pid returns the process id of the exited process. 111func (p *ProcessState) Pid() int { 112 return p.pid 113} 114 115func (p *ProcessState) exited() bool { 116 return p.status.Exited() 117} 118 119func (p *ProcessState) success() bool { 120 return p.status.ExitStatus() == 0 121} 122 123func (p *ProcessState) sys() interface{} { 124 return p.status 125} 126 127func (p *ProcessState) sysUsage() interface{} { 128 return p.status 129} 130 131func (p *ProcessState) userTime() time.Duration { 132 return time.Duration(p.status.Time[0]) * time.Millisecond 133} 134 135func (p *ProcessState) systemTime() time.Duration { 136 return time.Duration(p.status.Time[1]) * time.Millisecond 137} 138 139func (p *ProcessState) String() string { 140 if p == nil { 141 return "<nil>" 142 } 143 return "exit status: " + p.status.Msg 144} 145