skynet源碼分析(9)--LUA C API

作者:shihuaping0918@163.com,轉(zhuǎn)載請(qǐng)注明作者

這篇文章是分析skynet消息注冊(cè)前的知識(shí)準(zhǔn)備殖卑,skynet的消息注冊(cè)系奉,C服務(wù)和lua服務(wù)設(shè)置回調(diào)走的函數(shù)是不同的昭抒。C的回調(diào)可以直接調(diào),但是lua的回調(diào)不行攒磨,它需要一個(gè)默認(rèn)的回調(diào)C函數(shù),將返回參數(shù)轉(zhuǎn)換為lua能理解的格式汤徽,遵循lua的api協(xié)議娩缰,傳遞到lua層。這個(gè)回調(diào)的名字叫_cb谒府。具體它是怎么工作的我們下一篇再分析拼坎,這一篇要先了解一些必要的lua api的規(guī)范,才能進(jìn)行下一步完疫。這個(gè)lua參考手冊(cè)是隨時(shí)需要翻的:http://www.lua.org/manual/5.3/manual.html

首先是lua調(diào)c泰鸡,lua到C層的參數(shù)是按順序來(lái)的,也就是說(shuō)第一個(gè)參數(shù)就是1壳鹤,第二個(gè)就是2....第n個(gè)就是n盛龄。從C層傳遞到lua層也是一樣,但是會(huì)多一個(gè)參數(shù)個(gè)數(shù)器虾。舉個(gè)栗子吧讯嫂,干講是不好理解。能看懂英文的同學(xué)最好詳細(xì)看一下兆沙,看不懂的呢欧芽,也沒什么大礙。

In order to communicate properly with Lua, a C function must use the following protocol, 
which defines the way parameters and results are passed:
a C function receives its arguments from Lua in its stack in direct order (the first argument is pushed first). 
So, when the function starts, lua_gettop(L) returns the number of arguments received by the function. 
The first argument (if any) is at index 1 and its last argument is at index lua_gettop(L). 
To return values to Lua, a C function just pushes them onto the stack,
in direct order (the first result is pushed first), and returns the number of results.
Any other value in the stack below the results will be properly discarded by Lua. 
Like a Lua function, a C function called by Lua can also return many results.

As an example, the following function receives a variable number of numeric arguments and returns their average and their sum:

這是一個(gè)lua調(diào)C以后葛圃,C返回的例子
     static int foo (lua_State *L) {
       int n = lua_gettop(L);    /* number of arguments */  參數(shù)個(gè)數(shù)
       lua_Number sum = 0.0;
       int i;
       for (i = 1; i <= n; i++) {
         if (!lua_isnumber(L, i)) { //參數(shù)是不是數(shù)字
           lua_pushliteral(L, "incorrect argument"); //不是數(shù)字報(bào)錯(cuò)
           lua_error(L);
         }
         sum += lua_tonumber(L, i); //取第i個(gè)參數(shù)
       }
       lua_pushnumber(L, sum/n);        /* first result */ 第一個(gè)返回值
       lua_pushnumber(L, sum);         /* second result */ 第二個(gè)返回值
       return 2;                   /* number of results */ 一共兩個(gè)返回值
     }

然后是C層調(diào)LUA的函數(shù)千扔,它的具體過程就是把參數(shù)填好,然后調(diào)LUA的函數(shù)库正。為了防止異常導(dǎo)致服務(wù)不穩(wěn)定曲楚,skynet中調(diào)用lua回調(diào)函數(shù)的時(shí)候使用的是lua_pcall,這個(gè)函數(shù)在lua層也是有的褥符,LUA層就叫pcall龙誊。

lua_pcall的介紹請(qǐng)大家到參考手冊(cè)里去找,我這里貼個(gè)參數(shù)列表就好了喷楣。

int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);
lua_state就是lua環(huán)境了
nargs表示有多少個(gè)參數(shù)
nresults表示有多少個(gè)返回值
msgh為0表示返回初始錯(cuò)誤對(duì)象趟大,其它值表示消息處理函數(shù)所在的棧索引鹤树。

下面以skynet中的_cb函數(shù)來(lái)說(shuō)明一下C調(diào)用lua函數(shù)的場(chǎng)景。

static int
_cb(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
    lua_State *L = ud;
    int trace = 1;
    int r;
    int top = lua_gettop(L); //獲取棧參數(shù)個(gè)數(shù)
    if (top == 0) {
        lua_pushcfunction(L, traceback); //index為1逊朽,是一個(gè)錯(cuò)誤處理函數(shù)
        lua_rawgetp(L, LUA_REGISTRYINDEX, _cb); //index為2罕伯,是lua的回調(diào)函數(shù)
    } else {
        assert(top == 2);
    }

    lua_pushvalue(L,2); //lua回調(diào)函數(shù)入棧
    lua_pushinteger(L, type);  //回調(diào)參數(shù)1,類型
    lua_pushlightuserdata(L, (void *)msg);  //回調(diào)參數(shù)2叽讳,消息體
    lua_pushinteger(L,sz); //回調(diào)參數(shù)3追他,消息長(zhǎng)度
    lua_pushinteger(L, session); //回調(diào)參數(shù)4,session
    lua_pushinteger(L, source); //回調(diào)參數(shù)5岛蚤,source

    //nargs為5邑狸,表示有5個(gè)參數(shù)
    //nresults為0,表示返回值為0
    //trace為1涤妒,表示出錯(cuò)時(shí)調(diào)用前面設(shè)置的traceback函數(shù)
    r = lua_pcall(L, 5, 0 , trace); 

    if (r == LUA_OK) {
        return 0;
    }
    const char * self = skynet_command(context, "REG", NULL);
    switch (r) {
    case LUA_ERRRUN:
        skynet_error(context, "lua call [%x to %s : %d msgsz = %d] error : " KRED "%s" KNRM, source , self, session, sz, lua_tostring(L,-1));
        break;
    case LUA_ERRMEM:
        skynet_error(context, "lua memory error : [%x to %s : %d]", source , self, session);
        break;
    case LUA_ERRERR:
        skynet_error(context, "lua error in error : [%x to %s : %d]", source , self, session);
        break;
    case LUA_ERRGCMM:
        skynet_error(context, "lua gc error : [%x to %s : %d]", source , self, session);
        break;
    };

    lua_pop(L,1);

    return 0;
}

根據(jù)上面的代碼分析推溃,當(dāng)服務(wù)是lua實(shí)現(xiàn)的時(shí)候,skynet底層核心框架在處理完消息以后届腐,回調(diào)lua層服務(wù)的回調(diào)函數(shù)時(shí)铁坎,要先經(jīng)過一次lua api協(xié)議的處理,將參數(shù)準(zhǔn)備好以后犁苏,然后調(diào)用lua服務(wù)中的回調(diào)函數(shù)硬萍。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市围详,隨后出現(xiàn)的幾起案子朴乖,更是在濱河造成了極大的恐慌,老刑警劉巖助赞,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件买羞,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡雹食,警方通過查閱死者的電腦和手機(jī)畜普,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)群叶,“玉大人吃挑,你說(shuō)我怎么就攤上這事〗至ⅲ” “怎么了舶衬?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)赎离。 經(jīng)常有香客問我逛犹,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任虽画,我火速辦了婚禮掠手,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘狸捕。我一直安慰自己,他們只是感情好众雷,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布灸拍。 她就那樣靜靜地躺著,像睡著了一般砾省。 火紅的嫁衣襯著肌膚如雪鸡岗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天编兄,我揣著相機(jī)與錄音轩性,去河邊找鬼。 笑死狠鸳,一個(gè)胖子當(dāng)著我的面吹牛揣苏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播件舵,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼卸察,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了铅祸?” 一聲冷哼從身側(cè)響起坑质,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎临梗,沒想到半個(gè)月后涡扼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盟庞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年吃沪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片什猖。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡巷波,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卸伞,到底是詐尸還是另有隱情抹镊,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布荤傲,位于F島的核電站垮耳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜终佛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一俊嗽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧铃彰,春花似錦绍豁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至邪铲,卻和暖如春芬位,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背带到。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工昧碉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人揽惹。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓被饿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親搪搏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子锹漱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容