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  type processMode uint8
    21  
    22  const (
    23  	// modePID means that Process operations such use the raw PID from the
    24  	// Pid field. handle is not used.
    25  	//
    26  	// This may be due to the host not supporting handles, or because
    27  	// Process was created as a literal, leaving handle unset.
    28  	//
    29  	// This must be the zero value so Process literals get modePID.
    30  	modePID processMode = iota
    31  
    32  	// modeHandle means that Process operations use handle, which is
    33  	// initialized with an OS process handle.
    34  	//
    35  	// Note that Release and Wait will deactivate and eventually close the
    36  	// handle, so acquire may fail, indicating the reason.
    37  	modeHandle
    38  )
    39  
    40  type processStatus uint64
    41  
    42  const (
    43  	// PID/handle OK to use.
    44  	statusOK processStatus = 0
    45  
    46  	// statusDone indicates that the PID/handle should not be used because
    47  	// the process is done (has been successfully Wait'd on).
    48  	statusDone processStatus = 1 << 62
    49  
    50  	// statusReleased indicates that the PID/handle should not be used
    51  	// because the process is released.
    52  	statusReleased processStatus = 1 << 63
    53  
    54  	processStatusMask = 0x3 << 62
    55  )
    56  
    57  // Process stores the information about a process created by [StartProcess].
    58  type Process struct {
    59  	Pid int
    60  
    61  	mode processMode
    62  
    63  	// State contains the atomic process state.
    64  	//
    65  	// In modePID, this consists only of the processStatus fields, which
    66  	// indicate if the process is done/released.
    67  	//
    68  	// In modeHandle, the lower bits also contain a reference count for the
    69  	// handle field.
    70  	//
    71  	// The Process itself initially holds 1 persistent reference. Any
    72  	// operation that uses the handle with a system call temporarily holds
    73  	// an additional transient reference. This prevents the handle from
    74  	// being closed prematurely, which could result in the OS allocating a
    75  	// different handle with the same value, leading to Process' methods
    76  	// operating on the wrong process.
    77  	//
    78  	// Release and Wait both drop the Process' persistent reference, but
    79  	// other concurrent references may delay actually closing the handle
    80  	// because they hold a transient reference.
    81  	//
    82  	// Regardless, we want new method calls to immediately treat the handle
    83  	// as unavailable after Release or Wait to avoid extending this delay.
    84  	// This is achieved by setting either processStatus flag when the
    85  	// Process' persistent reference is dropped. The only difference in the
    86  	// flags is the reason the handle is unavailable, which affects the
    87  	// errors returned by concurrent calls.
    88  	state atomic.Uint64
    89  
    90  	// Used only in modePID.
    91  	sigMu sync.RWMutex // avoid race between wait and signal
    92  
    93  	// handle is the OS handle for process actions, used only in
    94  	// modeHandle.
    95  	//
    96  	// handle must be accessed only via the handleTransientAcquire method
    97  	// (or during closeHandle), not directly! handle is immutable.
    98  	//
    99  	// On Windows, it is a handle from OpenProcess.
   100  	// On Linux, it is a pidfd.
   101  	// It is unused on other GOOSes.
   102  	handle uintptr
   103  }
   104  
   105  func newPIDProcess(pid int) *Process {
   106  	p := &Process{
   107  		Pid:  pid,
   108  		mode: modePID,
   109  	}
   110  	runtime.SetFinalizer(p, (*Process).Release)
   111  	return p
   112  }
   113  
   114  func newHandleProcess(pid int, handle uintptr) *Process {
   115  	p := &Process{
   116  		Pid:    pid,
   117  		mode:   modeHandle,
   118  		handle: handle,
   119  	}
   120  	p.state.Store(1) // 1 persistent reference
   121  	runtime.SetFinalizer(p, (*Process).Release)
   122  	return p
   123  }
   124  
   125  func newDoneProcess(pid int) *Process {
   126  	p := &Process{
   127  		Pid:  pid,
   128  		mode: modeHandle,
   129  		// N.B Since we set statusDone, handle will never actually be
   130  		// used, so its value doesn't matter.
   131  	}
   132  	p.state.Store(uint64(statusDone)) // No persistent reference, as there is no handle.
   133  	runtime.SetFinalizer(p, (*Process).Release)
   134  	return p
   135  }
   136  
   137  func (p *Process) handleTransientAcquire() (uintptr, processStatus) {
   138  	if p.mode != modeHandle {
   139  		panic("handleTransientAcquire called in invalid mode")
   140  	}
   141  
   142  	for {
   143  		refs := p.state.Load()
   144  		if refs&processStatusMask != 0 {
   145  			return 0, processStatus(refs & processStatusMask)
   146  		}
   147  		new := refs + 1
   148  		if !p.state.CompareAndSwap(refs, new) {
   149  			continue
   150  		}
   151  		return p.handle, statusOK
   152  	}
   153  }
   154  
   155  func (p *Process) handleTransientRelease() {
   156  	if p.mode != modeHandle {
   157  		panic("handleTransientRelease called in invalid mode")
   158  	}
   159  
   160  	for {
   161  		state := p.state.Load()
   162  		refs := state &^ processStatusMask
   163  		status := processStatus(state & processStatusMask)
   164  		if refs == 0 {
   165  			// This should never happen because
   166  			// handleTransientRelease is always paired with
   167  			// handleTransientAcquire.
   168  			panic("release of handle with refcount 0")
   169  		}
   170  		if refs == 1 && status == statusOK {
   171  			// Process holds a persistent reference and always sets
   172  			// a status when releasing that reference
   173  			// (handlePersistentRelease). Thus something has gone
   174  			// wrong if this is the last release but a status has
   175  			// not always been set.
   176  			panic("final release of handle without processStatus")
   177  		}
   178  		new := state - 1
   179  		if !p.state.CompareAndSwap(state, new) {
   180  			continue
   181  		}
   182  		if new&^processStatusMask == 0 {
   183  			p.closeHandle()
   184  		}
   185  		return
   186  	}
   187  }
   188  
   189  // Drop the Process' persistent reference on the handle, deactivating future
   190  // Wait/Signal calls with the passed reason.
   191  //
   192  // Returns the status prior to this call. If this is not statusOK, then the
   193  // reference was not dropped or status changed.
   194  func (p *Process) handlePersistentRelease(reason processStatus) processStatus {
   195  	if p.mode != modeHandle {
   196  		panic("handlePersistentRelease called in invalid mode")
   197  	}
   198  
   199  	for {
   200  		refs := p.state.Load()
   201  		status := processStatus(refs & processStatusMask)
   202  		if status != statusOK {
   203  			// Both Release and successful Wait will drop the
   204  			// Process' persistent reference on the handle. We
   205  			// can't allow concurrent calls to drop the reference
   206  			// twice, so we use the status as a guard to ensure the
   207  			// reference is dropped exactly once.
   208  			return status
   209  		}
   210  		if refs == 0 {
   211  			// This should never happen because dropping the
   212  			// persistent reference always sets a status.
   213  			panic("release of handle with refcount 0")
   214  		}
   215  		new := (refs - 1) | uint64(reason)
   216  		if !p.state.CompareAndSwap(refs, new) {
   217  			continue
   218  		}
   219  		if new&^processStatusMask == 0 {
   220  			p.closeHandle()
   221  		}
   222  		return status
   223  	}
   224  }
   225  
   226  func (p *Process) pidStatus() processStatus {
   227  	if p.mode != modePID {
   228  		panic("pidStatus called in invalid mode")
   229  	}
   230  
   231  	return processStatus(p.state.Load())
   232  }
   233  
   234  func (p *Process) pidDeactivate(reason processStatus) {
   235  	if p.mode != modePID {
   236  		panic("pidDeactivate called in invalid mode")
   237  	}
   238  
   239  	// Both Release and successful Wait will deactivate the PID. Only one
   240  	// of those should win, so nothing left to do here if the compare
   241  	// fails.
   242  	//
   243  	// N.B. This means that results can be inconsistent. e.g., with a
   244  	// racing Release and Wait, Wait may successfully wait on the process,
   245  	// returning the wait status, while future calls error with "process
   246  	// released" rather than "process done".
   247  	p.state.CompareAndSwap(0, uint64(reason))
   248  }
   249  
   250  // ProcAttr holds the attributes that will be applied to a new process
   251  // started by StartProcess.
   252  type ProcAttr struct {
   253  	// If Dir is non-empty, the child changes into the directory before
   254  	// creating the process.
   255  	Dir string
   256  	// If Env is non-nil, it gives the environment variables for the
   257  	// new process in the form returned by Environ.
   258  	// If it is nil, the result of Environ will be used.
   259  	Env []string
   260  	// Files specifies the open files inherited by the new process. The
   261  	// first three entries correspond to standard input, standard output, and
   262  	// standard error. An implementation may support additional entries,
   263  	// depending on the underlying operating system. A nil entry corresponds
   264  	// to that file being closed when the process starts.
   265  	// On Unix systems, StartProcess will change these File values
   266  	// to blocking mode, which means that SetDeadline will stop working
   267  	// and calling Close will not interrupt a Read or Write.
   268  	Files []*File
   269  
   270  	// Operating system-specific process creation attributes.
   271  	// Note that setting this field means that your program
   272  	// may not execute properly or even compile on some
   273  	// operating systems.
   274  	Sys *syscall.SysProcAttr
   275  }
   276  
   277  // A Signal represents an operating system signal.
   278  // The usual underlying implementation is operating system-dependent:
   279  // on Unix it is syscall.Signal.
   280  type Signal interface {
   281  	String() string
   282  	Signal() // to distinguish from other Stringers
   283  }
   284  
   285  // Getpid returns the process id of the caller.
   286  func Getpid() int { return syscall.Getpid() }
   287  
   288  // Getppid returns the process id of the caller's parent.
   289  func Getppid() int { return syscall.Getppid() }
   290  
   291  // FindProcess looks for a running process by its pid.
   292  //
   293  // The [Process] it returns can be used to obtain information
   294  // about the underlying operating system process.
   295  //
   296  // On Unix systems, FindProcess always succeeds and returns a Process
   297  // for the given pid, regardless of whether the process exists. To test whether
   298  // the process actually exists, see whether p.Signal(syscall.Signal(0)) reports
   299  // an error.
   300  func FindProcess(pid int) (*Process, error) {
   301  	return findProcess(pid)
   302  }
   303  
   304  // StartProcess starts a new process with the program, arguments and attributes
   305  // specified by name, argv and attr. The argv slice will become [os.Args] in the
   306  // new process, so it normally starts with the program name.
   307  //
   308  // If the calling goroutine has locked the operating system thread
   309  // with [runtime.LockOSThread] and modified any inheritable OS-level
   310  // thread state (for example, Linux or Plan 9 name spaces), the new
   311  // process will inherit the caller's thread state.
   312  //
   313  // StartProcess is a low-level interface. The [os/exec] package provides
   314  // higher-level interfaces.
   315  //
   316  // If there is an error, it will be of type [*PathError].
   317  func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) {
   318  	testlog.Open(name)
   319  	return startProcess(name, argv, attr)
   320  }
   321  
   322  // Release releases any resources associated with the [Process] p,
   323  // rendering it unusable in the future.
   324  // Release only needs to be called if [Process.Wait] is not.
   325  func (p *Process) Release() error {
   326  	// Note to future authors: the Release API is cursed.
   327  	//
   328  	// On Unix and Plan 9, Release sets p.Pid = -1. This is the only part of the
   329  	// Process API that is not thread-safe, but it can't be changed now.
   330  	//
   331  	// On Windows, Release does _not_ modify p.Pid.
   332  	//
   333  	// On Windows, Wait calls Release after successfully waiting to
   334  	// proactively clean up resources.
   335  	//
   336  	// On Unix and Plan 9, Wait also proactively cleans up resources, but
   337  	// can not call Release, as Wait does not set p.Pid = -1.
   338  	//
   339  	// On Unix and Plan 9, calling Release a second time has no effect.
   340  	//
   341  	// On Windows, calling Release a second time returns EINVAL.
   342  	return p.release()
   343  }
   344  
   345  // Kill causes the [Process] to exit immediately. Kill does not wait until
   346  // the Process has actually exited. This only kills the Process itself,
   347  // not any other processes it may have started.
   348  func (p *Process) Kill() error {
   349  	return p.kill()
   350  }
   351  
   352  // Wait waits for the [Process] to exit, and then returns a
   353  // ProcessState describing its status and an error, if any.
   354  // Wait releases any resources associated with the Process.
   355  // On most operating systems, the Process must be a child
   356  // of the current process or an error will be returned.
   357  func (p *Process) Wait() (*ProcessState, error) {
   358  	return p.wait()
   359  }
   360  
   361  // Signal sends a signal to the [Process].
   362  // Sending [Interrupt] on Windows is not implemented.
   363  func (p *Process) Signal(sig Signal) error {
   364  	return p.signal(sig)
   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  

View as plain text