Source File
	exec.go
Belonging Package
	os
// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package osimport ()// ErrProcessDone indicates a [Process] has finished.var ErrProcessDone = errors.New("os: process already finished")type processMode uint8const (// modePID means that Process operations such use the raw PID from the// Pid field. handle is not used.//// This may be due to the host not supporting handles, or because// Process was created as a literal, leaving handle unset.//// This must be the zero value so Process literals get modePID.modePID processMode = iota// modeHandle means that Process operations use handle, which is// initialized with an OS process handle.//// Note that Release and Wait will deactivate and eventually close the// handle, so acquire may fail, indicating the reason.modeHandle)type processStatus uint64const (// PID/handle OK to use.statusOK processStatus = 0// statusDone indicates that the PID/handle should not be used because// the process is done (has been successfully Wait'd on).statusDone processStatus = 1 << 62// statusReleased indicates that the PID/handle should not be used// because the process is released.statusReleased processStatus = 1 << 63processStatusMask = 0x3 << 62)// Process stores the information about a process created by [StartProcess].type Process struct {Pid intmode processMode// State contains the atomic process state.//// In modePID, this consists only of the processStatus fields, which// indicate if the process is done/released.//// In modeHandle, the lower bits also contain a reference count for the// handle field.//// The Process itself initially holds 1 persistent reference. Any// operation that uses the handle with a system call temporarily holds// an additional transient reference. This prevents the handle from// being closed prematurely, which could result in the OS allocating a// different handle with the same value, leading to Process' methods// operating on the wrong process.//// Release and Wait both drop the Process' persistent reference, but// other concurrent references may delay actually closing the handle// because they hold a transient reference.//// Regardless, we want new method calls to immediately treat the handle// as unavailable after Release or Wait to avoid extending this delay.// This is achieved by setting either processStatus flag when the// Process' persistent reference is dropped. The only difference in the// flags is the reason the handle is unavailable, which affects the// errors returned by concurrent calls.state atomic.Uint64// Used only in modePID.sigMu sync.RWMutex // avoid race between wait and signal// handle is the OS handle for process actions, used only in// modeHandle.//// handle must be accessed only via the handleTransientAcquire method// (or during closeHandle), not directly! handle is immutable.//// On Windows, it is a handle from OpenProcess.// On Linux, it is a pidfd.// It is unused on other GOOSes.handle uintptr}func ( int) *Process {:= &Process{Pid: ,mode: modePID,}runtime.SetFinalizer(, (*Process).Release)return}func ( int, uintptr) *Process {:= &Process{Pid: ,mode: modeHandle,handle: ,}.state.Store(1) // 1 persistent referenceruntime.SetFinalizer(, (*Process).Release)return}func ( int) *Process {:= &Process{Pid: ,mode: modeHandle,// N.B Since we set statusDone, handle will never actually be// used, so its value doesn't matter.}.state.Store(uint64(statusDone)) // No persistent reference, as there is no handle.runtime.SetFinalizer(, (*Process).Release)return}func ( *Process) () (uintptr, processStatus) {if .mode != modeHandle {panic("handleTransientAcquire called in invalid mode")}for {:= .state.Load()if &processStatusMask != 0 {return 0, processStatus( & processStatusMask)}:= + 1if !.state.CompareAndSwap(, ) {continue}return .handle, statusOK}}func ( *Process) () {if .mode != modeHandle {panic("handleTransientRelease called in invalid mode")}for {:= .state.Load():= &^ processStatusMask:= processStatus( & processStatusMask)if == 0 {// This should never happen because// handleTransientRelease is always paired with// handleTransientAcquire.panic("release of handle with refcount 0")}if == 1 && == statusOK {// Process holds a persistent reference and always sets// a status when releasing that reference// (handlePersistentRelease). Thus something has gone// wrong if this is the last release but a status has// not always been set.panic("final release of handle without processStatus")}:= - 1if !.state.CompareAndSwap(, ) {continue}if &^processStatusMask == 0 {.closeHandle()}return}}// Drop the Process' persistent reference on the handle, deactivating future// Wait/Signal calls with the passed reason.//// Returns the status prior to this call. If this is not statusOK, then the// reference was not dropped or status changed.func ( *Process) ( processStatus) processStatus {if .mode != modeHandle {panic("handlePersistentRelease called in invalid mode")}for {:= .state.Load():= processStatus( & processStatusMask)if != statusOK {// Both Release and successful Wait will drop the// Process' persistent reference on the handle. We// can't allow concurrent calls to drop the reference// twice, so we use the status as a guard to ensure the// reference is dropped exactly once.return}if == 0 {// This should never happen because dropping the// persistent reference always sets a status.panic("release of handle with refcount 0")}:= ( - 1) | uint64()if !.state.CompareAndSwap(, ) {continue}if &^processStatusMask == 0 {.closeHandle()}return}}func ( *Process) () processStatus {if .mode != modePID {panic("pidStatus called in invalid mode")}return processStatus(.state.Load())}func ( *Process) ( processStatus) {if .mode != modePID {panic("pidDeactivate called in invalid mode")}// Both Release and successful Wait will deactivate the PID. Only one// of those should win, so nothing left to do here if the compare// fails.//// N.B. This means that results can be inconsistent. e.g., with a// racing Release and Wait, Wait may successfully wait on the process,// returning the wait status, while future calls error with "process// released" rather than "process done"..state.CompareAndSwap(0, uint64())}// ProcAttr holds the attributes that will be applied to a new process// started by StartProcess.type ProcAttr struct {// If Dir is non-empty, the child changes into the directory before// creating the process.Dir string// If Env is non-nil, it gives the environment variables for the// new process in the form returned by Environ.// If it is nil, the result of Environ will be used.Env []string// Files specifies the open files inherited by the new process. The// first three entries correspond to standard input, standard output, and// standard error. An implementation may support additional entries,// depending on the underlying operating system. A nil entry corresponds// to that file being closed when the process starts.// On Unix systems, StartProcess will change these File values// to blocking mode, which means that SetDeadline will stop working// and calling Close will not interrupt a Read or Write.Files []*File// Operating system-specific process creation attributes.// Note that setting this field means that your program// may not execute properly or even compile on some// operating systems.Sys *syscall.SysProcAttr}// A Signal represents an operating system signal.// The usual underlying implementation is operating system-dependent:// on Unix it is syscall.Signal.type Signal interface {String() stringSignal() // to distinguish from other Stringers}// Getpid returns the process id of the caller.func () int { return syscall.Getpid() }// Getppid returns the process id of the caller's parent.func () int { return syscall.Getppid() }// FindProcess looks for a running process by its pid.//// The [Process] it returns can be used to obtain information// about the underlying operating system process.//// On Unix systems, FindProcess always succeeds and returns a Process// for the given pid, regardless of whether the process exists. To test whether// the process actually exists, see whether p.Signal(syscall.Signal(0)) reports// an error.func ( int) (*Process, error) {return findProcess()}// StartProcess starts a new process with the program, arguments and attributes// specified by name, argv and attr. The argv slice will become [os.Args] in the// new process, so it normally starts with the program name.//// If the calling goroutine has locked the operating system thread// with [runtime.LockOSThread] and modified any inheritable OS-level// thread state (for example, Linux or Plan 9 name spaces), the new// process will inherit the caller's thread state.//// StartProcess is a low-level interface. The [os/exec] package provides// higher-level interfaces.//// If there is an error, it will be of type [*PathError].func ( string, []string, *ProcAttr) (*Process, error) {testlog.Open()return startProcess(, , )}// Release releases any resources associated with the [Process] p,// rendering it unusable in the future.// Release only needs to be called if [Process.Wait] is not.func ( *Process) () error {// Note to future authors: the Release API is cursed.//// On Unix and Plan 9, Release sets p.Pid = -1. This is the only part of the// Process API that is not thread-safe, but it can't be changed now.//// On Windows, Release does _not_ modify p.Pid.//// On Windows, Wait calls Release after successfully waiting to// proactively clean up resources.//// On Unix and Plan 9, Wait also proactively cleans up resources, but// can not call Release, as Wait does not set p.Pid = -1.//// On Unix and Plan 9, calling Release a second time has no effect.//// On Windows, calling Release a second time returns EINVAL.return .release()}// Kill causes the [Process] to exit immediately. Kill does not wait until// the Process has actually exited. This only kills the Process itself,// not any other processes it may have started.func ( *Process) () error {return .kill()}// Wait waits for the [Process] to exit, and then returns a// ProcessState describing its status and an error, if any.// Wait releases any resources associated with the Process.// On most operating systems, the Process must be a child// of the current process or an error will be returned.func ( *Process) () (*ProcessState, error) {return .wait()}// Signal sends a signal to the [Process].// Sending [Interrupt] on Windows is not implemented.func ( *Process) ( Signal) error {return .signal()}// UserTime returns the user CPU time of the exited process and its children.func ( *ProcessState) () time.Duration {return .userTime()}// SystemTime returns the system CPU time of the exited process and its children.func ( *ProcessState) () time.Duration {return .systemTime()}// Exited reports whether the program has exited.// On Unix systems this reports true if the program exited due to calling exit,// but false if the program terminated due to a signal.func ( *ProcessState) () bool {return .exited()}// Success reports whether the program exited successfully,// such as with exit status 0 on Unix.func ( *ProcessState) () bool {return .success()}// Sys returns system-dependent exit information about// the process. Convert it to the appropriate underlying// type, such as [syscall.WaitStatus] on Unix, to access its contents.func ( *ProcessState) () any {return .sys()}// SysUsage returns system-dependent resource usage information about// the exited process. Convert it to the appropriate underlying// type, such as [*syscall.Rusage] on Unix, to access its contents.// (On Unix, *syscall.Rusage matches struct rusage as defined in the// getrusage(2) manual page.)func ( *ProcessState) () any {return .sysUsage()}
|  | The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |