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 "internal/itoa" 9 "runtime" 10 "syscall" 11 "time" 12) 13 14// The only signal values guaranteed to be present in the os package 15// on all systems are Interrupt (send the process an interrupt) and 16// Kill (force the process to exit). Interrupt is not implemented on 17// Windows; using it with [os.Process.Signal] will return an error. 18var ( 19 Interrupt Signal = syscall.Note("interrupt") 20 Kill Signal = syscall.Note("kill") 21) 22 23func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { 24 sysattr := &syscall.ProcAttr{ 25 Dir: attr.Dir, 26 Env: attr.Env, 27 Sys: attr.Sys, 28 } 29 30 sysattr.Files = make([]uintptr, 0, len(attr.Files)) 31 for _, f := range attr.Files { 32 sysattr.Files = append(sysattr.Files, f.Fd()) 33 } 34 35 pid, _, e := syscall.StartProcess(name, argv, sysattr) 36 if e != nil { 37 return nil, &PathError{Op: "fork/exec", Path: name, Err: e} 38 } 39 40 return newPIDProcess(pid), nil 41} 42 43func (p *Process) writeProcFile(file string, data string) error { 44 f, e := OpenFile("/proc/"+itoa.Itoa(p.Pid)+"/"+file, O_WRONLY, 0) 45 if e != nil { 46 return e 47 } 48 defer f.Close() 49 _, e = f.Write([]byte(data)) 50 return e 51} 52 53func (p *Process) signal(sig Signal) error { 54 switch p.pidStatus() { 55 case statusDone: 56 return ErrProcessDone 57 case statusReleased: 58 return syscall.ENOENT 59 } 60 61 if e := p.writeProcFile("note", sig.String()); e != nil { 62 return NewSyscallError("signal", e) 63 } 64 return nil 65} 66 67func (p *Process) kill() error { 68 return p.signal(Kill) 69} 70 71func (p *Process) wait() (ps *ProcessState, err error) { 72 var waitmsg syscall.Waitmsg 73 74 switch p.pidStatus() { 75 case statusReleased: 76 return nil, ErrInvalid 77 } 78 79 err = syscall.WaitProcess(p.Pid, &waitmsg) 80 if err != nil { 81 return nil, NewSyscallError("wait", err) 82 } 83 84 p.pidDeactivate(statusDone) 85 ps = &ProcessState{ 86 pid: waitmsg.Pid, 87 status: &waitmsg, 88 } 89 return ps, nil 90} 91 92func (p *Process) release() error { 93 p.Pid = -1 94 95 // Just mark the PID unusable. 96 p.pidDeactivate(statusReleased) 97 98 // no need for a finalizer anymore 99 runtime.SetFinalizer(p, nil) 100 return nil 101} 102 103func findProcess(pid int) (p *Process, err error) { 104 // NOOP for Plan 9. 105 return newPIDProcess(pid), nil 106} 107 108// ProcessState stores information about a process, as reported by Wait. 109type ProcessState struct { 110 pid int // The process's id. 111 status *syscall.Waitmsg // System-dependent status info. 112} 113 114// Pid returns the process id of the exited process. 115func (p *ProcessState) Pid() int { 116 return p.pid 117} 118 119func (p *ProcessState) exited() bool { 120 return p.status.Exited() 121} 122 123func (p *ProcessState) success() bool { 124 return p.status.ExitStatus() == 0 125} 126 127func (p *ProcessState) sys() any { 128 return p.status 129} 130 131func (p *ProcessState) sysUsage() any { 132 return p.status 133} 134 135func (p *ProcessState) userTime() time.Duration { 136 return time.Duration(p.status.Time[0]) * time.Millisecond 137} 138 139func (p *ProcessState) systemTime() time.Duration { 140 return time.Duration(p.status.Time[1]) * time.Millisecond 141} 142 143func (p *ProcessState) String() string { 144 if p == nil { 145 return "<nil>" 146 } 147 return "exit status: " + p.status.Msg 148} 149 150// ExitCode returns the exit code of the exited process, or -1 151// if the process hasn't exited or was terminated by a signal. 152func (p *ProcessState) ExitCode() int { 153 // return -1 if the process hasn't started. 154 if p == nil { 155 return -1 156 } 157 return p.status.ExitStatus() 158} 159