文章目录
-
1 libevent简介
-
2 工作原理
- 2.1 工作流程图
- 2.2 Reactor模式框架
-
3 源码分析
-
3.1 event_init()
1
2
3
41* 3.1.1 函数定义
2* 3.1.2 函数说明
3* 3.1.3 函数源码分析
4 -
3.2 event_set()
1
2
3
41* 3.2.1 函数定义
2* 3.2.2 函数说明
3* 3.2.3 函数源码分析
4 -
3.3 event_base_set()
1
2
3
41* 3.3.1 函数定义
2* 3.3.2 函数说明
3* 3.3.3 函数源码分析
4 -
3.4 event_add()
1
2
3
41* 3.4.1 函数定义
2* 3.4.2 函数说明
3* 3.4.3 函数源码分析
4 -
3.5 event_base_loop()
1
2
3
41* 3.5.1 函数定义
2* 3.5.2 函数说明
3* 3.5.3 函数源码分析
4
-
-
技术交流
1 libevent简介
libevent是一个事件通知库,适用于windows、linux、bsd等多种平台,内部使用select、epoll、kqueue、IOCP等系统调用管理事件机制。著名分布式缓存软件memcached也是基于libevent,而且libevent在使用上可以做到跨平台,而且根据libevent官方网站上公布的数据统计,似乎也有着非凡的性能。
2 工作原理
2.1 工作流程图
1 首先初始化一个event_base。调用event_init()
2 新生成一个事件event。设置好监听的对象,监听对象的动作,动作产生之后的回调函数,已经回调函数的参数。掉用event_set()完成。
3 设置事件所属的event_base。调用event_base_set()完成。
4 注册这个事件。主要通过event_add()完成。
a)对于定时事件,libevent使用一个小根堆管理,key为超时时间,timeheap;
b)对于I/O事件,libevent将其放入到等待链表(wait list)中,这是一个双向链表结构 eventqueue;
c)对于Signal和,libevent将其放入到sig集合中
5 程序调用event_base_dispatch()系列函数进入无限循环,等待事件,
以epoll()函数为例;
每次循环前libevent会检查定时事件的最小超时时间tv,根据tv设置select()的最大等待时间,以便于后面及时处理超时事件;
当epoll()返回后,首先检查超时事件,然后检查I/O事件;
Libevent将所有的就绪事件,放入到激活链表中;
然后对激活链表中的事件,调用事件的回调函数执行事件处理activequeues;
2.2 Reactor模式框架
3 源码分析
3.1 event_init()
3.1.1 函数定义
1
2
3 1struct event_base * event_init(void)
2
3
3.1.2 函数说明
首先初始化struct event_base 变量,并保存返回的指针。实际上这一步相当于初始化一个 Reactor 实例;在初始化 libevent 后,就可以注册事件了。
3.1.3 函数源码分析
1 struct event_base。事件基础类,相当于Reactor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 1struct event_base {
2 const struct eventop *evsel; ////表示选择的事件引擎,可能为:epoll, poll, select
3 void *evbase; //指向IO复用机制真正存储的数据,它通过evsel成员的init函数来进行初始化
4 int event_count; /* counts number of total events */
5 int event_count_active; /* counts number of active events */
6
7 int event_gotterm; /* Set to terminate loop */
8 int event_break; /* Set to terminate loop immediately */
9
10 /* active event management */
11 struct event_list **activequeues;
12 /*是一个二级指针,前面讲过libevent支持事件优先级,因此你可以把它看作是数组,
13 * 其中的元素activequeues[priority]是一个链表, 链表的每个节点指向一个优先级为priority的就绪事件event。*/
14 int nactivequeues;
15
16 /* signal handling info */
17 struct evsignal_info sig;
18
19 struct event_list eventqueue;////链表,保存了所有的注册事件event的指针。
20 struct timeval event_tv; //系统的当前时间
21
22 struct min_heap timeheap;////用来检测事件是否超时的堆栈,是管理定时事件的小根堆
23
24 struct timeval tv_cache;//与event::ev_timeout进行比较,确定事件是否超时
25};
26
27
2 struct eventop,Libevent为了封装IO复用技术,定义了一个统一的事件操作结构体eventop。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 1//Libevent为了封装IO复用技术,定义了一个统一的事件操作结构体eventop:
2//这里可以理解为定了了一个类eventop。 epoll、 poll、 dev/poll、 select 和 kqueue都是这个类的实例
3//类的属性是name,need_reinit
4//类方法是init,add,del,dispatch,dealloc
5struct eventop {
6 const char *name; // 后端IO复用技术的名称
7 void *(*init)(struct event_base *);
8 int (*add)(void *, struct event *);
9 int (*del)(void *, struct event *);
10 int (*dispatch)(struct event_base *, void *, struct timeval *);
11 void (*dealloc)(struct event_base *, void *);
12 /* set if we need to reinitialize the event base */
13 int need_reinit;
14};
15
16/*epoll.c 定义实例epollops,(默认方式)
17 *epollops可以理解为是eventop一个实例。
18 * 如果是面向对象写的, eventop epollops = new eventop("epoll",epoll_init,epoll_add,epoll_del,epoll_dispatch,epoll_dealloc,)
19*/
20const struct eventop epollops = {
21 "epoll",
22 epoll_init,
23 epoll_add,
24 epoll_del,
25 epoll_dispatch,
26 epoll_dealloc,
27 1 /* need reinit */
28};
29
30/*
31 poll.c 定义实例pollops
32*/
33const struct eventop pollops = {
34 "poll",
35 poll_init,
36 poll_add,
37 poll_del,
38 poll_dispatch,
39 poll_dealloc,
40 0
41};
42
43/*
44 select.c 定义实例selectops
45*/
46const struct eventop selectops = {
47 "select",
48 select_init,
49 select_add,
50 select_del,
51 select_dispatch,
52 select_dealloc,
53 0
54};
55
56
57
3 event_init 初始化了一个struct event_base变量,并且会选择I/O复用的具体类型。这里Linux下面默认是epoll。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 1struct event_base *
2event_init(void)
3{
4 struct event_base *base = event_base_new();
5
6 if (base != NULL)
7 current_base = base;
8
9 return (base);
10}
11
12struct event_base *
13event_base_new(void)
14{
15 int i;
16 struct event_base *base;
17
18
19
20 //设置base->timeheap = -1
21 min_heap_ctor(&base->timeheap);
22 TAILQ_INIT(&base->eventqueue);
23
24 //设置信号量
25 base->sig.ev_signal_pair[0] = -1;
26 base->sig.ev_signal_pair[1] = -1;
27
28 base->evbase = NULL;
29
30 //选择事件驱动类型;eventops 数组第一个元素是epoll
31 for (i = 0; eventops[i] && !base->evbase; i++) {
32 base->evsel = eventops[i]; //&epollops
33
34 /* 指向IO复用机制真正存储的数据,它通过evsel成员的init函数来进行初始化 */
35 /* 比如epoll时,evbase指向的是epollop 这个地方很重要*/
36 base->evbase = base->evsel->init(base);
37 }
38
39
40 /* allocate a single active event queue */
41 event_base_priority_init(base, 1);
42
43 return (base);
44}
45
46
4 base->evbase = base->evsel->init(base);在epoll方式中实际上是调用的epoll_init。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 1struct evepoll {
2 struct event *evread; //读回调事件
3 struct event *evwrite;//写回调事件
4};
5
6typedef union epoll_data
7{
8 void *ptr;
9 int fd;
10 uint32_t u32;
11 uint64_t u64;
12} epoll_data_t;
13
14struct epoll_event
15{
16 uint32_t events; /* Epoll events */
17 epoll_data_t data; /* User data variable */
18} __attribute__ ((__packed__));
19
20
21struct epollop {
22 struct evepoll *fds; //你关注的socket数组,hash[fd] = evepoll。evepoll是事件struct event
23 int nfds;//您关注socket数的大小
24 struct epoll_event *events; //epoll_event数组
25 int nevents; //epoll_event数组大小默认是32
26 int epfd; //epoll_create(32000),你关注的socket以及socket上面发生的事件
27};
28
29static void *
30epoll_init(struct event_base *base)
31{
32 int epfd;
33 struct epollop *epollop;
34
35 /* Disable epollueue when this environment variable is set */
36 if (evutil_getenv("EVENT_NOEPOLL"))
37 return (NULL);
38
39 /* Initalize the kernel queue */
40 //函数生成一个epoll专用的文件描述符。它其实是在内核申请一空间,用来存放你想关注的socket fd上是否发生以及发生了什么事件。size(32000)就是你在这个epoll fd上能关注的最大socket fd数。随你定好了。只要你有空间
41 if ((epfd = epoll_create(32000)) == -1) {
42 if (errno != ENOSYS)
43 event_warn("epoll_create");
44 return (NULL);
45 }
46
47 FD_CLOSEONEXEC(epfd);
48
49 if (!(epollop = calloc(1, sizeof(struct epollop))))
50 return (NULL);
51
52 //epfd 赋值给epollop
53 epollop->epfd = epfd;
54
55 /* Initalize fields 初始值:32 个epoll_event*/
56 epollop->events = malloc(INITIAL_NEVENTS * sizeof(struct epoll_event));
57 if (epollop->events == NULL) {
58 free(epollop);
59 return (NULL);
60 }
61 epollop->nevents = INITIAL_NEVENTS;
62
63 //初始值 32 个 evepoll
64 epollop->fds = calloc(INITIAL_NFILES, sizeof(struct evepoll));
65 if (epollop->fds == NULL) {
66 free(epollop->events);
67 free(epollop);
68 return (NULL);
69 }
70 epollop->nfds = INITIAL_NFILES;
71
72 evsignal_init(base);
73
74 return (epollop);
75}
76
77
3.2 event_set()
3.2.1 函数定义
1
2
3 1void event_set(struct event *ev, int fd, short events, void (*callback)(int, short, void *), void *arg)
2
3
3.2.2 函数说明
event_set 初始化事件event,设置回调函数和关注的事件。
参数说明:
ev:执行要初始化的event对象;
fd:该event绑定的“句柄”,对于信号事件,它就是关注的信号;
events:在该fd上关注的事件类型,它可以是EV_READ, EV_WRITE, EV_SIGNAL;
callback:这是一个函数指针,当fd上的事件event发生时,调用该函数执行处理,它有三个参数,调用时由event_base负责传入,按顺序,实际上就是event_set时的fd, event和arg;
arg:传递给callback函数指针的参数;
定时事件说明:evtimer_set(&ev, timer_cb, NULL) = event_set(&ev, -1, 0, timer_cb, NULL)
由于定时事件不需要fd,并且定时事件是根据添加时(event_add)的超时值设定的,因此这里event也不需要设置。
这一步相当于初始化一个event handler,在libevent中事件类型保存在event结构体中。
注意:libevent并不会管理event事件集合,这需要应用程序自行管理;
3.2.3 函数源码分析
1 struct event结构体分析。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 1struct event {
2 TAILQ_ENTRY (event) ev_next;
3 TAILQ_ENTRY (event) ev_active_next;
4 TAILQ_ENTRY (event) ev_signal_next;
5 unsigned int min_heap_idx; /* for managing timeouts 用于管理超时默认是-1 */
6
7 struct event_base *ev_base; //属于哪个一event_base
8
9 int ev_fd; //设置事件监听对象,也就是监听句柄
10 short ev_events; //设置监听对象触发的动作:EV_READ, EV_WRITE, EV_SIGNAL,EV_TIMEOUT,EV_PERSIST
11 short ev_ncalls; //事件被调用了几次
12 short *ev_pncalls; /* Allows deletes in callback */
13
14 struct timeval ev_timeout;
15
16 int ev_pri; /* smaller numbers are higher priority */
17
18 //设置事件的回调函数
19 void (*ev_callback)(int, short, void *arg);
20
21 //设置事件的回调函数的参数
22 void *ev_arg;
23
24 int ev_res; /* result passed to event callback */
25 int ev_flags; //事件的状态,EVLIST_INIT,EVLIST_INTERNAL,EVLIST_ACTIVE,EVLIST_SIGNAL,EVLIST_INSERTED,EVLIST_TIMEOUT
26};
27
28
2 event_set源码分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 1void
2event_set(struct event *ev, int fd, short events,
3 void (*callback)(int, short, void *), void *arg)
4{
5 /* Take the current base - caller needs to set the real base later */
6
7 //设置当前的event_base,默认是current_base,后面可以通过event_base_set重新设置
8 ev->ev_base = current_base;
9
10 //设置事件的回调函数
11 ev->ev_callback = callback;
12 //设置事件的回调函数的参数
13 ev->ev_arg = arg;
14
15 //设置事件监听对象,也就是监听句柄
16 ev->ev_fd = fd;
17
18 //设置监听对象触发的动作:EV_READ, EV_WRITE, EV_SIGNAL
19 ev->ev_events = events;
20 ev->ev_res = 0;
21 ev->ev_flags = EVLIST_INIT; //设置事件的状态
22 ev->ev_ncalls = 0;
23 ev->ev_pncalls = NULL;
24
25 min_heap_elem_init(ev);
26
27 /* by default, we put new events into the middle priority */
28 if(current_base)
29 ev->ev_pri = current_base->nactivequeues/2;
30}
31
32
3.3 event_base_set()
3.3.1 函数定义
1
2
3 1int event_base_set(struct event_base *base, struct event *ev)
2
3
3.3.2 函数说明
设置event从属的event_base,这一步相当于指明event要注册到哪个event_base实例上。
3.3.3 函数源码分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14 1int
2event_base_set(struct event_base *base, struct event *ev)
3{
4 /* Only innocent events may be assigned to a different base */
5 if (ev->ev_flags != EVLIST_INIT)
6 return (-1);
7
8 ev->ev_base = base; //设置event的event_base
9 ev->ev_pri = base->nactivequeues/2;
10
11 return (0);
12}
13
14
3.4 event_add()
3.4.1 函数定义
1
2
3 1int event_add(struct event *ev, const struct timeval *tv)
2
3
3.4.2 函数说明
基本信息都已设置完成,只要简单的调用event_add()函数即可完成,其中tv是定时值;这一步相当于调用Reactor::register_handler()函数注册事件。
3.4.3 函数源码分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 1int
2event_add(struct event *ev, const struct timeval *tv)
3{
4 struct event_base *base = ev->ev_base; //自己事件所属的event_base
5 const struct eventop *evsel = base->evsel; //示选择的事件模型,这里默认是epllo
6 void *evbase = base->evbase;////事件模型存储数据的地址指针
7 int res = 0;
8
9 // tv不为0设置了,超时事件
10 if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
11 if (min_heap_reserve(&base->timeheap,
12 1 + min_heap_size(&base->timeheap)) == -1)
13 return (-1); /* ENOMEM == errno */
14 }
15
16 //1将ev存放到evsel事件模型的数据evbase中,2 将ev插入到&base->eventqueue的末尾
17 if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
18 !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
19
20 //将ev添加到evbase(epoll:epollop)的fds中(这个地方很重要,相当调用了epoll_add)
21 res = evsel->add(evbase, ev);
22 if (res != -1)
23 event_queue_insert(base, ev, EVLIST_INSERTED); //添加到base->eventqueue的末尾
24 }
25}
26
27
epoll_add 函数中,主要是向内核注册监听事件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 1static int
2epoll_add(void *arg, struct event *ev)
3{
4 struct epollop *epollop = arg;
5 struct epoll_event epev = {0, {0}};
6 struct evepoll *evep;
7 int fd, op, events;
8
9 if (ev->ev_events & EV_SIGNAL)
10 return (evsignal_add(ev));
11
12 fd = ev->ev_fd;
13 if (fd >= epollop->nfds) {
14 /* Extent the file descriptor array as necessary */
15 if (epoll_recalc(ev->ev_base, epollop, fd) == -1)
16 return (-1);
17 }
18
19 //给fd分配一个epollop。hash[fd] = evep。
20 evep = &epollop->fds[fd];
21 op = EPOLL_CTL_ADD;
22 events = 0;
23
24 //读
25 if (evep->evread != NULL) {
26 events |= EPOLLIN;
27 op = EPOLL_CTL_MOD;
28 }
29
30 //写
31 if (evep->evwrite != NULL) {
32 events |= EPOLLOUT;
33 op = EPOLL_CTL_MOD;
34 }
35
36 //读事件
37 if (ev->ev_events & EV_READ)
38 events |= EPOLLIN;
39 //写事件
40 if (ev->ev_events & EV_WRITE)
41 events |= EPOLLOUT;
42
43 epev.data.fd = fd;
44 epev.events = events;
45 /* epoll_ctl:epoll的事件注册函数
46 * epollop->epfd:由 epoll_create 生成的epoll专用的文件描述符
47 * op:要进行的操作例如注册事件,可能的取值EPOLL_CTL_ADD 注册、EPOLL_CTL_MOD 修 改、EPOLL_CTL_DEL 删除
48 * ev->ev_fd:监听的对象,也就是监听事件的句柄。
49 * epev:指向epoll_event的指针。主要包含2部分信息:epev.data.fd = 监听的对象。
50 * epev.events = events监听对象的事件类型读或者写。
51 */
52 if (epoll_ctl(epollop->epfd, op, ev->ev_fd, &epev) == -1)
53 return (-1);
54
55 /* Update events responsible */
56 if (ev->ev_events & EV_READ)
57 evep->evread = ev; //读回调处理ev
58 if (ev->ev_events & EV_WRITE)
59 evep->evwrite = ev; //写回调处理ev
60
61 return (0);
62}
63
64
3.5 event_base_loop()
3.5.1 函数定义
1
2
3 1int event_base_loop(struct event_base *base, int flags)
2
3
3.5.2 函数说明
程序进入无限循环,等待就绪事件并执行事件处理
event_base *base:event_base
flags:超时时间。
3.5.3 函数源码分析
1 event_base_loop,主要是通过evsel->dispatch(base, evbase, tv_p),真实调用了epoll_dispatch(),epoll_dispatch()函数中要是是调用了内核的epoll_wait,epoll_wait是阻塞等待关注的有事件发生。如果有关注时间的发生之后调用event_active将事件写入到event_base的激活事件队列中。如果有激活的队列,调用event_process_active(base)去执行激活的队列。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 1int
2event_base_loop(struct event_base *base, int flags)
3{
4 const struct eventop *evsel = base->evsel;//网络I/O模型,epoll
5 void *evbase = base->evbase;//模型中数据存储,epollop
6 struct timeval tv;
7
8 struct timeval *tv_p;
9 int res, done;
10
11 /* clear time cache */
12 base->tv_cache.tv_sec = 0;
13
14 if (base->sig.ev_signal_added)
15 evsignal_base = base;
16 done = 0;
17 while (!done) {
18
19 /*没有注册的事件,就退出 */
20 if (!event_haveevents(base)) {
21 event_debug(("%s: no events registered.", __func__));
22 return (1);
23 }
24
25 // 调用系统I/O demultiplexer等待就绪I/O events,可能是epoll_wait,或者select等;
26 // 在evsel->dispatch()中,会把就绪signal event、I/O event插入到激活链表中
27 //epoll模型,主要调用的是epoll_dispatch
28 res = evsel->dispatch(base, evbase, tv_p);
29
30 if (res == -1)
31 return (-1);
32 gettime(base, &base->tv_cache);
33
34 timeout_process(base);
35
36 // 调用event_process_active()处理激活链表中的就绪event,调用其回调函数执行事件处理
37 // 该函数会寻找最高优先级(priority值越小优先级越高)的激活事件链表,
38 // 然后处理链表中的所有就绪事件;
39 // 因此低优先级的就绪事件可能得不到及时处理;
40 if (base->event_count_active) {
41 event_process_active(base);
42 if (!base->event_count_active && (flags & EVLOOP_ONCE))
43 done = 1;
44 } else if (flags & EVLOOP_NONBLOCK)
45 done = 1;
46 }
47
48 /* clear time cache */
49 base->tv_cache.tv_sec = 0;
50
51
52 return (0);
53}
54
55
2 epoll_dispatch()函数,主要是函数中要是是调用了内核的epoll_wait,epoll_wait是阻塞等待关注的有事件发生。如果有关注时间的发生之后调用event_active将事件写入到event_base的激活事件列表中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 1static int
2epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
3{
4 struct epollop *epollop = arg;
5 struct epoll_event *events = epollop->events;
6 struct evepoll *evep;
7 int i, res, timeout = -1;
8
9 if (tv != NULL)
10 timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
11
12 if (timeout > MAX_EPOLL_TIMEOUT_MSEC) {
13 /* Linux kernels can wait forever if the timeout is too big;
14 * see comment on MAX_EPOLL_TIMEOUT_MSEC. */
15 timeout = MAX_EPOLL_TIMEOUT_MSEC;
16 }
17
18 /* 等待事件触发,当超过timeout还没有事件触发时,就超时
19 * epfd:由epoll_create 生成的epoll专用的文件描述符;
20 * epoll_event:用于回传代处理事件的数组;
21 * maxevents:每次能处理的事件数;
22 * timeout:等待I/O事件发生的超时值;-1相当于阻塞,0相当于非阻塞。一般用-1即可
23 * res:返回发生事件数
24 *
25 * epoll_wait工作原理:
26 * poll_wait运行的原理是
27 * 等侍注册在epfd上的socket fd的事件的发生,如果发生则将发生的sokct fd和事件类型放入到events数组中。
28 * 并 且将注册在epfd上的socket fd的事件类型给清空,所以如果下一个循环你还要关注这个socket fd的话
29 * ,则需要用epoll_ctl(epfd,EPOLL_CTL_MOD,listenfd,&ev)来重新设置socket fd的事件类型。
30 * 这时不用EPOLL_CTL_ADD,因为socket fd并未清空,只是事件类型清空。这一步非常重要。
31 */
32 res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
33
34 if (res == -1) {
35 if (errno != EINTR) {
36 event_warn("epoll_wait");
37 return (-1);
38 }
39
40 evsignal_process(base);
41 return (0);
42 } else if (base->sig.evsignal_caught) {
43 evsignal_process(base);
44 }
45
46
47 for (i = 0; i < res; i++) {
48 int what = events[i].events;
49 struct event *evread = NULL, *evwrite = NULL;
50 int fd = events[i].data.fd; //拿到触发事件的socketId
51
52 if (fd < 0 || fd >= epollop->nfds)
53 continue;
54
55 //从epollop->fds[fd]找到回调evep。epollop->fds[fd] = evep,hash结构。
56 evep = &epollop->fds[fd];
57
58 //获取读写回调event
59 if (what & (EPOLLHUP|EPOLLERR)) {
60 evread = evep->evread;
61 evwrite = evep->evwrite;
62 } else {
63 if (what & EPOLLIN) {
64 evread = evep->evread;
65 }
66
67 if (what & EPOLLOUT) {
68 evwrite = evep->evwrite;
69 }
70 }
71
72 if (!(evread||evwrite))
73 continue;
74
75 //将读写放到激活队列中
76 if (evread != NULL)
77 event_active(evread, EV_READ, 1);
78 if (evwrite != NULL)
79 event_active(evwrite, EV_WRITE, 1);
80 }
81
82 //扩容
83 if (res == epollop->nevents && epollop->nevents < MAX_NEVENTS) {
84 /* We used all of the event space this time. We should
85 be ready for more events next time. */
86 int new_nevents = epollop->nevents * 2;
87 struct epoll_event *new_events;
88
89 new_events = realloc(epollop->events,
90 new_nevents * sizeof(struct epoll_event));
91 if (new_events) {
92 epollop->events = new_events;
93 epollop->nevents = new_nevents;
94 }
95 }
96
97 return (0);
98}
99
100
3 event_active函数,主要是讲激活的event加入激活队列中:base->activequeues。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 1//放入到激活队列中,ev:事件,res:EV_READ|EV_WRITE,ncalls:调用次数:1
2void
3event_active(struct event *ev, int res, short ncalls)
4{
5 /* We get different kinds of events, add them together */
6 if (ev->ev_flags & EVLIST_ACTIVE) {
7 ev->ev_res |= res;
8 return;
9 }
10
11 ev->ev_res = res;
12 ev->ev_ncalls = ncalls;
13 ev->ev_pncalls = NULL;
14 event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
15}
16
17
4 event_process_active主要是处理激活队列中的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 1static void
2event_process_active(struct event_base *base)
3{
4 struct event *ev;
5 struct event_list *activeq = NULL;
6 int i;
7 short ncalls;
8
9 ////获得就绪链表中有就绪事件并且高优先级的表头
10 for (i = 0; i < base->nactivequeues; ++i) {
11 if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
12 activeq = base->activequeues[i];
13 break;
14 }
15 }
16
17 assert(activeq != NULL);
18
19 for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
20 if (ev->ev_events & EV_PERSIST)
21 event_queue_remove(base, ev, EVLIST_ACTIVE);
22 else
23 event_del(ev);//如果不是永久事件则需要进行一系统的删除工作,包括移除注册在事件链表的事件等
24
25 /* Allows deletes to work */
26 ncalls = ev->ev_ncalls;
27 ev->ev_pncalls = &ncalls;
28 while (ncalls) {
29 ncalls--;
30 ev->ev_ncalls = ncalls;
31 //根据回调次数调用回调函数
32 (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
33 if (event_gotsig || base->event_break)
34 return;
35 }
36 }
37}
38
39