...

Source file src/os/exec.go

Documentation: os

     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  

View as plain text