Source file src/os/exec.go
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 package os 6 7 import ( 8 "errors" 9 "internal/testlog" 10 "runtime" 11 "sync" 12 "sync/atomic" 13 "syscall" 14 "time" 15 ) 16 17 // ErrProcessDone indicates a [Process] has finished. 18 var ErrProcessDone = errors.New("os: process already finished") 19 20 // processStatus describes the status of a [Process]. 21 type processStatus uint32 22 23 const ( 24 // statusOK means that the Process is ready to use. 25 statusOK processStatus = iota 26 27 // statusDone indicates that the PID/handle should not be used because 28 // the process is done (has been successfully Wait'd on). 29 statusDone 30 31 // statusReleased indicates that the PID/handle should not be used 32 // because the process is released. 33 statusReleased 34 ) 35 36 // Process stores the information about a process created by [StartProcess]. 37 type Process struct { 38 Pid int 39 40 // state contains the atomic process state. 41 // 42 // This consists of the processStatus fields, 43 // which indicate if the process is done/released. 44 state atomic.Uint32 45 46 // Used only when handle is nil 47 sigMu sync.RWMutex // avoid race between wait and signal 48 49 // handle, if not nil, is a pointer to a struct 50 // that holds the OS-specific process handle. 51 // This pointer is set when Process is created, 52 // and never changed afterward. 53 // This is a pointer to a separate memory allocation 54 // so that we can use runtime.AddCleanup. 55 handle *processHandle 56 57 // cleanup is used to clean up the process handle. 58 cleanup runtime.Cleanup 59 } 60 61 // processHandle holds an operating system handle to a process. 62 // This is only used on systems that support that concept, 63 // currently Linux and Windows. 64 // This maintains a reference count to the handle, 65 // and closes the handle when the reference drops to zero. 66 type processHandle struct { 67 // The actual handle. This field should not be used directly. 68 // Instead, use the acquire and release methods. 69 // 70 // On Windows this is a handle returned by OpenProcess. 71 // On Linux this is a pidfd. 72 handle uintptr 73 74 // Number of active references. When this drops to zero 75 // the handle is closed. 76 refs atomic.Int32 77 } 78 79 // acquire adds a reference and returns the handle. 80 // The bool result reports whether acquire succeeded; 81 // it fails if the handle is already closed. 82 // Every successful call to acquire should be paired with a call to release. 83 func (ph *processHandle) acquire() (uintptr, bool) { 84 for { 85 refs := ph.refs.Load() 86 if refs < 0 { 87 panic("internal error: negative process handle reference count") 88 } 89 if refs == 0 { 90 return 0, false 91 } 92 if ph.refs.CompareAndSwap(refs, refs+1) { 93 return ph.handle, true 94 } 95 } 96 } 97 98 // release releases a reference to the handle. 99 func (ph *processHandle) release() { 100 for { 101 refs := ph.refs.Load() 102 if refs <= 0 { 103 panic("internal error: too many releases of process handle") 104 } 105 if ph.refs.CompareAndSwap(refs, refs-1) { 106 if refs == 1 { 107 ph.closeHandle() 108 } 109 return 110 } 111 } 112 } 113 114 // newPIDProcess returns a [Process] for the given PID. 115 func newPIDProcess(pid int) *Process { 116 p := &Process{ 117 Pid: pid, 118 } 119 return p 120 } 121 122 // newHandleProcess returns a [Process] with the given PID and handle. 123 func newHandleProcess(pid int, handle uintptr) *Process { 124 ph := &processHandle{ 125 handle: handle, 126 } 127 128 // Start the reference count as 1, 129 // meaning the reference from the returned Process. 130 ph.refs.Store(1) 131 132 p := &Process{ 133 Pid: pid, 134 handle: ph, 135 } 136 137 p.cleanup = runtime.AddCleanup(p, (*processHandle).release, ph) 138 139 return p 140 } 141 142 // newDoneProcess returns a [Process] for the given PID 143 // that is already marked as done. This is used on Unix systems 144 // if the process is known to not exist. 145 func newDoneProcess(pid int) *Process { 146 p := &Process{ 147 Pid: pid, 148 } 149 p.state.Store(uint32(statusDone)) // No persistent reference, as there is no handle. 150 return p 151 } 152 153 // handleTransientAcquire returns the process handle or, 154 // if the process is not ready, the current status. 155 func (p *Process) handleTransientAcquire() (uintptr, processStatus) { 156 if p.handle == nil { 157 panic("handleTransientAcquire called in invalid mode") 158 } 159 160 status := processStatus(p.state.Load()) 161 if status != statusOK { 162 return 0, status 163 } 164 h, ok := p.handle.acquire() 165 if ok { 166 return h, statusOK 167 } 168 169 // This case means that the handle has been closed. 170 // We always set the status to non-zero before closing the handle. 171 // If we get here the status must have been set non-zero after 172 // we just checked it above. 173 status = processStatus(p.state.Load()) 174 if status == statusOK { 175 panic("inconsistent process status") 176 } 177 return 0, status 178 } 179 180 // handleTransientRelease releases a handle returned by handleTransientAcquire. 181 func (p *Process) handleTransientRelease() { 182 if p.handle == nil { 183 panic("handleTransientRelease called in invalid mode") 184 } 185 p.handle.release() 186 } 187 188 // pidStatus returns the current process status. 189 func (p *Process) pidStatus() processStatus { 190 if p.handle != nil { 191 panic("pidStatus called in invalid mode") 192 } 193 194 return processStatus(p.state.Load()) 195 } 196 197 // ProcAttr holds the attributes that will be applied to a new process 198 // started by StartProcess. 199 type ProcAttr struct { 200 // If Dir is non-empty, the child changes into the directory before 201 // creating the process. 202 Dir string 203 // If Env is non-nil, it gives the environment variables for the 204 // new process in the form returned by Environ. 205 // If it is nil, the result of Environ will be used. 206 Env []string 207 // Files specifies the open files inherited by the new process. The 208 // first three entries correspond to standard input, standard output, and 209 // standard error. An implementation may support additional entries, 210 // depending on the underlying operating system. A nil entry corresponds 211 // to that file being closed when the process starts. 212 // On Unix systems, StartProcess will change these File values 213 // to blocking mode, which means that SetDeadline will stop working 214 // and calling Close will not interrupt a Read or Write. 215 Files []*File 216 217 // Operating system-specific process creation attributes. 218 // Note that setting this field means that your program 219 // may not execute properly or even compile on some 220 // operating systems. 221 Sys *syscall.SysProcAttr 222 } 223 224 // A Signal represents an operating system signal. 225 // The usual underlying implementation is operating system-dependent: 226 // on Unix it is syscall.Signal. 227 type Signal interface { 228 String() string 229 Signal() // to distinguish from other Stringers 230 } 231 232 // Getpid returns the process id of the caller. 233 func Getpid() int { return syscall.Getpid() } 234 235 // Getppid returns the process id of the caller's parent. 236 func Getppid() int { return syscall.Getppid() } 237 238 // FindProcess looks for a running process by its pid. 239 // 240 // The [Process] it returns can be used to obtain information 241 // about the underlying operating system process. 242 // 243 // On Unix systems, FindProcess always succeeds and returns a Process 244 // for the given pid, regardless of whether the process exists. To test whether 245 // the process actually exists, see whether p.Signal(syscall.Signal(0)) reports 246 // an error. 247 func FindProcess(pid int) (*Process, error) { 248 return findProcess(pid) 249 } 250 251 // StartProcess starts a new process with the program, arguments and attributes 252 // specified by name, argv and attr. The argv slice will become [os.Args] in the 253 // new process, so it normally starts with the program name. 254 // 255 // If the calling goroutine has locked the operating system thread 256 // with [runtime.LockOSThread] and modified any inheritable OS-level 257 // thread state (for example, Linux or Plan 9 name spaces), the new 258 // process will inherit the caller's thread state. 259 // 260 // StartProcess is a low-level interface. The [os/exec] package provides 261 // higher-level interfaces. 262 // 263 // If there is an error, it will be of type [*PathError]. 264 func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) { 265 testlog.Open(name) 266 return startProcess(name, argv, attr) 267 } 268 269 // Release releases any resources associated with the [Process] p, 270 // rendering it unusable in the future. 271 // Release only needs to be called if [Process.Wait] is not. 272 func (p *Process) Release() error { 273 // Unfortunately, for historical reasons, on systems other 274 // than Windows, Release sets the Pid field to -1. 275 // This causes the race detector to report a problem 276 // on concurrent calls to Release, but we can't change it now. 277 if runtime.GOOS != "windows" { 278 p.Pid = -1 279 } 280 281 oldStatus := p.doRelease(statusReleased) 282 283 // For backward compatibility, on Windows only, 284 // we return EINVAL on a second call to Release. 285 if runtime.GOOS == "windows" { 286 if oldStatus == statusReleased { 287 return syscall.EINVAL 288 } 289 } 290 291 return nil 292 } 293 294 // doRelease releases a [Process], setting the status to newStatus. 295 // If the previous status is not statusOK, this does nothing. 296 // It returns the previous status. 297 func (p *Process) doRelease(newStatus processStatus) processStatus { 298 for { 299 state := p.state.Load() 300 oldStatus := processStatus(state) 301 if oldStatus != statusOK { 302 return oldStatus 303 } 304 305 if !p.state.CompareAndSwap(state, uint32(newStatus)) { 306 continue 307 } 308 309 // We have successfully released the Process. 310 // If it has a handle, release the reference we 311 // created in newHandleProcess. 312 if p.handle != nil { 313 // No need for more cleanup. 314 // We must stop the cleanup before calling release; 315 // otherwise the cleanup might run concurrently 316 // with the release, which would cause the reference 317 // counts to be invalid, causing a panic. 318 p.cleanup.Stop() 319 320 p.handle.release() 321 } 322 323 return statusOK 324 } 325 } 326 327 // Kill causes the [Process] to exit immediately. Kill does not wait until 328 // the Process has actually exited. This only kills the Process itself, 329 // not any other processes it may have started. 330 func (p *Process) Kill() error { 331 return p.kill() 332 } 333 334 // Wait waits for the [Process] to exit, and then returns a 335 // ProcessState describing its status and an error, if any. 336 // Wait releases any resources associated with the Process. 337 // On most operating systems, the Process must be a child 338 // of the current process or an error will be returned. 339 func (p *Process) Wait() (*ProcessState, error) { 340 return p.wait() 341 } 342 343 // Signal sends a signal to the [Process]. 344 // Sending [Interrupt] on Windows is not implemented. 345 func (p *Process) Signal(sig Signal) error { 346 return p.signal(sig) 347 } 348 349 // UserTime returns the user CPU time of the exited process and its children. 350 func (p *ProcessState) UserTime() time.Duration { 351 return p.userTime() 352 } 353 354 // SystemTime returns the system CPU time of the exited process and its children. 355 func (p *ProcessState) SystemTime() time.Duration { 356 return p.systemTime() 357 } 358 359 // Exited reports whether the program has exited. 360 // On Unix systems this reports true if the program exited due to calling exit, 361 // but false if the program terminated due to a signal. 362 func (p *ProcessState) Exited() bool { 363 return p.exited() 364 } 365 366 // Success reports whether the program exited successfully, 367 // such as with exit status 0 on Unix. 368 func (p *ProcessState) Success() bool { 369 return p.success() 370 } 371 372 // Sys returns system-dependent exit information about 373 // the process. Convert it to the appropriate underlying 374 // type, such as [syscall.WaitStatus] on Unix, to access its contents. 375 func (p *ProcessState) Sys() any { 376 return p.sys() 377 } 378 379 // SysUsage returns system-dependent resource usage information about 380 // the exited process. Convert it to the appropriate underlying 381 // type, such as [*syscall.Rusage] on Unix, to access its contents. 382 // (On Unix, *syscall.Rusage matches struct rusage as defined in the 383 // getrusage(2) manual page.) 384 func (p *ProcessState) SysUsage() any { 385 return p.sysUsage() 386 } 387