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 5//go:build unix || (js && wasm) || wasip1 6 7package os 8 9import ( 10 "errors" 11 "runtime" 12 "syscall" 13 "time" 14) 15 16const ( 17 // Special values for Process.Pid. 18 pidUnset = 0 19 pidReleased = -1 20) 21 22func (p *Process) wait() (ps *ProcessState, err error) { 23 // Which type of Process do we have? 24 switch p.mode { 25 case modeHandle: 26 // pidfd 27 return p.pidfdWait() 28 case modePID: 29 // Regular PID 30 return p.pidWait() 31 default: 32 panic("unreachable") 33 } 34} 35 36func (p *Process) pidWait() (*ProcessState, error) { 37 // TODO(go.dev/issue/67642): When there are concurrent Wait calls, one 38 // may wait on the wrong process if the PID is reused after the 39 // completes its wait. 40 // 41 // Checking for statusDone here would not be a complete fix, as the PID 42 // could still be waited on and reused prior to blockUntilWaitable. 43 switch p.pidStatus() { 44 case statusReleased: 45 return nil, syscall.EINVAL 46 } 47 48 // If we can block until Wait4 will succeed immediately, do so. 49 ready, err := p.blockUntilWaitable() 50 if err != nil { 51 return nil, err 52 } 53 if ready { 54 // Mark the process done now, before the call to Wait4, 55 // so that Process.pidSignal will not send a signal. 56 p.pidDeactivate(statusDone) 57 // Acquire a write lock on sigMu to wait for any 58 // active call to the signal method to complete. 59 p.sigMu.Lock() 60 p.sigMu.Unlock() 61 } 62 63 var ( 64 status syscall.WaitStatus 65 rusage syscall.Rusage 66 pid1 int 67 e error 68 ) 69 for { 70 pid1, e = syscall.Wait4(p.Pid, &status, 0, &rusage) 71 if e != syscall.EINTR { 72 break 73 } 74 } 75 if e != nil { 76 return nil, NewSyscallError("wait", e) 77 } 78 p.pidDeactivate(statusDone) 79 return &ProcessState{ 80 pid: pid1, 81 status: status, 82 rusage: &rusage, 83 }, nil 84} 85 86func (p *Process) signal(sig Signal) error { 87 s, ok := sig.(syscall.Signal) 88 if !ok { 89 return errors.New("os: unsupported signal type") 90 } 91 92 // Which type of Process do we have? 93 switch p.mode { 94 case modeHandle: 95 // pidfd 96 return p.pidfdSendSignal(s) 97 case modePID: 98 // Regular PID 99 return p.pidSignal(s) 100 default: 101 panic("unreachable") 102 } 103} 104 105func (p *Process) pidSignal(s syscall.Signal) error { 106 if p.Pid == pidReleased { 107 return errors.New("os: process already released") 108 } 109 if p.Pid == pidUnset { 110 return errors.New("os: process not initialized") 111 } 112 113 p.sigMu.RLock() 114 defer p.sigMu.RUnlock() 115 116 switch p.pidStatus() { 117 case statusDone: 118 return ErrProcessDone 119 case statusReleased: 120 return errors.New("os: process already released") 121 } 122 123 return convertESRCH(syscall.Kill(p.Pid, s)) 124} 125 126func convertESRCH(err error) error { 127 if err == syscall.ESRCH { 128 return ErrProcessDone 129 } 130 return err 131} 132 133func (p *Process) release() error { 134 // We clear the Pid field only for API compatibility. On Unix, Release 135 // has always set Pid to -1. Internally, the implementation relies 136 // solely on statusReleased to determine that the Process is released. 137 p.Pid = pidReleased 138 139 switch p.mode { 140 case modeHandle: 141 // Drop the Process' reference and mark handle unusable for 142 // future calls. 143 // 144 // Ignore the return value: we don't care if this was a no-op 145 // racing with Wait, or a double Release. 146 p.handlePersistentRelease(statusReleased) 147 case modePID: 148 // Just mark the PID unusable. 149 p.pidDeactivate(statusReleased) 150 } 151 // no need for a finalizer anymore 152 runtime.SetFinalizer(p, nil) 153 return nil 154} 155 156func findProcess(pid int) (p *Process, err error) { 157 h, err := pidfdFind(pid) 158 if err == ErrProcessDone { 159 // We can't return an error here since users are not expecting 160 // it. Instead, return a process with a "done" state already 161 // and let a subsequent Signal or Wait call catch that. 162 return newDoneProcess(pid), nil 163 } else if err != nil { 164 // Ignore other errors from pidfdFind, as the callers 165 // do not expect them. Fall back to using the PID. 166 return newPIDProcess(pid), nil 167 } 168 // Use the handle. 169 return newHandleProcess(pid, h), nil 170} 171 172func (p *ProcessState) userTime() time.Duration { 173 return time.Duration(p.rusage.Utime.Nano()) * time.Nanosecond 174} 175 176func (p *ProcessState) systemTime() time.Duration { 177 return time.Duration(p.rusage.Stime.Nano()) * time.Nanosecond 178} 179