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 //go:build linux && !baremetal && !moxie.wasm && !nintendoswitch
6 7 package os
8 9 import (
10 "errors"
11 "runtime"
12 "syscall"
13 )
14 15 // The only signal values guaranteed to be present in the os package on all
16 // systems are os.Interrupt (send the process an interrupt) and os.Kill (force
17 // the process to exit). On Windows, sending os.Interrupt to a process with
18 // os.Process.Signal is not implemented; it will return an error instead of
19 // sending a signal.
20 var (
21 Interrupt Signal = syscall.SIGINT
22 Kill Signal = syscall.SIGKILL
23 )
24 25 // Keep compatible with golang and always succeed and return new proc with pid on Linux.
26 func findProcess(pid int) (*Process, error) {
27 return &Process{Pid: pid}, nil
28 }
29 30 func (p *Process) release() error {
31 // NOOP for unix.
32 p.Pid = -1
33 // no need for a finalizer anymore
34 runtime.SetFinalizer(p, nil)
35 return nil
36 }
37 38 // This function is a wrapper around the forkExec function, which is a wrapper around the fork and execve system calls.
39 // The StartProcess function creates a new process by forking the current process and then calling execve to replace the current process with the new process.
40 // It thereby replaces the newly created process with the specified command and arguments.
41 // Differences to upstream golang implementation (https://cs.opensource.google/go/go/+/master:src/syscall/exec_unix.go;l=143):
42 // * No setting of Process Attributes
43 // * Ignoring Ctty
44 // * No ForkLocking (might be introduced by #4273)
45 // * No parent-child communication via pipes (TODO)
46 // * No waiting for crashes child processes to prohibit zombie process accumulation / Wait status checking (TODO)
47 func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
48 if argv == nil {
49 return 0, errors.New("exec: no argv")
50 }
51 52 if len(argv) == 0 {
53 return 0, errors.New("exec: no argv")
54 }
55 56 if attr == nil {
57 attr = new(ProcAttr)
58 }
59 60 p, err := fork()
61 if err != nil {
62 return 0, err
63 }
64 65 if p == 0 {
66 // Child process: replace with the new binary.
67 err = execve(argv0, argv, attr.Env)
68 // execve only returns on failure — child must exit to avoid
69 // two copies of the parent running.
70 libc_exit(127)
71 // unreachable
72 }
73 74 // Parent process: return child PID.
75 return int(p), nil
76 }
77 78 // In Golang, the idiomatic way to create a new process is to use the StartProcess function.
79 // Since the Model of operating system processes in moxie differs from the one in Golang, we need to implement the StartProcess function differently.
80 // The startProcess function is a wrapper around the forkExec function, which is a wrapper around the fork and execve system calls.
81 // The StartProcess function creates a new process by forking the current process and then calling execve to replace the current process with the new process.
82 // It thereby replaces the newly created process with the specified command and arguments.
83 func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
84 if attr != nil {
85 if attr.Dir != "" {
86 return nil, ErrNotImplementedDir
87 }
88 89 if attr.Sys != nil {
90 return nil, ErrNotImplementedSys
91 }
92 93 if len(attr.Files) != 0 {
94 return nil, ErrNotImplementedFiles
95 }
96 }
97 98 pid, err := forkExec(name, argv, attr)
99 if err != nil {
100 return nil, err
101 }
102 103 return findProcess(pid)
104 }
105