Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 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 ( |
Anthony Martin | cabe0e6 | 2011-11-08 09:06:02 -0500 | [diff] [blame] | 8 | "errors" |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 9 | "runtime" |
| 10 | "syscall" |
Rob Pike | ccacab6 | 2012-02-21 14:10:34 +1100 | [diff] [blame] | 11 | "time" |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 12 | ) |
| 13 | |
Anthony Martin | fe5005f | 2012-05-04 03:44:41 -0700 | [diff] [blame] | 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 | |
Russ Cox | 30db6d4 | 2012-03-01 21:56:54 -0500 | [diff] [blame] | 22 | func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 23 | sysattr := &syscall.ProcAttr{ |
| 24 | Dir: attr.Dir, |
| 25 | Env: attr.Env, |
Russ Cox | 4d0f2e9 | 2011-06-14 10:49:34 -0400 | [diff] [blame] | 26 | Sys: attr.Sys, |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 27 | } |
| 28 | |
David du Colombier | 11f4a6c | 2012-02-16 14:04:51 -0500 | [diff] [blame] | 29 | for _, f := range attr.Files { |
| 30 | sysattr.Files = append(sysattr.Files, f.Fd()) |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 31 | } |
| 32 | |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 33 | pid, h, e := syscall.StartProcess(name, argv, sysattr) |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 34 | if e != nil { |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 35 | return nil, &PathError{"fork/exec", name, e} |
| 36 | } |
| 37 | |
| 38 | return newProcess(pid, h), nil |
| 39 | } |
| 40 | |
Anthony Martin | fe5005f | 2012-05-04 03:44:41 -0700 | [diff] [blame] | 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 |
Yuval Pavel Zholkover | 0bf36ce | 2011-07-13 16:29:37 -0700 | [diff] [blame] | 49 | } |
| 50 | |
Russ Cox | 30db6d4 | 2012-03-01 21:56:54 -0500 | [diff] [blame] | 51 | func (p *Process) signal(sig Signal) error { |
Dave Cheney | 122a558 | 2012-08-21 10:41:31 +1000 | [diff] [blame] | 52 | if p.done() { |
Anthony Martin | cabe0e6 | 2011-11-08 09:06:02 -0500 | [diff] [blame] | 53 | return errors.New("os: process already finished") |
Yuval Pavel Zholkover | 0bf36ce | 2011-07-13 16:29:37 -0700 | [diff] [blame] | 54 | } |
Anthony Martin | fe5005f | 2012-05-04 03:44:41 -0700 | [diff] [blame] | 55 | if e := p.writeProcFile("note", sig.String()); e != nil { |
Yuval Pavel Zholkover | 0bf36ce | 2011-07-13 16:29:37 -0700 | [diff] [blame] | 56 | return NewSyscallError("signal", e) |
| 57 | } |
Anthony Martin | fe5005f | 2012-05-04 03:44:41 -0700 | [diff] [blame] | 58 | return nil |
Yuval Pavel Zholkover | 0bf36ce | 2011-07-13 16:29:37 -0700 | [diff] [blame] | 59 | } |
| 60 | |
Russ Cox | 30db6d4 | 2012-03-01 21:56:54 -0500 | [diff] [blame] | 61 | func (p *Process) kill() error { |
Anthony Martin | 189397d | 2014-03-12 18:12:56 -0700 | [diff] [blame] | 62 | return p.signal(Kill) |
Yuval Pavel Zholkover | 1811243 | 2011-06-14 11:20:34 -0400 | [diff] [blame] | 63 | } |
| 64 | |
Russ Cox | 30db6d4 | 2012-03-01 21:56:54 -0500 | [diff] [blame] | 65 | func (p *Process) wait() (ps *ProcessState, err error) { |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 66 | var waitmsg syscall.Waitmsg |
| 67 | |
| 68 | if p.Pid == -1 { |
Rob Pike | 56069f0 | 2012-02-17 10:04:29 +1100 | [diff] [blame] | 69 | return nil, ErrInvalid |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 70 | } |
Akshat Kumar | b628470 | 2013-01-18 16:43:25 -0500 | [diff] [blame] | 71 | err = syscall.WaitProcess(p.Pid, &waitmsg) |
| 72 | if err != nil { |
| 73 | return nil, NewSyscallError("wait", err) |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 74 | } |
| 75 | |
Akshat Kumar | b628470 | 2013-01-18 16:43:25 -0500 | [diff] [blame] | 76 | p.setDone() |
Rob Pike | ccacab6 | 2012-02-21 14:10:34 +1100 | [diff] [blame] | 77 | ps = &ProcessState{ |
| 78 | pid: waitmsg.Pid, |
Rob Pike | 880cda5 | 2012-02-23 07:51:49 +1100 | [diff] [blame] | 79 | status: &waitmsg, |
Rob Pike | ccacab6 | 2012-02-21 14:10:34 +1100 | [diff] [blame] | 80 | } |
| 81 | return ps, nil |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 82 | } |
| 83 | |
Alex Brainman | ed238ca | 2012-03-01 17:36:35 +1100 | [diff] [blame] | 84 | func (p *Process) release() error { |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 85 | // NOOP for Plan 9. |
| 86 | p.Pid = -1 |
| 87 | // no need for a finalizer anymore |
| 88 | runtime.SetFinalizer(p, nil) |
| 89 | return nil |
| 90 | } |
| 91 | |
Alex Brainman | 994e064 | 2012-01-17 16:51:54 +1100 | [diff] [blame] | 92 | func findProcess(pid int) (p *Process, err error) { |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 93 | // NOOP for Plan 9. |
| 94 | return newProcess(pid, 0), nil |
| 95 | } |
| 96 | |
Rob Pike | 36d9ee4 | 2012-03-02 14:07:26 +1100 | [diff] [blame] | 97 | // ProcessState stores information about a process, as reported by Wait. |
Rob Pike | ccacab6 | 2012-02-21 14:10:34 +1100 | [diff] [blame] | 98 | type ProcessState struct { |
Rob Pike | 880cda5 | 2012-02-23 07:51:49 +1100 | [diff] [blame] | 99 | pid int // The process's id. |
| 100 | status *syscall.Waitmsg // System-dependent status info. |
Rob Pike | ccacab6 | 2012-02-21 14:10:34 +1100 | [diff] [blame] | 101 | } |
| 102 | |
| 103 | // Pid returns the process id of the exited process. |
| 104 | func (p *ProcessState) Pid() int { |
| 105 | return p.pid |
| 106 | } |
| 107 | |
Russ Cox | 30db6d4 | 2012-03-01 21:56:54 -0500 | [diff] [blame] | 108 | func (p *ProcessState) exited() bool { |
Rob Pike | ccacab6 | 2012-02-21 14:10:34 +1100 | [diff] [blame] | 109 | return p.status.Exited() |
| 110 | } |
| 111 | |
Russ Cox | 30db6d4 | 2012-03-01 21:56:54 -0500 | [diff] [blame] | 112 | func (p *ProcessState) success() bool { |
Rob Pike | ccacab6 | 2012-02-21 14:10:34 +1100 | [diff] [blame] | 113 | return p.status.ExitStatus() == 0 |
| 114 | } |
| 115 | |
Russ Cox | 30db6d4 | 2012-03-01 21:56:54 -0500 | [diff] [blame] | 116 | func (p *ProcessState) sys() interface{} { |
Rob Pike | 880cda5 | 2012-02-23 07:51:49 +1100 | [diff] [blame] | 117 | return p.status |
Rob Pike | ccacab6 | 2012-02-21 14:10:34 +1100 | [diff] [blame] | 118 | } |
| 119 | |
Russ Cox | 30db6d4 | 2012-03-01 21:56:54 -0500 | [diff] [blame] | 120 | func (p *ProcessState) sysUsage() interface{} { |
Rob Pike | 880cda5 | 2012-02-23 07:51:49 +1100 | [diff] [blame] | 121 | return p.status |
Rob Pike | ccacab6 | 2012-02-21 14:10:34 +1100 | [diff] [blame] | 122 | } |
| 123 | |
Russ Cox | 30db6d4 | 2012-03-01 21:56:54 -0500 | [diff] [blame] | 124 | func (p *ProcessState) userTime() time.Duration { |
Rob Pike | ccacab6 | 2012-02-21 14:10:34 +1100 | [diff] [blame] | 125 | return time.Duration(p.status.Time[0]) * time.Millisecond |
| 126 | } |
| 127 | |
Russ Cox | 30db6d4 | 2012-03-01 21:56:54 -0500 | [diff] [blame] | 128 | func (p *ProcessState) systemTime() time.Duration { |
Rob Pike | ccacab6 | 2012-02-21 14:10:34 +1100 | [diff] [blame] | 129 | return time.Duration(p.status.Time[1]) * time.Millisecond |
| 130 | } |
| 131 | |
| 132 | func (p *ProcessState) String() string { |
| 133 | if p == nil { |
Graham Miller | cf201ed | 2011-06-20 15:42:17 -0400 | [diff] [blame] | 134 | return "<nil>" |
| 135 | } |
Rob Pike | ccacab6 | 2012-02-21 14:10:34 +1100 | [diff] [blame] | 136 | return "exit status: " + p.status.Msg |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 137 | } |