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
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:
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.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.