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