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	"runtime"
10	"syscall"
11	"time"
12)
13
14// The only signal values guaranteed to be present on all systems
15// are Interrupt (send the process an interrupt) and Kill (force
16// the process to exit).
17var (
18	Interrupt Signal = syscall.Note("interrupt")
19	Kill      Signal = syscall.Note("kill")
20)
21
22func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
23	sysattr := &syscall.ProcAttr{
24		Dir: attr.Dir,
25		Env: attr.Env,
26		Sys: attr.Sys,
27	}
28
29	for _, f := range attr.Files {
30		sysattr.Files = append(sysattr.Files, f.Fd())
31	}
32
33	pid, h, e := syscall.StartProcess(name, argv, sysattr)
34	if e != nil {
35		return nil, &PathError{"fork/exec", name, e}
36	}
37
38	return newProcess(pid, h), nil
39}
40
41func (p *Process) writeProcFile(file string, data string) error {
42	f, e := OpenFile("/proc/"+itoa(p.Pid)+"/"+file, O_WRONLY, 0)
43	if e != nil {
44		return e
45	}
46	defer f.Close()
47	_, e = f.Write([]byte(data))
48	return e
49}
50
51func (p *Process) signal(sig Signal) error {
52	if p.done() {
53		return errors.New("os: process already finished")
54	}
55	if sig == Kill {
56		// Special-case the kill signal since it doesn't use /proc/$pid/note.
57		return p.Kill()
58	}
59	if e := p.writeProcFile("note", sig.String()); e != nil {
60		return NewSyscallError("signal", e)
61	}
62	return nil
63}
64
65func (p *Process) kill() error {
66	if e := p.writeProcFile("ctl", "kill"); e != nil {
67		return NewSyscallError("kill", e)
68	}
69	return nil
70}
71
72func (p *Process) wait() (ps *ProcessState, err error) {
73	var waitmsg syscall.Waitmsg
74
75	if p.Pid == -1 {
76		return nil, ErrInvalid
77	}
78	err = syscall.WaitProcess(p.Pid, &waitmsg)
79	if err != nil {
80		return nil, NewSyscallError("wait", err)
81	}
82
83	p.setDone()
84	ps = &ProcessState{
85		pid:    waitmsg.Pid,
86		status: &waitmsg,
87	}
88	return ps, nil
89}
90
91func (p *Process) release() error {
92	// NOOP for Plan 9.
93	p.Pid = -1
94	// no need for a finalizer anymore
95	runtime.SetFinalizer(p, nil)
96	return nil
97}
98
99func findProcess(pid int) (p *Process, err error) {
100	// NOOP for Plan 9.
101	return newProcess(pid, 0), nil
102}
103
104// ProcessState stores information about a process, as reported by Wait.
105type ProcessState struct {
106	pid    int              // The process's id.
107	status *syscall.Waitmsg // System-dependent status info.
108}
109
110// Pid returns the process id of the exited process.
111func (p *ProcessState) Pid() int {
112	return p.pid
113}
114
115func (p *ProcessState) exited() bool {
116	return p.status.Exited()
117}
118
119func (p *ProcessState) success() bool {
120	return p.status.ExitStatus() == 0
121}
122
123func (p *ProcessState) sys() interface{} {
124	return p.status
125}
126
127func (p *ProcessState) sysUsage() interface{} {
128	return p.status
129}
130
131func (p *ProcessState) userTime() time.Duration {
132	return time.Duration(p.status.Time[0]) * time.Millisecond
133}
134
135func (p *ProcessState) systemTime() time.Duration {
136	return time.Duration(p.status.Time[1]) * time.Millisecond
137}
138
139func (p *ProcessState) String() string {
140	if p == nil {
141		return "<nil>"
142	}
143	return "exit status: " + p.status.Msg
144}
145