// ErrProcessDone indicates a [Process] has finished.
var ErrProcessDone = errors.New("os: process already finished")
+// processStatus describes the status of a [Process].
type processStatus uint32
const (
}
}
+// newPIDProcess returns a [Process] for the given PID.
func newPIDProcess(pid int) *Process {
p := &Process{
Pid: pid,
return p
}
+// newHandleProcess returns a [Process] with the given PID and handle.
func newHandleProcess(pid int, handle uintptr) *Process {
ph := &processHandle{
handle: handle,
return p
}
+// newDoneProcess returns a [Process] for the given PID
+// that is already marked as done. This is used on Unix systems
+// if the process is known to not exist.
func newDoneProcess(pid int) *Process {
p := &Process{
Pid: pid,
return p
}
+// handleTransientAcquire returns the process handle or,
+// if the process is not ready, the current status.
func (p *Process) handleTransientAcquire() (uintptr, processStatus) {
if p.handle == nil {
panic("handleTransientAcquire called in invalid mode")
return 0, status
}
+// handleTransientRelease releases a handle returned by handleTransientAcquire.
func (p *Process) handleTransientRelease() {
if p.handle == nil {
panic("handleTransientRelease called in invalid mode")
p.handle.release()
}
+// pidStatus returns the current process status.
func (p *Process) pidStatus() processStatus {
if p.handle != nil {
panic("pidStatus called in invalid mode")
// created in newHandleProcess.
if p.handle != nil {
// No need for more cleanup.
+ // We must stop the cleanup before calling release;
+ // otherwise the cleanup might run concurrently
+ // with the release, which would cause the reference
+ // counts to be invalid, causing a panic.
p.cleanup.Stop()
p.handle.release()
return uintptr(h), true
}
+// pidfdFind returns the process handle for pid.
func pidfdFind(pid int) (uintptr, error) {
if !pidfdWorks() {
return 0, syscall.ENOSYS
return h, nil
}
+// pidfdWait waits for the process to complete,
+// and updates the process status to done.
func (p *Process) pidfdWait() (*ProcessState, error) {
// When pidfd is used, there is no wait/kill race (described in CL 23967)
// because the PID recycle issue doesn't exist (IOW, pidfd, unlike PID,
}, nil
}
+// pidfdSendSignal sends a signal to the process.
func (p *Process) pidfdSendSignal(s syscall.Signal) error {
handle, status := p.handleTransientAcquire()
switch status {
return convertESRCH(unix.PidFDSendSignal(handle, s))
}
+// pidfdWorks returns whether we can use pidfd on this system.
func pidfdWorks() bool {
return checkPidfdOnce() == nil
}
+// checkPidfdOnce is used to only check whether pidfd works once.
var checkPidfdOnce = sync.OnceValue(checkPidfd)
// checkPidfd checks whether all required pidfd-related syscalls work. This