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