-
Notifications
You must be signed in to change notification settings - Fork 918
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: leongross <leon.gross@9elements.com>
- Loading branch information
Showing
10 changed files
with
295 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
//go:build linux && !baremetal && !tinygo.wasm | ||
|
||
package os_test | ||
|
||
import ( | ||
"errors" | ||
. "os" | ||
"runtime" | ||
"syscall" | ||
"testing" | ||
) | ||
|
||
// Test the functionality of the forkExec function, which is used to fork and exec a new process. | ||
// This test is not run on Windows, as forkExec is not supported on Windows. | ||
// This test is not run on Plan 9, as forkExec is not supported on Plan 9. | ||
func TestForkExec(t *testing.T) { | ||
if runtime.GOOS != "linux" { | ||
t.Logf("skipping test on %s", runtime.GOOS) | ||
return | ||
} | ||
|
||
proc, err := StartProcess("/bin/echo", []string{"hello", "world"}, &ProcAttr{}) | ||
if !errors.Is(err, nil) { | ||
t.Fatalf("forkExec failed: %v", err) | ||
} | ||
|
||
if proc == nil { | ||
t.Fatalf("proc is nil") | ||
} | ||
|
||
if proc.Pid == 0 { | ||
t.Fatalf("forkExec failed: new process has pid 0") | ||
} | ||
} | ||
|
||
func TestForkExecErrNotExist(t *testing.T) { | ||
proc, err := StartProcess("invalid", []string{"invalid"}, &ProcAttr{}) | ||
if !errors.Is(err, ErrNotExist) { | ||
t.Fatalf("wanted ErrNotExist, got %s\n", err) | ||
} | ||
|
||
if proc != nil { | ||
t.Fatalf("wanted nil, got %v\n", proc) | ||
} | ||
} | ||
|
||
func TestForkExecProcDir(t *testing.T) { | ||
proc, err := StartProcess("/bin/echo", []string{"hello", "world"}, &ProcAttr{Dir: "dir"}) | ||
if !errors.Is(err, ErrNotImplementedDir) { | ||
t.Fatalf("wanted ErrNotImplementedDir, got %v\n", err) | ||
} | ||
|
||
if proc != nil { | ||
t.Fatalf("wanted nil, got %v\n", proc) | ||
} | ||
} | ||
|
||
func TestForkExecProcSys(t *testing.T) { | ||
proc, err := StartProcess("/bin/echo", []string{"hello", "world"}, &ProcAttr{Sys: &syscall.SysProcAttr{}}) | ||
if !errors.Is(err, ErrNotImplementedSys) { | ||
t.Fatalf("wanted ErrNotImplementedSys, got %v\n", err) | ||
} | ||
|
||
if proc != nil { | ||
t.Fatalf("wanted nil, got %v\n", proc) | ||
} | ||
} | ||
|
||
func TestForkExecProcFiles(t *testing.T) { | ||
proc, err := StartProcess("/bin/echo", []string{"hello", "world"}, &ProcAttr{Files: []*File{}}) | ||
if !errors.Is(err, ErrNotImplementedFiles) { | ||
t.Fatalf("wanted ErrNotImplementedFiles, got %v\n", err) | ||
} | ||
|
||
if proc != nil { | ||
t.Fatalf("wanted nil, got %v\n", proc) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
//go:build (!aix && !android && !freebsd && !linux && !netbsd && !openbsd && !plan9 && !solaris) || baremetal || tinygo.wasm | ||
|
||
package os | ||
|
||
import "syscall" | ||
|
||
var ( | ||
Interrupt Signal = syscall.SIGINT | ||
Kill Signal = syscall.SIGKILL | ||
) | ||
|
||
func findProcess(pid int) (*Process, error) { | ||
return &Process{Pid: pid}, nil | ||
} | ||
|
||
func (p *Process) release() error { | ||
p.Pid = -1 | ||
return nil | ||
} | ||
|
||
func forkExec(_ string, _ []string, _ *ProcAttr) (pid int, err error) { | ||
return 0, ErrNotImplemented | ||
} | ||
|
||
func startProcess(_ string, _ []string, _ *ProcAttr) (proc *Process, err error) { | ||
return &Process{Pid: 0}, ErrNotImplemented | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
//go:build linux && !baremetal && !tinygo.wasm | ||
|
||
package os | ||
|
||
import ( | ||
"syscall" | ||
"unsafe" | ||
) | ||
|
||
func fork() (pid int32, err error) { | ||
pid = libc_fork() | ||
if pid != 0 { | ||
if errno := *libc_errno(); errno != 0 { | ||
err = syscall.Errno(*libc_errno()) | ||
} | ||
} | ||
return | ||
} | ||
|
||
// the golang standard library does not expose interfaces for execve and fork, so we define them here the same way via the libc wrapper | ||
func execve(pathname string, argv []string, envv []string) error { | ||
argv0 := cstring(pathname) | ||
|
||
// transform argv and envv into the format expected by execve | ||
argv1 := make([]*byte, len(argv)+1) | ||
for i, arg := range argv { | ||
argv1[i] = &cstring(arg)[0] | ||
} | ||
argv1[len(argv)] = nil | ||
|
||
env1 := make([]*byte, len(envv)+1) | ||
for i, env := range envv { | ||
env1[i] = &cstring(env)[0] | ||
} | ||
env1[len(envv)] = nil | ||
|
||
ret, _, err := syscall.Syscall(syscall.SYS_EXECVE, uintptr(unsafe.Pointer(&argv0[0])), uintptr(unsafe.Pointer(&argv1[0])), uintptr(unsafe.Pointer(&env1[0]))) | ||
if int(ret) != 0 { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func cstring(s string) []byte { | ||
data := make([]byte, len(s)+1) | ||
copy(data, s) | ||
// final byte should be zero from the initial allocation | ||
return data | ||
} | ||
|
||
//export fork | ||
func libc_fork() int32 | ||
|
||
// Internal musl function to get the C errno pointer. | ||
// | ||
//export __errno_location | ||
func libc_errno() *int32 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
//go:build linux || unix | ||
|
||
package syscall | ||
|
||
func Exec(argv0 string, argv []string, envv []string) (err error) | ||
|