Steve
Steve

Reputation: 798

Equivalent of Lua coroutine.create in C++ using lua_newthread

I have a callback system, which can add lua functions to a C++ handler, e.g. in lua i can do

myCObject:AddCallback(luaFunc)

i also have the same, for coroutines

myCObject:AddCallback(coroutine.create(luaFunc))

I then can use

lua_State * pThread = lua_tothread(L, -1);
lua_resume(pThread, 0,0);

in C++

To start/resume the lua function.

Now, i dont want to require script writers to write coroutine.create(luaFunc) - and i just want to automatically "convert" a lua func to a coroutine. When AddCallback gets called, i have the luaFunc on the stack - and then how do i proceed? (with coroutine.create i already have a thread on the stack)

EDIT: Im looking for a solution that uses the C API e.g. lua_newthread

Upvotes: 4

Views: 5118

Answers (2)

Nicol Bolas
Nicol Bolas

Reputation: 473322

The idea is fairly simple. First, you create a new thread.

lua_State *pThread = lua_newthread(L);

This function also pushes that thread onto L. The next step is to get your thread function onto pThread. Given that you have a Lua function on the stack at this point, your next step is to transfer that function to the pThread stack.

There is a function specifically for transferring values between threads: lua_xmove. However, it only transfers the top elements of the stack. So you need to copy the Lua function from where it is on L's stack to the top of L's stack. Then lua_xmove it to the new stack.

lua_pushvalue(L, #); //Where # is the index in the stack where the function is.
                     //Remember that lua_newthread pushed a value on the stack, so compensate for that.
lua_xmove(L, pThread, 1); //Moves the function to the top of the new stack.

Remember that lua_xmove moves the value, which removes it from L. So lua_pushvalue pushes the value, and lua_xmove pops it. So the top of the stack is again the lua_State represented by pThread.

After that, push all of the parameters you need to send to the function (which apparently is zero), and resume it.

lua_resume(pThread, 0, 0);

The total code:

lua_State *pThread = lua_newthread(L);
lua_pushvalue(L, #); //Where # is the index in the stack where the function is.
                     //Remember that lua_newthread pushed a value on the stack, so compensate for that.
lua_xmove(L, pThread, 1); //Moves the function to the top of the new stack.
lua_resume(pThread, 0, 0);

A Lua thread (whether created in Lua or in the C API) is a Lua value, just like a table, userdata, string, etc. Therefore, it is subject to garbage collection. It will be collected when Lua detects that there are no more references to the value.

Remember: lua_newthread pushes the thread onto the original stack. It is up to you to copy it into the registry, or into the global environment or wherever you intend for that thread to permanently reside. Simply keeping a pointer to the lua_State that it generated will not ensure that the thread remains alive.

Upvotes: 11

jxh
jxh

Reputation: 70392

I haven't done much lua stuff in a long time, so I am a little rusty. But, I think what you want to do is:

  • extract the luaFunc
  • then push the coroutine.create function on
  • then push the luaFunc back on
  • and use lua_pcall to get your thread on the stack.

From your comments, you want to use lua_newthread. I don't have any experience with it, but I did find this answer which contains an example program that is using it.

Upvotes: 2

Related Questions