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:
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) = {