当前位置: 首页 > news >正文

lua-epoll 模块简单分析

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

    这个模块是把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进行参数传递与返回。

转载于:https://my.oschina.net/kaedehao/blog/513157

相关文章:

  • MyBatis:简单物理分页实现(Plugin)
  • 堆与堆排序
  • laravel 怎么使用ajax
  • argz_count()函数
  • JS获取阴历阳历和星期
  • LCA UESTC 92 Journey
  • jquery cookie
  • Android调用系统相机拍照保存照片很小解决方案
  • Caching with Instance Variables 缓存与实例变量
  • jsf初学解决faces 中文输入乱码问题
  • Java随机数生成原理
  • jvm参数详解,内存泄露解决
  • HDU 2815 Mod Tree 离散对数 扩张Baby Step Giant Step算法
  • centos 7 修改默认运行级别
  • Python之继承
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • -------------------- 第二讲-------- 第一节------在此给出链表的基本操作
  • 【翻译】babel对TC39装饰器草案的实现
  • github指令
  • GraphQL学习过程应该是这样的
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • python3 使用 asyncio 代替线程
  • springMvc学习笔记(2)
  • Vue 动态创建 component
  • 如何编写一个可升级的智能合约
  • 如何在 Tornado 中实现 Middleware
  • 我感觉这是史上最牛的防sql注入方法类
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • 正则表达式小结
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • (7)STL算法之交换赋值
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • (一)VirtualBox安装增强功能
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • .net 4.0 A potentially dangerous Request.Form value was detected from the client 的解决方案
  • .NET CORE 2.0发布后没有 VIEWS视图页面文件
  • .NET NPOI导出Excel详解
  • .Net Remoting常用部署结构
  • .net web项目 调用webService
  • .net 程序发生了一个不可捕获的异常
  • .Net 代码性能 - (1)
  • .NET项目中存在多个web.config文件时的加载顺序
  • [ vulhub漏洞复现篇 ] ThinkPHP 5.0.23-Rce
  • [].slice.call()将类数组转化为真正的数组
  • []Telit UC864E 拨号上网
  • [20171113]修改表结构删除列相关问题4.txt
  • [Android Studio] 开发Java 程序
  • [Angular] 笔记 9:list/detail 页面以及@Output
  • [BUUCTF 2018]Online Tool(特详解)
  • [C/C++]数据结构 循环队列