Question

it works when lua call a C API if a C function call lua function, and the lua function call C API, longjmp error

lua_yieldk, lua_callk, and lua_pcallk how does it work?

my c code:

int trace(lua_State *L)
{
    const char *str = luaL_checkstring(L, 1);
    printf("%d:%s\n", GetTickCount(), str);
    return 1;
 }

int pause(lua_State *L)
{
    printf("pause");
    return lua_yield(L, 0);
}

int _tmain(int argc, _TCHAR* argv[])
{
    lua_State *L = luaL_newstate(); 
    luaL_openlibs(L);
    lua_pushcfunction( L, pause );
    lua_setglobal( L, "pause" );
    lua_pushcfunction( L, trace );
    lua_setglobal( L, "trace" );
    if (luaL_loadfile(L, "test.lua"))
       error(L, "cannot run script %s\n", lua_tostring(L,-1));
    lua_resume(L, NULL, 0);
        lua_getglobal(L, "t");
    lua_pcallk(L, 0, 0, 0, 0, 0);
    lua_resume(L, NULL, 0);
    lua_resume(L, NULL, 0);
    lua_resume(L, NULL, 0);
    lua_resume(L, NULL, 0);
    lua_close(L);
    getchar();
    return 0;
}

lua code

function t()
pause(2)
pause(2)
pause(2)
pause(2)
end
Was it helpful?

Solution

You call lua_resume on a thread returned by lua_newthread, not lua_newstate.

So in your code you would either have to change the first lua_resume to lua_(p)call:

if (luaL_loadfile(L, "test.lua"))
   error(L, "cannot run script %s\n", lua_tostring(L,-1));
lua_pcall(L, 0, 0, 0);

or swap luaL_loadfile for luaL_dofile:

if (luaL_dofile(L, "test.lua"))
   error(L, "cannot run script %s\n", lua_tostring(L,-1));
//lua_resume(L, NULL, 0); Not necessary anymore

I'm not relating to the efficiency of setting the global t here.

Now to the main point of the question:

  • First, each call to lua_callk, lua_pcallk or lua_yieldk needs to receive a continuation function as an argument. In your case it's 0. Actually, lua_yieldk can take 0 as continuation function, but then control is passed back to Lua script, where the call to the C function occured.
  • Next, any call to those functions must be made within a coroutine thread, not the main thread.
  • And lastly, you cannot yield across C call boundary. That is, when you call lua_pcallk and the chunk that pcallk is calling yields, the continuation function is executed. However, you cannot have lua_pcallk call a Lua function that in turn calls a C function that yields (pause in your example). That's forbidden.

An example of lua_pcallk:

int cont(lua_State *L)
{
    getchar();
    return 0;
}

int pcallktest(lua_State *L)
{
    luaL_loadstring(L, "yield()");
    int test = lua_pcallk(L, 0, 0, 0, 0, cont);
    return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    lua_State *T = lua_newthread(L);

    luaL_loadfile(T, "Test.lua");
    lua_pushcfunction(T, pcallktest);
    lua_resume(T, NULL, 1);
    return 0;
}

Lua code:

local pcallktest = ...
pcallktest()

Now this piece of code starts a new coroutine from file "Test.lua". The Lua code calls C function pcallktest, which in turn calls lua_pcallk on another Lua function, which just yields. When the yield occurs, execution jumps (longjmp) to the cont function, which was provided as an argument to lua_pcallk. When the cont function returns, the coroutine execution ends and lua_resume from the _tmain returns.

An example of lua_yieldk:

int cont(lua_State *L)
{
    getchar();
    return 0;
}

int yieldktest(lua_State *L)
{
    return lua_yieldk(L, 0, 0, cont);
}
int _tmain(int argc, _TCHAR* argv[])
{
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    lua_State *T = lua_newthread(L);

    luaL_loadfile(T, "Test.lua");
    lua_pushcfunction(T, yieldktest);
    lua_resume(T, NULL, 1);
    lua_resume(T, NULL, 0);
    return 0;
}

Lua code:

local yieldktest = ...
yieldktest()

This bit in turn executes coroutine that yields from within a C function (yieldktest). When the coroutine is then resumed (the second lua_resume), control is passed back to the continuation function cont, which executes as a continuation of yieldktest.

These examples do not deal with lua_getctx and stack states, but merely demonstrate the mechanisms of those functions.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top