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