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, _, 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 newPIDProcess(pid), 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  	switch p.pidStatus() {
    55  	case statusDone:
    56  		return ErrProcessDone
    57  	case statusReleased:
    58  		return syscall.ENOENT
    59  	}
    60  
    61  	if e := p.writeProcFile("note", sig.String()); e != nil {
    62  		return NewSyscallError("signal", e)
    63  	}
    64  	return nil
    65  }
    66  
    67  func (p *Process) kill() error {
    68  	return p.signal(Kill)
    69  }
    70  
    71  func (p *Process) wait() (ps *ProcessState, err error) {
    72  	var waitmsg syscall.Waitmsg
    73  
    74  	switch p.pidStatus() {
    75  	case statusReleased:
    76  		return nil, ErrInvalid
    77  	}
    78  
    79  	err = syscall.WaitProcess(p.Pid, &waitmsg)
    80  	if err != nil {
    81  		return nil, NewSyscallError("wait", err)
    82  	}
    83  
    84  	p.pidDeactivate(statusDone)
    85  	ps = &ProcessState{
    86  		pid:    waitmsg.Pid,
    87  		status: &waitmsg,
    88  	}
    89  	return ps, nil
    90  }
    91  
    92  func (p *Process) release() error {
    93  	p.Pid = -1
    94  
    95  	// Just mark the PID unusable.
    96  	p.pidDeactivate(statusReleased)
    97  
    98  	// no need for a finalizer anymore
    99  	runtime.SetFinalizer(p, nil)
   100  	return nil
   101  }
   102  
   103  func findProcess(pid int) (p *Process, err error) {
   104  	// NOOP for Plan 9.
   105  	return newPIDProcess(pid), nil
   106  }
   107  
   108  // ProcessState stores information about a process, as reported by Wait.
   109  type ProcessState struct {
   110  	pid    int              // The process's id.
   111  	status *syscall.Waitmsg // System-dependent status info.
   112  }
   113  
   114  // Pid returns the process id of the exited process.
   115  func (p *ProcessState) Pid() int {
   116  	return p.pid
   117  }
   118  
   119  func (p *ProcessState) exited() bool {
   120  	return p.status.Exited()
   121  }
   122  
   123  func (p *ProcessState) success() bool {
   124  	return p.status.ExitStatus() == 0
   125  }
   126  
   127  func (p *ProcessState) sys() any {
   128  	return p.status
   129  }
   130  
   131  func (p *ProcessState) sysUsage() any {
   132  	return p.status
   133  }
   134  
   135  func (p *ProcessState) userTime() time.Duration {
   136  	return time.Duration(p.status.Time[0]) * time.Millisecond
   137  }
   138  
   139  func (p *ProcessState) systemTime() time.Duration {
   140  	return time.Duration(p.status.Time[1]) * time.Millisecond
   141  }
   142  
   143  func (p *ProcessState) String() string {
   144  	if p == nil {
   145  		return "<nil>"
   146  	}
   147  	return "exit status: " + p.status.Msg
   148  }
   149  
   150  // ExitCode returns the exit code of the exited process, or -1
   151  // if the process hasn't exited or was terminated by a signal.
   152  func (p *ProcessState) ExitCode() int {
   153  	// return -1 if the process hasn't started.
   154  	if p == nil {
   155  		return -1
   156  	}
   157  	return p.status.ExitStatus()
   158  }
   159  

View as plain text