Source file src/os/exec_plan9.go

     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  	"internal/itoa"
     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  	sysattr.Files = make([]uintptr, 0, len(attr.Files))
    31  	for _, f := range attr.Files {
    32  		sysattr.Files = append(sysattr.Files, f.Fd())
    33  	}
    34  
    35  	pid, h, e := syscall.StartProcess(name, argv, sysattr)
    36  	if e != nil {
    37  		return nil, &PathError{Op: "fork/exec", Path: name, Err: e}
    38  	}
    39  
    40  	return newProcess(pid, h), nil
    41  }
    42  
    43  func (p *Process) writeProcFile(file string, data string) error {
    44  	f, e := OpenFile("/proc/"+itoa.Itoa(p.Pid)+"/"+file, O_WRONLY, 0)
    45  	if e != nil {
    46  		return e
    47  	}
    48  	defer f.Close()
    49  	_, e = f.Write([]byte(data))
    50  	return e
    51  }
    52  
    53  func (p *Process) signal(sig Signal) error {
    54  	if p.done() {
    55  		return ErrProcessDone
    56  	}
    57  	if e := p.writeProcFile("note", sig.String()); e != nil {
    58  		return NewSyscallError("signal", e)
    59  	}
    60  	return nil
    61  }
    62  
    63  func (p *Process) kill() error {
    64  	return p.signal(Kill)
    65  }
    66  
    67  func (p *Process) wait() (ps *ProcessState, err error) {
    68  	var waitmsg syscall.Waitmsg
    69  
    70  	if p.Pid == -1 {
    71  		return nil, ErrInvalid
    72  	}
    73  	err = syscall.WaitProcess(p.Pid, &waitmsg)
    74  	if err != nil {
    75  		return nil, NewSyscallError("wait", err)
    76  	}
    77  
    78  	p.setDone()
    79  	ps = &ProcessState{
    80  		pid:    waitmsg.Pid,
    81  		status: &waitmsg,
    82  	}
    83  	return ps, nil
    84  }
    85  
    86  func (p *Process) release() error {
    87  	// NOOP for Plan 9.
    88  	p.Pid = -1
    89  	// no need for a finalizer anymore
    90  	runtime.SetFinalizer(p, nil)
    91  	return nil
    92  }
    93  
    94  func findProcess(pid int) (p *Process, err error) {
    95  	// NOOP for Plan 9.
    96  	return newProcess(pid, 0), nil
    97  }
    98  
    99  // ProcessState stores information about a process, as reported by Wait.
   100  type ProcessState struct {
   101  	pid    int              // The process's id.
   102  	status *syscall.Waitmsg // System-dependent status info.
   103  }
   104  
   105  // Pid returns the process id of the exited process.
   106  func (p *ProcessState) Pid() int {
   107  	return p.pid
   108  }
   109  
   110  func (p *ProcessState) exited() bool {
   111  	return p.status.Exited()
   112  }
   113  
   114  func (p *ProcessState) success() bool {
   115  	return p.status.ExitStatus() == 0
   116  }
   117  
   118  func (p *ProcessState) sys() any {
   119  	return p.status
   120  }
   121  
   122  func (p *ProcessState) sysUsage() any {
   123  	return p.status
   124  }
   125  
   126  func (p *ProcessState) userTime() time.Duration {
   127  	return time.Duration(p.status.Time[0]) * time.Millisecond
   128  }
   129  
   130  func (p *ProcessState) systemTime() time.Duration {
   131  	return time.Duration(p.status.Time[1]) * time.Millisecond
   132  }
   133  
   134  func (p *ProcessState) String() string {
   135  	if p == nil {
   136  		return "<nil>"
   137  	}
   138  	return "exit status: " + p.status.Msg
   139  }
   140  
   141  // ExitCode returns the exit code of the exited process, or -1
   142  // if the process hasn't exited or was terminated by a signal.
   143  func (p *ProcessState) ExitCode() int {
   144  	// return -1 if the process hasn't started.
   145  	if p == nil {
   146  		return -1
   147  	}
   148  	return p.status.ExitStatus()
   149  }
   150  

View as plain text