Hello everybody.
I'm making a module to process messages from a program ( yate ), and, being a novice lua user, I'd like to expose my dessign in case I've make some mistake.
The engine is made in C++, and calls message handler from multiple threads, passing a message reference ( which I've already wrapped in a userdata ) to the handler and expects a boolean return value.
I've already coded the part to load my handler code into a lua state and initialize it. The lua callback code is fast, so I just lock the state whenever I call into it to avoid problems.
The tricky part is sometimes my code needs to dispatch a new message, which is a blocking, potentially long operation, and can lead to the message being dispatched again to my lua code from another thread.
To do these I do the following.
- Each time I receive a message I lock the lua state , create a new coroutine wtith the handler function and call lua_resume on it in a loop ( while( (lua_resume(...)!=LUA_YIELD) .... ).
- When my handler needs to dispatch a message it yields a unique (lightuserdata) operation code along with the message.
- The code inside the while() loop test the params, and if the operation code for dispatch is detected it extracts the C++ message from the userdata, unlocks the state, dispatchs it, relocks the state and returns via lua_resume the dispatch result.
My thought is that if somehow the c++ dispatchers calls back to me again from another thread I'll just create a new coroutine, process it, return the message, the dispatcher will get it back to the original thread which will in turn resume after relocking.
I'm confident my code is only entering the interpreter from a thread at a time. I'd like to confirm that lua will not longjmp() out of a lua_resume() call. I'd also like to know if this (yielding) is overkill. I did it instead of just doing a normal dispatch function which just called the c++ dispatcher while temporarily unlocking the state because I was worried it will longjmp out of the function and skip my unlocking code.