hare

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

commit 568fe624fc236a2cc0f97f0a501ab4d77e66c9b1
parent 3ba88ee45d9844b414b8d40f228f0527c523152a
Author: Bor Grošelj Simić <bor.groseljsimic@telemach.net>
Date:   Fri, 18 Feb 2022 10:09:48 +0100

os::exec: expand waitpid functionality

Add os::exec::waitany that waits for whichever child terminates first
and os::exec::waitall that waits for all child processes.

Implements: https://todo.sr.ht/~sircmpwn/hare/519
Signed-off-by: Bor Grošelj Simić <bor.groseljsimic@telemach.net>

Diffstat:
Mos/exec/process+freebsd.ha | 38+++++++++++++++++++++++++++++++++++++-
Mos/exec/process+linux.ha | 38+++++++++++++++++++++++++++++++++++++-
2 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/os/exec/process+freebsd.ha b/os/exec/process+freebsd.ha @@ -1,7 +1,6 @@ use errors; use rt; use fmt; -// TODO: Add function to wait on all/any children // Stores information about a child process. export type process = int; @@ -66,6 +65,43 @@ export fn wait(proc: *process) (status | error) = { return st; }; +// Waits for the first child process to complete, then returns its process info +// and status +export fn waitany() ((process, status) | error) = { + let ru: rt::rusage = rt::rusage { ... }; + let st: status = status { ... }; + match (rt::wait4(-1, &st.status, 0, &ru)) { + case let err: rt::errno => + return errors::errno(err); + case let pid: int => + rusage(&st, &ru); + return (pid, st); + }; +}; + +// Waits for all children to terminate succesfully. If a child process exits +// with a nonzero status, returns its process info and exit status immediately, +// not waiting for the remaining children. +export fn waitall() (uint | error | !(process, exit_status)) = { + let st: status = status { ... }; + let ru: rt::rusage = rt::rusage { ... }; + for (let i = 0u; true; i += 1) match (rt::wait4(-1, &st.status, 0, &ru)) { + case let err: rt::errno => + if (err: int == rt::ECHILD) { + return i; + } else { + return errors::errno(err); + }; + case let pid: int => + match (check(&st)) { + case void => void; + case let es: !exit_status => + return (pid, es); + }; + }; + abort("unreachable"); +}; + // Checks for process completion, returning its status information on // completion, or void if it is still running. export fn peek(proc: *process) (status | void | error) = { diff --git a/os/exec/process+linux.ha b/os/exec/process+linux.ha @@ -1,7 +1,6 @@ use errors; use rt; use fmt; -// TODO: Add function to wait on all/any children // Stores information about a child process. export type process = int; @@ -52,6 +51,43 @@ export fn wait(proc: *process) (status | error) = { return st; }; +// Waits for the first child process to complete, then returns its process info +// and status +export fn waitany() ((process, status) | error) = { + let ru: rt::rusage = rt::rusage { ... }; + let st: status = status { ... }; + match (rt::wait4(-1, &st.status, 0, &ru)) { + case let err: rt::errno => + return errors::errno(err); + case let pid: int => + rusage(&st, &ru); + return (pid, st); + }; +}; + +// Waits for all children to terminate succesfully. If a child process exits +// with a nonzero status, returns its process info and exit status immediately, +// not waiting for the remaining children. +export fn waitall() (uint | error | !(process, exit_status)) = { + let st: status = status { ... }; + let ru: rt::rusage = rt::rusage { ... }; + for (let i = 0u; true; i += 1) match (rt::wait4(-1, &st.status, 0, &ru)) { + case let err: rt::errno => + if (err: int == rt::ECHILD) { + return i; + } else { + return errors::errno(err); + }; + case let pid: int => + match (check(&st)) { + case void => void; + case let es: !exit_status => + return (pid, es); + }; + }; + abort("unreachable"); +}; + // Checks for process completion, returning its status information on // completion, or void if it is still running. export fn peek(proc: *process) (status | void | error) = {