2

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?

asked May 26, 2011 at 21:05

1 Answer 1

4

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);
}
answered May 26, 2011 at 23:34
2
  • Am I allowed to yield from a lua_pcall? Or is there a way to do a lua_resume after the luaL_loadbuffer instead of the lua_pcall? I agree coroutines sounds like a perfect match, but I'm missing the way I link in the processing of stdin with the coroutine. Commented 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. Commented May 27, 2011 at 0:24

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.