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) {
/* 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?
1 Answer 1
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);
}
-
Am I allowed to yield from a
lua_pcall
? Or is there a way to do alua_resume
after theluaL_loadbuffer
instead of thelua_pcall
? I agree coroutines sounds like a perfect match, but I'm missing the way I link in the processing ofstdin
with the coroutine.BMitch– BMitch2011年05月26日 23:55:00 +00:00Commented May 26, 2011 at 23:55 -
Hmm, after looking through the docs some more, it looks like the answer to my second question is going to be yes since
luaL_loadbuffer
is returning a function. Let me do a little testing to see if I can get this to work. Thanks Wossname.BMitch– BMitch2011年05月27日 00:24:05 +00:00Commented May 27, 2011 at 0:24