How to suspend/resume processing of a Lua command
I'm writing a client that can talk to multiple servers and processes user commands on stdin
or eventually from a file using Lua. The server is a custom application, so I'm handling all the communication back in C
where all the code for the protocol has already been written. Here's a bit of pseudo-code of what I have now:
int main(int argc, char **argv) {
/* setup fd list, vars, etc */
...
while (1) {
开发者_JAVA技巧/* process list of file descriptors to create read/write fd sets */
...
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
}
}
}
}
int process_stdin() {
luaL_loadbuffer(L, stdin_buffer, len, "stdin");
lua_pcall(L, 0, 0, 0);
}
int process_remote() {
parse buffer into message from remote system
if message is complete, call Lua with either a new message notification or resume
}
So here's my problem: If the user on stdin
types something like wait_for_remote_message(xyz)
, how do I stop at that point, return from the lua_pcall
and go into the select
loop to wait for more data? And then, how would process_remote
resume the Lua command from that point forward?
I can imagine a solution involving pthreads, but that feels like overkill for this application and introduces a lot of extra complexity.
I can also imagine a solution where the while(1)/select
loop is moved into a function and from the wait_for_remote_message(xyz)
I jump back to C
and call this function with stdin
added to some kind of exclusion list.
Are there any better ways to do this?
This sounds like a perfect use for Lua coroutines, where you can call yield to suspend execution, and then resume later.
Check out http://www.lua.org/pil/9.html for details
You might do something like
int process_stdin() {
lua_State coroutine = lua_newthread(L);
luaL_loadbuffer(coroutine, stdin_buffer, len, "stdin");
if (lua_resume(coroutine, 0) == LUA_YIELD) {
// store coroutine somewhere global
}
}
int process_remote() {
// parse buffer into message from remote system
// push the message onto the Lua stack
lua_resume(coroutine, 1);
}
精彩评论