| | |
| | |
| | |
| |
|
| | package os |
| |
|
| | import ( |
| | "internal/strconv" |
| | "syscall" |
| | "time" |
| | ) |
| |
|
| | |
| | |
| | |
| | |
| | var ( |
| | Interrupt Signal = syscall.Note("interrupt") |
| | Kill Signal = syscall.Note("kill") |
| | ) |
| |
|
| | func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { |
| | sysattr := &syscall.ProcAttr{ |
| | Dir: attr.Dir, |
| | Env: attr.Env, |
| | Sys: attr.Sys, |
| | } |
| |
|
| | sysattr.Files = make([]uintptr, 0, len(attr.Files)) |
| | for _, f := range attr.Files { |
| | sysattr.Files = append(sysattr.Files, f.Fd()) |
| | } |
| |
|
| | pid, _, e := syscall.StartProcess(name, argv, sysattr) |
| | if e != nil { |
| | return nil, &PathError{Op: "fork/exec", Path: name, Err: e} |
| | } |
| |
|
| | return newPIDProcess(pid), nil |
| | } |
| |
|
| | func (p *Process) writeProcFile(file string, data string) error { |
| | f, e := OpenFile("/proc/"+strconv.Itoa(p.Pid)+"/"+file, O_WRONLY, 0) |
| | if e != nil { |
| | return e |
| | } |
| | defer f.Close() |
| | _, e = f.Write([]byte(data)) |
| | return e |
| | } |
| |
|
| | func (p *Process) signal(sig Signal) error { |
| | switch p.pidStatus() { |
| | case statusDone: |
| | return ErrProcessDone |
| | case statusReleased: |
| | return syscall.ENOENT |
| | } |
| |
|
| | if e := p.writeProcFile("note", sig.String()); e != nil { |
| | return NewSyscallError("signal", e) |
| | } |
| | return nil |
| | } |
| |
|
| | func (p *Process) kill() error { |
| | return p.signal(Kill) |
| | } |
| |
|
| | func (p *Process) wait() (ps *ProcessState, err error) { |
| | var waitmsg syscall.Waitmsg |
| |
|
| | switch p.pidStatus() { |
| | case statusReleased: |
| | return nil, ErrInvalid |
| | } |
| |
|
| | err = syscall.WaitProcess(p.Pid, &waitmsg) |
| | if err != nil { |
| | return nil, NewSyscallError("wait", err) |
| | } |
| |
|
| | p.doRelease(statusDone) |
| | ps = &ProcessState{ |
| | pid: waitmsg.Pid, |
| | status: &waitmsg, |
| | } |
| | return ps, nil |
| | } |
| |
|
| | func (p *Process) withHandle(_ func(handle uintptr)) error { |
| | return ErrNoHandle |
| | } |
| |
|
| | func findProcess(pid int) (p *Process, err error) { |
| | |
| | return newPIDProcess(pid), nil |
| | } |
| |
|
| | |
| | type ProcessState struct { |
| | pid int |
| | status *syscall.Waitmsg |
| | } |
| |
|
| | |
| | func (p *ProcessState) Pid() int { |
| | return p.pid |
| | } |
| |
|
| | func (p *ProcessState) exited() bool { |
| | return p.status.Exited() |
| | } |
| |
|
| | func (p *ProcessState) success() bool { |
| | return p.status.ExitStatus() == 0 |
| | } |
| |
|
| | func (p *ProcessState) sys() any { |
| | return p.status |
| | } |
| |
|
| | func (p *ProcessState) sysUsage() any { |
| | return p.status |
| | } |
| |
|
| | func (p *ProcessState) userTime() time.Duration { |
| | return time.Duration(p.status.Time[0]) * time.Millisecond |
| | } |
| |
|
| | func (p *ProcessState) systemTime() time.Duration { |
| | return time.Duration(p.status.Time[1]) * time.Millisecond |
| | } |
| |
|
| | func (p *ProcessState) String() string { |
| | if p == nil { |
| | return "<nil>" |
| | } |
| | return "exit status: " + p.status.Msg |
| | } |
| |
|
| | |
| | |
| | func (p *ProcessState) ExitCode() int { |
| | |
| | if p == nil { |
| | return -1 |
| | } |
| | return p.status.ExitStatus() |
| | } |
| |
|