Home | History | Annotate | Download | only in os
      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 (
      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).
     17 var (
     18 	Interrupt Signal = syscall.Note("interrupt")
     19 	Kill      Signal = syscall.Note("kill")
     20 )
     21 
     22 func 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 
     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
     49 }
     50 
     51 func (p *Process) signal(sig Signal) error {
     52 	if p.done() {
     53 		return errors.New("os: process already finished")
     54 	}
     55 	if e := p.writeProcFile("note", sig.String()); e != nil {
     56 		return NewSyscallError("signal", e)
     57 	}
     58 	return nil
     59 }
     60 
     61 func (p *Process) kill() error {
     62 	return p.signal(Kill)
     63 }
     64 
     65 func (p *Process) wait() (ps *ProcessState, err error) {
     66 	var waitmsg syscall.Waitmsg
     67 
     68 	if p.Pid == -1 {
     69 		return nil, ErrInvalid
     70 	}
     71 	err = syscall.WaitProcess(p.Pid, &waitmsg)
     72 	if err != nil {
     73 		return nil, NewSyscallError("wait", err)
     74 	}
     75 
     76 	p.setDone()
     77 	ps = &ProcessState{
     78 		pid:    waitmsg.Pid,
     79 		status: &waitmsg,
     80 	}
     81 	return ps, nil
     82 }
     83 
     84 func (p *Process) release() error {
     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 
     92 func findProcess(pid int) (p *Process, err error) {
     93 	// NOOP for Plan 9.
     94 	return newProcess(pid, 0), nil
     95 }
     96 
     97 // ProcessState stores information about a process, as reported by Wait.
     98 type ProcessState struct {
     99 	pid    int              // The process's id.
    100 	status *syscall.Waitmsg // System-dependent status info.
    101 }
    102 
    103 // Pid returns the process id of the exited process.
    104 func (p *ProcessState) Pid() int {
    105 	return p.pid
    106 }
    107 
    108 func (p *ProcessState) exited() bool {
    109 	return p.status.Exited()
    110 }
    111 
    112 func (p *ProcessState) success() bool {
    113 	return p.status.ExitStatus() == 0
    114 }
    115 
    116 func (p *ProcessState) sys() interface{} {
    117 	return p.status
    118 }
    119 
    120 func (p *ProcessState) sysUsage() interface{} {
    121 	return p.status
    122 }
    123 
    124 func (p *ProcessState) userTime() time.Duration {
    125 	return time.Duration(p.status.Time[0]) * time.Millisecond
    126 }
    127 
    128 func (p *ProcessState) systemTime() time.Duration {
    129 	return time.Duration(p.status.Time[1]) * time.Millisecond
    130 }
    131 
    132 func (p *ProcessState) String() string {
    133 	if p == nil {
    134 		return "<nil>"
    135 	}
    136 	return "exit status: " + p.status.Msg
    137 }
    138