]>
Commit | Line | Data |
---|---|---|
405ca104 ILT |
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 ( | |
9c63abc9 | 8 | "errors" |
405ca104 ILT |
9 | "runtime" |
10 | "syscall" | |
501699af | 11 | "time" |
405ca104 ILT |
12 | ) |
13 | ||
4ccad563 ILT |
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). | |
17 | var ( | |
18 | Interrupt Signal = syscall.Note("interrupt") | |
19 | Kill Signal = syscall.Note("kill") | |
20 | ) | |
21 | ||
593f74bb | 22 | func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { |
405ca104 ILT |
23 | sysattr := &syscall.ProcAttr{ |
24 | Dir: attr.Dir, | |
25 | Env: attr.Env, | |
adb0401d | 26 | Sys: attr.Sys, |
405ca104 ILT |
27 | } |
28 | ||
501699af ILT |
29 | for _, f := range attr.Files { |
30 | sysattr.Files = append(sysattr.Files, f.Fd()) | |
405ca104 ILT |
31 | } |
32 | ||
405ca104 | 33 | pid, h, e := syscall.StartProcess(name, argv, sysattr) |
ab61e9c4 | 34 | if e != nil { |
405ca104 ILT |
35 | return nil, &PathError{"fork/exec", name, e} |
36 | } | |
37 | ||
38 | return newProcess(pid, h), nil | |
39 | } | |
40 | ||
4ccad563 ILT |
41 | func (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 | |
adb0401d ILT |
49 | } |
50 | ||
593f74bb | 51 | func (p *Process) signal(sig Signal) error { |
bd2e46c8 | 52 | if p.done() { |
9c63abc9 | 53 | return errors.New("os: process already finished") |
adb0401d | 54 | } |
4ccad563 ILT |
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 { | |
adb0401d ILT |
60 | return NewSyscallError("signal", e) |
61 | } | |
4ccad563 | 62 | return nil |
adb0401d ILT |
63 | } |
64 | ||
593f74bb | 65 | func (p *Process) kill() error { |
4ccad563 | 66 | if e := p.writeProcFile("ctl", "kill"); e != nil { |
adb0401d ILT |
67 | return NewSyscallError("kill", e) |
68 | } | |
4ccad563 | 69 | return nil |
adb0401d ILT |
70 | } |
71 | ||
593f74bb | 72 | func (p *Process) wait() (ps *ProcessState, err error) { |
405ca104 ILT |
73 | var waitmsg syscall.Waitmsg |
74 | ||
75 | if p.Pid == -1 { | |
501699af | 76 | return nil, ErrInvalid |
405ca104 ILT |
77 | } |
78 | ||
79 | for true { | |
80 | err = syscall.Await(&waitmsg) | |
81 | ||
ab61e9c4 | 82 | if err != nil { |
405ca104 ILT |
83 | return nil, NewSyscallError("wait", err) |
84 | } | |
85 | ||
86 | if waitmsg.Pid == p.Pid { | |
bd2e46c8 | 87 | p.setDone() |
405ca104 ILT |
88 | break |
89 | } | |
90 | } | |
91 | ||
501699af ILT |
92 | ps = &ProcessState{ |
93 | pid: waitmsg.Pid, | |
94 | status: &waitmsg, | |
405ca104 | 95 | } |
501699af | 96 | return ps, nil |
405ca104 ILT |
97 | } |
98 | ||
593f74bb | 99 | func (p *Process) release() error { |
405ca104 ILT |
100 | // NOOP for Plan 9. |
101 | p.Pid = -1 | |
102 | // no need for a finalizer anymore | |
103 | runtime.SetFinalizer(p, nil) | |
104 | return nil | |
105 | } | |
106 | ||
af92e385 | 107 | func findProcess(pid int) (p *Process, err error) { |
405ca104 ILT |
108 | // NOOP for Plan 9. |
109 | return newProcess(pid, 0), nil | |
110 | } | |
111 | ||
593f74bb | 112 | // ProcessState stores information about a process, as reported by Wait. |
501699af ILT |
113 | type ProcessState struct { |
114 | pid int // The process's id. | |
115 | status *syscall.Waitmsg // System-dependent status info. | |
116 | } | |
117 | ||
118 | // Pid returns the process id of the exited process. | |
119 | func (p *ProcessState) Pid() int { | |
120 | return p.pid | |
121 | } | |
122 | ||
593f74bb | 123 | func (p *ProcessState) exited() bool { |
501699af ILT |
124 | return p.status.Exited() |
125 | } | |
126 | ||
593f74bb | 127 | func (p *ProcessState) success() bool { |
501699af ILT |
128 | return p.status.ExitStatus() == 0 |
129 | } | |
130 | ||
593f74bb | 131 | func (p *ProcessState) sys() interface{} { |
501699af ILT |
132 | return p.status |
133 | } | |
134 | ||
593f74bb | 135 | func (p *ProcessState) sysUsage() interface{} { |
501699af ILT |
136 | return p.status |
137 | } | |
138 | ||
593f74bb | 139 | func (p *ProcessState) userTime() time.Duration { |
501699af ILT |
140 | return time.Duration(p.status.Time[0]) * time.Millisecond |
141 | } | |
142 | ||
593f74bb | 143 | func (p *ProcessState) systemTime() time.Duration { |
501699af ILT |
144 | return time.Duration(p.status.Time[1]) * time.Millisecond |
145 | } | |
146 | ||
147 | func (p *ProcessState) String() string { | |
148 | if p == nil { | |
adb0401d ILT |
149 | return "<nil>" |
150 | } | |
501699af | 151 | return "exit status: " + p.status.Msg |
405ca104 | 152 | } |