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
5package os
6
7import (
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.
18var ErrProcessDone = errors.New("os: process already finished")
19
20type processMode uint8
21
22const (
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
40type processStatus uint64
41
42const (
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].
58type 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
105func 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
114func 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
125func 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
137func (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
155func (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.
194func (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
226func (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
234func (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.
252type 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.
280type Signal interface {
281	String() string
282	Signal() // to distinguish from other Stringers
283}
284
285// Getpid returns the process id of the caller.
286func Getpid() int { return syscall.Getpid() }
287
288// Getppid returns the process id of the caller's parent.
289func 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.
300func 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].
317func 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.
325func (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.
348func (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.
357func (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.
363func (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.
368func (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.
373func (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.
380func (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.
386func (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.
393func (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.)
402func (p *ProcessState) SysUsage() any {
403	return p.sysUsage()
404}
405