lua-epoll 模組簡單分析

來源:互聯網
上載者:User

標籤:

    這個模組是把Linux下的epoll操作按照Lua Cfunction 的格式封裝出來,供lua使用。

    Lua要求每一個擴充模組,必須提供luaopen_XXX(lua_State *L) 作為模組的入口函數,此函數會在require載入模組時被調用到。我們就從這個函數開始分析:

static const struct luaL_Reg epoll[]={    {"setnonblocking",setnonblocking},    {"create",ep_create},    {"register",ep_event_add},    {"modify",ep_event_mod},    {"unregister",ep_event_del},    {"wait",ep_wait},    {"close",ep_close},    {NULL,NULL},};int luaopen_epoll(lua_State *L){    // register epoll table     luaL_register(L,"epoll",epoll);#define SETCONST(EVENT)     lua_pushnumber(L,EVENT);     lua_setfield(L,-2,#EVENT)    // push const values into epoll table.    SETCONST(EPOLLIN);    SETCONST(EPOLLPRI);    SETCONST(EPOLLOUT);    SETCONST(EPOLLRDNORM);    SETCONST(EPOLLRDBAND);    SETCONST(EPOLLWRNORM);    SETCONST(EPOLLWRBAND);    SETCONST(EPOLLMSG);    SETCONST(EPOLLERR);    SETCONST(EPOLLHUP);    SETCONST(EPOLLRDHUP);    SETCONST(EPOLLONESHOT);    SETCONST(EPOLLET);    return 1;}

    該函數首先是調用luaL_register向 lua _G全域table中註冊了epoll table,並將epoll結構體中的成員註冊到epoll table中。看一下luaL_register 官方文檔說明:

void luaL_register (lua_State *L,                    const char *libname,                    const luaL_Reg *l);Opens a library.    When called with libname equal to NULL, it simply registers all functions in the list l (see luaL_Reg) into the table on the top of the stack.    When called with a non-null libname, luaL_register creates a new table t, sets it as the value of the global variable libname, sets it as the value of package.loaded[libname], and registers on it all functions in the list l. If there is a table in package.loaded[libname] or in variable libname, reuses this table instead of creating a new one.    In any case the function leaves the table on the top of the stack.

    然後調用SETCONST宏來向epoll table中插入EVENTS數值。

    luaopen_epoll函數返回後,epoll table的成員如下:

/*   epoll = {setnonblocking = setnonblocking,create = ep_create,register = ep_event_add,modify = ep_event_mod,unregister = ep_event_del,wait = ep_wait,close = ep_close,EPOLLIN = EPOLLIN,EPOLLPRI = EPOLLPRI,EPOLLOUT = EPOLLOUT,EPOLLRDNORM = EPOLLRDNORM,EPOLLRDBAND = EPOLLRDBAND,EPOLLWRNORM = EPOLLWRNORM,EPOLLWRBAND = EPOLLWRBAND,EPOLLMSG = EPOLLMSG,EPOLLERR = EPOLLERR,EPOLLHUP = EPOLLHUP,EPOLLRDHUP = EPOLLRDHUP,EPOLLONESHOT = EPOLLONESHOT,EPOLLET = EPOLLET,  };*/

    此時,在lua中執行:

local epoll = require("epoll")local epfd = epoll.create()

    就會調用到epoll table中名為create的函數,即ep_create,下面看一下其實現:

static int ep_create(lua_State *L){    int epfd;    if((epfd=epoll_create(1))==-1){        DSERR();    }    lua_pushinteger(L,epfd);    return 1;}

    跳過錯誤處理,可以發現非常的簡單,就是調用epoll_create方法,然後將其傳回值壓入棧頂。如果epoll_create調用出錯,則執行RSTERR宏:

#define DSERR()     lua_pushnil(L);     lua_pushstring(L,strerror(errno));     return 2

    這個宏就是壓入nil與error資訊到棧中。

    再看看如何註冊一個事件:向epoll中註冊一個可讀事件

epoll.register(epfd, sfd, poll.EPOLLIN)

    上述lua代碼會調用到epoll table中名為register函數,即ep_event_add函數:

static int ep_event_add(lua_State *L){    int epfd,fd;    EVENTMASK eventmask;        epfd=luaL_checkint(L,1);    fd=luaL_checkint(L,2);    eventmask=luaL_checknumber(L,3);    struct epoll_event ev;    ev.data.fd=fd;    ev.events=eventmask;    if(epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev)==-1){        DSERR();    }    lua_pushboolean(L,1);    return 1;}

    在調用上述函數時,棧的情況為:/*L stack: epfd, fd, eventmask*/。ep_event_add首先是把傳入的參數從棧中取出,然後執行epoll_ctl(),最後把執行結果壓入棧頂進行返回。

    最後,看一下epoll.wait的使用:

events,err=epoll.wait(epfd,timeout,max_events)

    lua執行epoll.wait函數,即執行ep_wait()函數:

static int ep_wait(lua_State *L){    int i,n,epfd,timeout,max_events;    epfd=luaL_checkint(L,1);    timeout=luaL_checkint(L,2);    max_events=luaL_checkint(L,3);    struct epoll_event events[max_events];    if((n=epoll_wait(epfd,events,max_events,timeout))==-1){        DSERR();    }    lua_newtable(L);    for(i=0;i<n;++i){        lua_pushinteger(L,events[i].data.fd);        lua_pushnumber(L,events[i].events);        lua_settable(L,-3);    }    return 1;}

    執行ep_wait()函數時,此時棧的情況為:/*L stack: epfd, timeout, max_events */。首先也是把傳入的參數從棧中取出,然後執行epoll_wait(),然後把結果壓入棧中進行返回。不過這裡返回是一個table,以就緒的fd作為table的索引,值為對應的就緒事件,即t[events[i].data.fd] = events[i].events

    其實只要自己動手寫上一兩個模組,就清楚lua C API的使用了,也就明白了Lua是如何通過棧與C進行參數傳遞與返回。

lua-epoll 模組簡單分析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.