diff options
Diffstat (limited to 'src/os/exec_linux.go')
-rw-r--r-- | src/os/exec_linux.go | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/os/exec_linux.go b/src/os/exec_linux.go new file mode 100644 index 000000000..58ee79cc8 --- /dev/null +++ b/src/os/exec_linux.go @@ -0,0 +1,103 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && !baremetal && !tinygo.wasm + +package os + +import ( + "errors" + "runtime" + "syscall" +) + +// The only signal values guaranteed to be present in the os package on all +// systems are os.Interrupt (send the process an interrupt) and os.Kill (force +// the process to exit). On Windows, sending os.Interrupt to a process with +// os.Process.Signal is not implemented; it will return an error instead of +// sending a signal. +var ( + Interrupt Signal = syscall.SIGINT + Kill Signal = syscall.SIGKILL +) + +// Keep compatible with golang and always succeed and return new proc with pid on Linux. +func findProcess(pid int) (*Process, error) { + return &Process{Pid: pid}, nil +} + +func (p *Process) release() error { + // NOOP for unix. + p.Pid = -1 + // no need for a finalizer anymore + runtime.SetFinalizer(p, nil) + return nil +} + +// This function is a wrapper around the forkExec function, which is a wrapper around the fork and execve system calls. +// 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. +// It thereby replaces the newly created process with the specified command and arguments. +// Differences to upstream golang implementation (https://cs.opensource.google/go/go/+/master:src/syscall/exec_unix.go;l=143): +// * No setting of Process Attributes +// * Ignoring Ctty +// * No ForkLocking (might be introduced by #4273) +// * No parent-child communication via pipes (TODO) +// * No waiting for crashes child processes to prohibit zombie process accumulation / Wait status checking (TODO) +func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { + if argv == nil { + return 0, errors.New("exec: no argv") + } + + if len(argv) == 0 { + return 0, errors.New("exec: no argv") + } + + if attr == nil { + attr = new(ProcAttr) + } + + p, err := fork() + pid = int(p) + + if err != nil { + return 0, err + } + + // else code runs in child, which then should exec the new process + err = execve(argv0, argv, attr.Env) + if err != nil { + // exec failed + return 0, err + } + // 3. TODO: use pipes to communicate back child status + return pid, nil +} + +// In Golang, the idiomatic way to create a new process is to use the StartProcess function. +// Since the Model of operating system processes in tinygo differs from the one in Golang, we need to implement the StartProcess function differently. +// The startProcess function is a wrapper around the forkExec function, which is a wrapper around the fork and execve system calls. +// 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. +// It thereby replaces the newly created process with the specified command and arguments. +func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { + if attr != nil { + if attr.Dir != "" { + return nil, ErrNotImplementedDir + } + + if attr.Sys != nil { + return nil, ErrNotImplementedSys + } + + if len(attr.Files) != 0 { + return nil, ErrNotImplementedFiles + } + } + + pid, err := forkExec(name, argv, attr) + if err != nil { + return nil, err + } + + return findProcess(pid) +} |