hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mos/exec/+linux.ha | 33+++++++++++++++++++++++++++------
Mos/exec/cmd.ha | 7+++++--
Art/+linux/+aarch64.ha | 22++++++++++++++++++++++
Art/+linux/+x86_64.ha | 22++++++++++++++++++++++
Mrt/+linux/syscalls.ha | 19+++++++++----------
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,