lua_resume(): What is the meaning of the second argument?



Note: There are some questions below that illustrate my thinking, but the only answer I'm looking for is the answer to the actual question, in the title. Not asking for "a book" here, or itemized responses to all of those.

I'm trying to start a coroutine from the C API, let it yield, and continue it later (possibly after executing resumes from other coroutines). This is a fairly simple use case, but the documentation for lua_resume() is extremely confusing:

int lua_resume (lua_State *L, lua_State *from, int nargs);

Starts and resumes a coroutine in the given thread L.

To start a coroutine, you push onto the thread stack the main function plus any arguments; then you call lua_resume, with nargs being the number of arguments. This call returns when the coroutine suspends or finishes its execution. When it returns, the stack contains all values passed to lua_yield, or all values returned by the body function. lua_resume returns LUA_YIELD if the coroutine yields, LUA_OK if the coroutine finishes its execution without errors, or an error code in case of errors (see lua_pcall).

In case of errors, the stack is not unwound, so you can use the debug API over it. The error message is on the top of the stack.

To resume a coroutine, you remove any results from the last lua_yield, put on its stack only the values to be passed as results from yield, and then call lua_resume.

The parameter from represents the coroutine that is resuming L. If there is no such coroutine, this parameter can be NULL.
The meaning of "represents the coroutine that is resuming L" is extremely unclear here. When exactly is "from" nil, which of L and from are the "thread stack", and what are the exact requirements for resuming a coroutine? Can the state L be modified between the initial lua_resume() and the second one which is actually resuming? If so, how does the state know where/what function to resume? If not (ie. one thread per lua_State) what is the proper way to create a new thread, so that it shares an execution context (globals, environment, etc) with the parent thread, and what is the proper way to call lua_resume() and unwind the call for each start/resume in this case? Could the 'from' argument do / be related to any of these things?

And finally, in either case - how can I get a full stack trace for debugging in an error handler (for example invoked on error from lua_pcall) which respects / is aware of calls across resumes? Does lua_getinfo() report correctly through resumes? Is that what the 'from' argument is for?

I'd really like a complete, working example of a coroutine start/resume from the C API that illustrates the use of that second argument. There's this example on gist, but it's years old and the API has changed since then - lua_resume() takes 3 arguments now, not 2...

Continue reading...