很早前在折騰掛起LUA腳本支持時,接觸到lua_yield這個函數。lua manual中給的解釋是:
This function should only be called as the return expression of a C function。
而這個函數一般是在一個注冊到LUA環境中的C函數里被調用。lua_CFunction要求的原型里
,函數的返回值必須返回要返回到LUA腳本中的值的個數。也就是說,在一個不需要掛起的
lua_CFunction實現里,也就是一個不需要return lua_yield(...的實現里,我應該return
一個返回值個數。
但是為什么調用lua_yield就必須放在return表達式里?當時很天真,沒去深究,反正發現
不按照lua manual里說的做就是不行。而且關鍵是,lua manual就不告訴你為什么。
最近突然就想到這個問題,決定去搞清楚這個問題。侯捷說了,源碼面前了無秘密。我甚至
在看代碼之前,還琢磨著LUA是不是操作了堆棧(系統堆棧)之類的東西。結果隨便跟了下
代碼真的讓我很汗顏。有時候人犯傻了真的是一個悲劇。諾簡單的一個問題會被人搞得很神
秘:
解釋執行調用一個注冊進LUA的lua_CFunction是在ldo.c里的luaD_precall函數里,有如下
代碼:

n = (*curr_func(L)->c.f)(L); /**//* do the actual call */
lua_lock(L);

if (n < 0) /**//* yielding? */
return PCRYIELD;

else
{
luaD_poscall(L, L->top - n);
return PCRC;
}
多的我就不說了,別人注釋寫得很清楚了,注冊進去的lua_CFunction如果返回值小于0,這
個函數就向上層返回PCRYIELD,從名字就可看出是告訴上層需要YIELD。再找到lua_yield函
數的實現,恰好該函數就返回-1。
要再往上層跟,會到lvm.c里luaV_execute函數,看起來應該就是虛擬機在解釋執行指令:

case OP_CALL:
{
int b = GETARG_B(i);
int nresults = GETARG_C(i) - 1;

if (b != 0) L->top = ra+b; /**//* else previous instruction set top */
L->savedpc = pc;

switch (luaD_precall(L, ra, nresults))
{

case PCRLUA:
{
nexeccalls++;

goto reentry; /**//* restart luaV_execute over new Lua function */
}

case PCRC:
{

/**//* it was a C function (`precall' called it); adjust results */
if (nresults >= 0) L->top = L->ci->top;
base = L->base;
continue;