1

I am using lua 5.3 from my C/C++ game to allow certain parts of its behavior to be scripted.

From the C++ program, every frame I call the lua function main in the following manner:

lua_getfield(VMState, LUA_GLOBALSINDEX, "main");
int result = lua_pcall(VMState, 0, 0, 0);

I expect the script to define a function called main, which does a bunch of stuff. For example, I can have a script that does something like this:

local f = function()
    draw_something({visible = true, x = 0, y = 0})
end

main = function()
    f()
end

draw_something() is a callback to the C code, which does something interesting with the parameters passed:

lua_getfield(VMState, 1, "visible");
bool visible = (bool)lua_toboolean(VMState, 2); lua_pop(VMState, 1);
if (!visible)
    return;
// Do some other stuff

Of interest, is that by the time this callback is called, the anonymous table I passed as a parameter to do_something in the lua side, is now at stack position 1, so I can call lua_getfield() from the C side, to access the "visible" field, and do something with it.

This works pretty well, and I've done lots of stuff like this for years.

Now, I want to convert the lua call to f to a coroutine, so I do something like this from the lua side:

local f = function()
    draw_something({visible = true, x = 0, y = 0})
end

local g = coroutine.create(function()
    while true do
        f()
        coroutine.yield()
    end
end

main = function()
    coroutine.resume(g)
end

The result should be the same. However, it now turns out that by moving the call to draw_something() inside a coroutine, the parameter I had passed to the function, which should have been a table, is now a thread? (lua_istable() returns 0, while lua_isthread() returns 1).

Interestingly, it doesn't matter how many parameters I pass to my function: 0, 1, 4, 50, from inside the callback I'm only getting one parameter, and it is a thread.

For some reason, this is happening with some functions that I exported, but not all. I can't see any difference in the way I'm exporting the different functions though.

Is there any reason why lua would switch my parameters to a thread?

Panda Pajama
  • 1,283
  • 2
  • 13
  • 31
  • why you write C++/C ? there is not C++/C line of code here , next time , write only LUA – Skiller Dz Jan 12 '19 at 10:00
  • @SkillerDz: The first and third blocks of code are in C/C++, and the unusual behavior is happening in the C/C++ side. – Panda Pajama Jan 12 '19 at 10:04
  • Did you build LuaJIT with option `-DLUA_USE_APICHECK`? – Egor Skriptunoff Jan 12 '19 at 11:08
  • @EgorSkriptunoff: I was not aware of that flag. I am using msvcbuild.bat, So I added /DLUA_USE_APICHECK to LJCOMPILE, and rebuilt the game. I'm not getting any assertions or console ouptut. I changed this to /DLUA_USE_ASSERT, and nothing either – Panda Pajama Jan 12 '19 at 12:47

1 Answers1

3

I found the answer.

It turns out that the lua_State that is passed to you on a lua_CFunction is not guaranteed to be the same to the one you first got on lua_newstate()

I suppose that each coroutine might get its own separate lua_State. If you always do stuff on the lua_State you got on lua_newstate(), you might have problems with coroutines, so you have to ensure you always use the lua_State you got passed on your lua_CFunction.

Panda Pajama
  • 1,283
  • 2
  • 13
  • 31
  • This is correct. Each coroutine gets created with its own stack, so in order for the API functions to work properly, a new `lua_State` is created, linking to the main state. A proper `lua_CFunction` implementation (one you pass to the Lua state) should use the Lua pointer passed in the parameters. – IS4 Jan 16 '19 at 18:12