diff options
author | Přemysl Eric Janouch <p@janouch.name> | 2025-01-06 14:27:53 +0100 |
---|---|---|
committer | Přemysl Eric Janouch <p@janouch.name> | 2025-01-06 14:29:41 +0100 |
commit | 37a8f1623592efbcb249d8ca0acd0c6167d37ed8 (patch) | |
tree | 24fbf880f5f613f35c5181724cf1e998e5c04f93 | |
parent | 9fe576ae9e7b641925168612b98a704967a04dd0 (diff) | |
download | liberty-37a8f1623592efbcb249d8ca0acd0c6167d37ed8.tar.gz liberty-37a8f1623592efbcb249d8ca0acd0c6167d37ed8.tar.xz liberty-37a8f1623592efbcb249d8ca0acd0c6167d37ed8.zip |
wdye: enable waiting for processes
-rw-r--r-- | tools/wdye/test.lua | 7 | ||||
-rw-r--r-- | tools/wdye/wdye.adoc | 10 | ||||
-rw-r--r-- | tools/wdye/wdye.c | 53 |
3 files changed, 69 insertions, 1 deletions
diff --git a/tools/wdye/test.lua b/tools/wdye/test.lua index 5e2fe36..c255c72 100644 --- a/tools/wdye/test.lua +++ b/tools/wdye/test.lua @@ -18,7 +18,14 @@ expect(cat:regex {"A(.*)3", nocase=true, function (p) assert(p[1] == "bc12", "wrong regex group #1") end}) +assert(not cat:wait (true), "process reports exiting early") + -- Send EOF (^D), test method chaining. cat:send("Closing...\r"):send("\004") local v = expect(cat:eof {true}, cat:default {.5, function (p) error "expected EOF, got a timeout" end}) + +local s1, exit, signal = cat:wait () +assert(s1 == 0 and exit == 0 and not signal, "unexpected exit status") +local s2 = cat:wait (true) +assert(s1 == s2, "exit status not remembered") diff --git a/tools/wdye/wdye.adoc b/tools/wdye/wdye.adoc index 6282af2..d901400 100644 --- a/tools/wdye/wdye.adoc +++ b/tools/wdye/wdye.adoc @@ -94,6 +94,16 @@ PROCESS:eof {[notransfer=true, ] [value1, ...]} Returns a new end-of-file _pattern_, which matches the entire read buffer contents once the child process closes the terminal. +PROCESS:wait ([nowait]) +~~~~~~~~~~~~~~~~~~~~~~~ +Waits for the program to terminate, and returns three values: +a combined status as used by `$?` in shells, +an exit status, and a termination signal number. +One of the latter two values will be _nil_, as appropriate. + +When the *nowait* option is _true_, the function returns immediately. +If the process hasn't terminated yet, the function then returns no values. + PROCESS:default {[timeout, ] [notransfer=true, ] [value1, ...]} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Returns a new _pattern_ combining *wdye.timeout* with *eof*. diff --git a/tools/wdye/wdye.c b/tools/wdye/wdye.c index b801c89..ece3038 100644 --- a/tools/wdye/wdye.c +++ b/tools/wdye/wdye.c @@ -431,9 +431,10 @@ static luaL_Reg xlua_pattern_table[] = struct process { int terminal_fd; ///< Process stdin/stdout/stderr - pid_t pid; ///< Process ID + pid_t pid; ///< Process ID or -1 if collected int ref_term; ///< Terminal information struct str buffer; ///< Terminal input buffer + int status; ///< Process status iff pid is -1 }; static struct process * @@ -598,6 +599,54 @@ xlua_process_default (lua_State *L) return 1; } +static int +xlua_process_wait (lua_State *L) +{ + struct process *self = luaL_checkudata (L, 1, XLUA_PROCESS_METATABLE); + bool nowait = luaL_opt(L, lua_toboolean, 2, false); + if (lua_gettop (L) > 2) + return luaL_error (L, "too many arguments"); + + int status = self->status; +restart: + if (self->pid != -1) + { + int options = 0; + if (nowait) + options |= WNOHANG; + + pid_t pid = waitpid (self->pid, &status, options); + if (!pid) + return 0; + + if (pid < 0) + { + if (errno == EINTR) + goto restart; + return luaL_error (L, "waitpid: %s", strerror (errno)); + } + + // We lose the ability to reliably kill the whole process group. + self->status = status; + self->pid = -1; + } + if (WIFEXITED (status)) + { + lua_pushinteger (L, WEXITSTATUS (status)); + lua_pushinteger (L, WEXITSTATUS (status)); + lua_pushnil (L); + return 3; + } + if (WIFSIGNALED (status)) + { + lua_pushinteger (L, 128 + WTERMSIG (status)); + lua_pushnil (L); + lua_pushinteger (L, WTERMSIG (status)); + return 3; + } + return 0; +} + static bool process_feed (struct process *self) { @@ -632,6 +681,7 @@ static luaL_Reg xlua_process_table[] = { "exact", xlua_process_exact }, { "eof", xlua_process_eof }, { "default", xlua_process_default }, + { "wait", xlua_process_wait }, { NULL, NULL } }; @@ -851,6 +901,7 @@ spawn_protected (lua_State *L) execvpe (ctx->argv.vector[0], ctx->argv.vector, ctx->envv.vector); print_error ("failed to spawn %s: %s", ctx->argv.vector[0], strerror (errno)); + // Or we could figure out when exactly to use statuses 126 and 127. _exit (EXIT_FAILURE); } |