wdye: enable waiting for processes
This commit is contained in:
parent
9fe576ae9e
commit
37a8f16235
@ -18,7 +18,14 @@ expect(cat:regex {"A(.*)3", nocase=true, function (p)
|
|||||||
assert(p[1] == "bc12", "wrong regex group #1")
|
assert(p[1] == "bc12", "wrong regex group #1")
|
||||||
end})
|
end})
|
||||||
|
|
||||||
|
assert(not cat:wait (true), "process reports exiting early")
|
||||||
|
|
||||||
-- Send EOF (^D), test method chaining.
|
-- Send EOF (^D), test method chaining.
|
||||||
cat:send("Closing...\r"):send("\004")
|
cat:send("Closing...\r"):send("\004")
|
||||||
local v = expect(cat:eof {true},
|
local v = expect(cat:eof {true},
|
||||||
cat:default {.5, function (p) error "expected EOF, got a timeout" end})
|
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")
|
||||||
|
@ -94,6 +94,16 @@ PROCESS:eof {[notransfer=true, ] [value1, ...]}
|
|||||||
Returns a new end-of-file _pattern_, which matches the entire read buffer
|
Returns a new end-of-file _pattern_, which matches the entire read buffer
|
||||||
contents once the child process closes the terminal.
|
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, ...]}
|
PROCESS:default {[timeout, ] [notransfer=true, ] [value1, ...]}
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
Returns a new _pattern_ combining *wdye.timeout* with *eof*.
|
Returns a new _pattern_ combining *wdye.timeout* with *eof*.
|
||||||
|
@ -431,9 +431,10 @@ static luaL_Reg xlua_pattern_table[] =
|
|||||||
struct process
|
struct process
|
||||||
{
|
{
|
||||||
int terminal_fd; ///< Process stdin/stdout/stderr
|
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
|
int ref_term; ///< Terminal information
|
||||||
struct str buffer; ///< Terminal input buffer
|
struct str buffer; ///< Terminal input buffer
|
||||||
|
int status; ///< Process status iff pid is -1
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct process *
|
static struct process *
|
||||||
@ -598,6 +599,54 @@ xlua_process_default (lua_State *L)
|
|||||||
return 1;
|
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
|
static bool
|
||||||
process_feed (struct process *self)
|
process_feed (struct process *self)
|
||||||
{
|
{
|
||||||
@ -632,6 +681,7 @@ static luaL_Reg xlua_process_table[] =
|
|||||||
{ "exact", xlua_process_exact },
|
{ "exact", xlua_process_exact },
|
||||||
{ "eof", xlua_process_eof },
|
{ "eof", xlua_process_eof },
|
||||||
{ "default", xlua_process_default },
|
{ "default", xlua_process_default },
|
||||||
|
{ "wait", xlua_process_wait },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -851,6 +901,7 @@ spawn_protected (lua_State *L)
|
|||||||
execvpe (ctx->argv.vector[0], ctx->argv.vector, ctx->envv.vector);
|
execvpe (ctx->argv.vector[0], ctx->argv.vector, ctx->envv.vector);
|
||||||
print_error ("failed to spawn %s: %s",
|
print_error ("failed to spawn %s: %s",
|
||||||
ctx->argv.vector[0], strerror (errno));
|
ctx->argv.vector[0], strerror (errno));
|
||||||
|
// Or we could figure out when exactly to use statuses 126 and 127.
|
||||||
_exit (EXIT_FAILURE);
|
_exit (EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user