Background: I'm using a Lua thread (coroutine) to process user input from stdin (to allow the program to pause while waiting on data from another FD). Because it's user input, errors are possible if not probable, e.g. calling a non-existent function.
Question: Can the Lua thread be recovered so that I can continue to process more data from stdin, or do I have to nuke the thread and create a new one after every error?
Here's some rough sample/pseudo code of what I'm doing now:
while (1) {
select((max, &read_fds, &write_fds, NULL, NULL);
for each file descriptor {
if (read fd is set) {
read data into a buffer
if (current fd is stdin)
process_stdin()
else if (current fd is from server connection)
process_remote()
}
if (write fd is set) {
write data on non-blocking fd
}
}
}
process_stdin() {
status=luaL_loadbuffer(L, stdin_buf, len, "stdin");
if (status == LUA_ERRSYNTAX) {
/* handle EOF which means more user input needed
* or print error message for user, this works fine */
}
else if (status == 0) {
status=lua_resume(L, 0);
if (status != 0 && status != LUA_YIELD) {
/* Do I nuke the thread or is there another way to recover at this point??? */
}
}
}
Typically, I would use pcall
to catch the error and recover, but pcall
doesn't support the yield in 5.1 (though 5.2 may be a good solution here). With the lua_resume
call, I'm running into the following in my session:
> no_such_func()
Error: attempt to call global 'no_such_func' (a nil value)
> print("hello world")
Error: cannot resume non-suspended coroutine
After the first command, the thread status is set to 2 (LUA_ERRRUN
).
Edit: the error message I'm getting doesn't appear to be because of the unwound stack. I'm seeing this message from ldo.c which indicates the issue is because the thread state is getting set to 2.
if (L->status != LUA_YIELD && (L->status != 0 || L->ci != L->base_ci))
return resume_error(L, "cannot resume non-suspended coroutine");
So I either need a way to reset the state or avoid having the state change in the first place. My guess is that I may be stuck with popping the thread off my main stack and recreating a new one, or upgrading to 5.2 so I can yield from a pcall
.
pcall
on the stack, then runlua_loadbuffer
, and when thelua_resume
status is 0, you have the check thepcall
result to see if it was true or false. Much cleaner than the other options I was looking at. – BMitch