本章节主要说明如何基于epoll来实现基本的事件框架。
事件框架的名字我取名叫做popevent
,代码仓位于popevent,建立于我的造轮子专业组织popzilla下面。目前计划是完成一部分其中完整的功能将写一篇博客介绍这块功能以及对应的代码。所以这篇文章是介绍第一次提交的内容。
第一次提交主要包含代码目录结构,编译脚本,以及事件框架对外提供的一些接口与实现。当然最后为了验证实现的事件框架是否工作正常,新增了一个测试用例,叫做test_simple
。代码TAG点为0.1.0。
0.目录结构
代码当前的目录结构如下:
.
├── CMakelists.txt
├── LICENSE
├── README.en.md
├── README.md
├── build
├── include
│ └── pop_event.h
├── src
│ └── pop_event.c
└── test
└── test_simple.c
主要的几个目录为build
、include
、src
以及test
。
build
目录为进行构建以及中间产物生成的地方;include
为对外头文件(即提供给其他组件进行调用的头文件)存放的地方;src
为主要源码目录;test
为测试代码目录;
1.接口
接口一般反映了模块对外提供的一个能力,而头文件是接口承载的一个方式,所以我们先从头文件先来介绍。
当前工程中只有1个头文件,位于include/pop_event.h
,这个头文件也是后续我们提供给其他组件调用的头文件,其中内容如下。
enum {
POP_EVENT_IN = 0x001,
POP_EVENT_OUT = 0x002,
POP_EVENT_HUP = 0x004,
POP_EVENT_RDHUP = 0x008,
POP_EVENT_ERR = 0x010,
POP_EVENT_ET = 1 << 31
};
typedef struct pop_event pop_event_t;
typedef void (*pop_event_cb_t)(pop_event_t *event, uint32_t what, void *usrdata);
int pop_event_init(void);
pop_event_t *pop_event_create(int fd, void *usrdata);
int pop_event_add_watch(pop_event_t *event, uint32_t what, pop_event_cb_t cb);
int pop_event_mod_watch(pop_event_t *event, uint32_t what, pop_event_cb_t cb);
int pop_event_del_watch(pop_event_t *event);
void pop_event_destroy(pop_event_t *event);
void pop_event_loop(void);
void pop_event_fini(void);
1.1 框架初始化
在使用框架前需要对框架进行初始化,这个初始化的主要内容是完成一些全局变量的准备。_init
为初始化,_fini
为销毁。
int pop_event_init(void);
void pop_event_fini(void);
1.2 事件对象
我们使用pop_event_t
结构来承载创建的事件对象,为了隐藏其中的实现细节,对外只暴露了类型声明。创建和销毁对象的接口为
pop_event_t *pop_event_create(int fd, void *usrdata);
void pop_event_destroy(pop_event_t *event);
其中创建所需的参数为fd
和usrdata
,也就是可以基于文件描述符去创建1个事件对象,同时我们也可以通过usrdata
携带自定义数据。
1.3 事件的监听和删除
为了实现对事件类型的监听和修改、删除,提供了如下3个接口。其中what
为监听的事件类型,分别对应枚举值POP_EVENT_IN
等。
int pop_event_add_watch(pop_event_t *event, uint32_t what, pop_event_cb_t cb);
int pop_event_mod_watch(pop_event_t *event, uint32_t what, pop_event_cb_t cb);
int pop_event_del_watch(pop_event_t *event);
2. 实现
这里不对代码进行解读,实现的函数比较简单。内部使用epoll
对调用者所传递的fd
进行监听,当有事件到来时再回调调用者注册的事件处理函数。本次为基本功能提交,待完善的地方还有很多,没有过多的技巧在其中。
3. 测试
增加了一个测试代码,为基本的生产者/消费者模型,其中有2个线程,1个线程向管道中写数据,另外1个线程从管道中读取数据。
写入数据的线程每秒将向管道中写入数据。
读取数据的线程使用pop_event
对数据可读进行事件监听,当有数据可读时将数据打印出来。