commit efc37dcbd51c4d40453065e0a27eda98a93b8893
parent f64643a121e8176ff508bd9b5d05c4e55bfba2be
Author: Drew DeVault <sir@cmpwn.com>
Date: Mon, 8 Feb 2021 14:00:12 -0500
os::exec: expand start error handling
This also removes the SIGCHLD so that we don't have to worry about
handling it later on.
Diffstat:
5 files changed, 85 insertions(+), 18 deletions(-)
diff --git a/os/exec/+linux.ha b/os/exec/+linux.ha
@@ -1,5 +1,6 @@
use rt;
use strings;
+use os;
export type platform = int;
@@ -54,15 +55,35 @@ fn platform_exec(cmd: *command) os_error = {
};
fn platform_start(cmd: *command) (os_error | void) = {
- // TODO: Set aside a pipe to fetch errno from child process if exec
- // fails
- match (rt::fork()) {
+ // TODO: Let the user configure clone more to their taste (e.g. SIGCHLD)
+ let pipe: [2]int = [0...];
+ match (rt::pipe2(&pipe, 0)) {
err: rt::errno => return errno_to_os(err),
- int => {
+ void => void,
+ };
+
+ match (rt::clone(null, 0, null, null, 0u64)) {
+ err: rt::errno => return errno_to_os(err),
+ pid: int => {
// TODO: Fill in some kind of process structure
+ rt::close(pipe[1]);
+ let errno: int = 0;
+ match (rt::read(pipe[0], &errno, size(int))) {
+ err: rt::errno => return errno_to_os(err),
+ n: size => switch (n) {
+ size(int) => return errno_to_os(errno),
+ * => abort("Unexpected rt::read result"),
+ 0z => void,
+ },
+ };
return;
},
- void => void,
+ void => {
+ rt::close(pipe[0]);
+ let err = platform_exec(cmd);
+ let errno = err.data: uintptr: int;
+ rt::write(pipe[1], &errno, size(int));
+ rt::exit(1);
+ },
};
- platform_exec(cmd);
};
diff --git a/os/exec/cmd.ha b/os/exec/cmd.ha
@@ -69,9 +69,12 @@ export fn exec(cmd: *command) os_error = platform_exec(cmd);
// Starts a prepared command in a new process and calls [finish] on the command.
//
// TODO: Return a handle which gives information about the new process.
-export fn start(cmd: *command) (os_error | void) = {
+export fn start(cmd: *command) (error | void) = {
defer finish(cmd);
- platform_start(cmd);
+ return match (platform_start(cmd)) {
+ err: os_error => err,
+ void => void,
+ };
};
fn lookup(name: str) (platform | void) = {
diff --git a/rt/+linux/+aarch64.ha b/rt/+linux/+aarch64.ha
@@ -0,0 +1,22 @@
+// Returns the new PID to the parent, void to the child, or errno if something
+// goes wrong.
+export fn clone(
+ stack: nullable *void,
+ flags: int,
+ parent_tid: nullable *int,
+ child_tid: nullable *int,
+ tls: u64,
+) (int | void | errno) = {
+ return match (wrap_return(syscall5(SYS_clone,
+ flags: u64,
+ stack: uintptr: u64,
+ parent_tid: uintptr: u64,
+ tls,
+ child_tid: uintptr: u64))) {
+ u: u64 => switch (u) {
+ 0u64 => void,
+ * => u: int,
+ },
+ err: errno => err,
+ };
+};
diff --git a/rt/+linux/+x86_64.ha b/rt/+linux/+x86_64.ha
@@ -0,0 +1,22 @@
+// Returns the new PID to the parent, void to the child, or errno if something
+// goes wrong.
+export fn clone(
+ stack: nullable *void,
+ flags: int,
+ parent_tid: nullable *int,
+ child_tid: nullable *int,
+ tls: u64,
+) (int | void | errno) = {
+ return match (wrap_return(syscall5(SYS_clone,
+ flags: u64,
+ stack: uintptr: u64,
+ parent_tid: uintptr: u64,
+ child_tid: uintptr: u64,
+ tls))) {
+ u: u64 => switch (u) {
+ 0u64 => void,
+ * => u: int,
+ },
+ err: errno => err,
+ };
+};
diff --git a/rt/+linux/syscalls.ha b/rt/+linux/syscalls.ha
@@ -49,15 +49,7 @@ export fn execveat(dirfd: int, path: *const char, argv: *[*]nullable *const char
// Returns the new PID to the parent, void to the child, or errno if something
// goes wrong.
-export fn fork() (int | void | errno) = {
- return match (wrap_return(syscall2(SYS_clone, SIGCHLD: u64, 0u64))) {
- u: u64 => switch (u) {
- 0u64 => void,
- * => u: int,
- },
- err: errno => err,
- };
-};
+export fn fork() (int | void | errno) = clone(null, SIGCHLD, null, null, 0u64);
export fn getpid() int = syscall0(SYS_getpid): int;
@@ -72,7 +64,6 @@ export fn sendfile(
err: errno => err,
};
-
export @noreturn fn exit(status: int) void = syscall1(SYS_exit, status: u64);
export fn kill(pid: int, signal: int) (void | errno) = {
@@ -82,6 +73,14 @@ export fn kill(pid: int, signal: int) (void | errno) = {
};
};
+export fn pipe2(pipefd: *[2]int, flags: int) (void | errno) = {
+ return match (wrap_return(syscall2(SYS_pipe2,
+ pipefd: uintptr: u64, flags: u64))) {
+ err: errno => err,
+ u64 => void,
+ };
+};
+
export fn mmap(
addr: nullable *void,
length: size,