libevent源码分析

释放双眼,带上耳机,听听看~!

文章目录

  • 1 libevent简介

  • 2 工作原理

    • 2.1 工作流程图
    • 2.2 Reactor模式框架
  • 3 源码分析

    • 3.1 event_init()

      
      
      1
      2
      3
      4
      1* 3.1.1 函数定义
      2* 3.1.2 函数说明
      3* 3.1.3 函数源码分析
      4
    • 3.2 event_set()

      
      
      1
      2
      3
      4
      1* 3.2.1 函数定义
      2* 3.2.2 函数说明
      3* 3.2.3 函数源码分析
      4
    • 3.3 event_base_set()

      
      
      1
      2
      3
      4
      1* 3.3.1 函数定义
      2* 3.3.2 函数说明
      3* 3.3.3 函数源码分析
      4
    • 3.4 event_add()

      
      
      1
      2
      3
      4
      1* 3.4.1 函数定义
      2* 3.4.2 函数说明
      3* 3.4.3 函数源码分析
      4
    • 3.5 event_base_loop()

      
      
      1
      2
      3
      4
      1* 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

给TA打赏
共{{data.count}}人
人已打赏
安全经验

Google Adsense广告CPC(单元点击价格)为什么会减少??

2021-10-11 16:36:11

安全经验

安全咨询服务

2022-1-12 14:11:49

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索