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  

View as plain text