zoukankan      html  css  js  c++  java
  • libevent源码学习_event_test

    对应的sample文件中提供了event_test.c,里面就是关于事件的简单示例,具体如下:

     1 /*
     2  * Compile with:
     3  * cc -I/usr/local/include -o event-test event-test.c -L/usr/local/lib -levent
     4  */
     5 
     6 #ifdef HAVE_CONFIG_H
     7 #include "config.h"
     8 #endif
     9 
    10 #include <sys/types.h>
    11 #include <sys/stat.h>
    12 #include <sys/queue.h>
    13 #include <unistd.h>
    14 #include <sys/time.h>
    15 #include <fcntl.h>
    16 #include <stdlib.h>
    17 #include <stdio.h>
    18 #include <string.h>
    19 #include <errno.h>
    20 
    21 #include <event.h>
    22 
    23 static void
    24 fifo_read(int fd, short event, void *arg)
    25 {
    26     char buf[255];
    27     int len;
    28     struct event *ev = arg;
    29 
    30     /* Reschedule this event */
    31     event_add(ev, NULL);
    32 
    33     fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %p
    ",
    34         fd, event, arg);
    35 
    36     len = read(fd, buf, sizeof(buf) - 1);
    37 
    38     if (len == -1) {
    39         perror("read");
    40         return;
    41     } else if (len == 0) {
    42         fprintf(stderr, "Connection closed
    ");
    43         return;
    44     }
    45 
    46     buf[len] = '';
    47 
    48     fprintf(stdout, "Read: %s
    ", buf);
    49 }
    50 
    51 int
    52 main (int argc, char **argv)
    53 {
    54     struct event evfifo;
    55 
    56     struct stat st;
    57     const char *fifo = "event.fifo";
    58     int socket;
    59  
    60     if (lstat (fifo, &st) == 0) {
    61         if ((st.st_mode & S_IFMT) == S_IFREG) {
    62             errno = EEXIST;
    63             perror("lstat");
    64             exit (1);
    65         }
    66     }
    67 
    68     unlink (fifo);
    69     if (mkfifo (fifo, 0600) == -1) {
    70         perror("mkfifo");
    71         exit (1);
    72     }
    73 
    74 
    75     socket = open (fifo, O_RDWR | O_NONBLOCK, 0);
    76 
    77     if (socket == -1) {
    78         perror("open");
    79         exit (1);
    80     }
    81 
    82     fprintf(stderr, "Write data to %s
    ", fifo);
    83 
    84     /* Initalize the event library */
    85     event_init();
    86 
    87     /* Initalize one event */
    88     event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo);
    89 
    90     /* Add it to the active events, without a timeout */
    91     event_add(&evfifo, NULL);
    92     
    93     event_dispatch();
    94 
    95     return (0);
    96 }

    从这个例子中,我们可以看到使用libevent的基本步骤:

    event_init --> event_set --> event_add --> event_dispatch

    下面分步来解析这些函数。

    1、函数event_init()

    位于:event.c

     1 struct event_base *
     2 event_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 }

    比较简单,就是调用了函数event_base_new初始化一个event_base类型的变量,并且将这个变量赋值给一个全局变量current_base。

    2、函数event_base_new()

    位于:event.c

     1 struct event_base *
     2 event_base_new(void)
     3 {
     4     int i;
     5     struct event_base *base;
     6 
     7     /*
     8      * 在堆上分配内存存储event_base,所有字段初始化为0
     9      */
    10     if ((base = calloc(1, sizeof(struct event_base))) == NULL)
    11         event_err(1, "%s: calloc", __func__);
    12 
    13     /*
    14      * 设置use_monotonic变量
    15      */
    16     detect_monotonic();
    17     
    18     /*
    19      * 得到当前时间
    20      */
    21     gettime(base, &base->event_tv);
    22     
    23     /*
    24      * 初始化小根堆
    25      */
    26     min_heap_ctor(&base->timeheap);
    27     
    28     /*
    29      * 初始化注册时间队列
    30      */
    31     TAILQ_INIT(&base->eventqueue);
    32 
    33     /*
    34      * 初始化socketpair
    35      */
    36     base->sig.ev_signal_pair[0] = -1;
    37     base->sig.ev_signal_pair[1] = -1;
    38     
    39     /*
    40      * C语言实现多态
    41      * 根据所支持的系统调用进行对应的初始化
    42      */
    43     base->evbase = NULL;
    44     for (i = 0; eventops[i] && !base->evbase; i++) {
    45         base->evsel = eventops[i];
    46 
    47         base->evbase = base->evsel->init(base);
    48     }
    49 
    50     if (base->evbase == NULL)
    51         event_errx(1, "%s: no event mechanism available", __func__);
    52 
    53     if (evutil_getenv("EVENT_SHOW_METHOD")) 
    54         event_msgx("libevent using: %s
    ",
    55                base->evsel->name);
    56 
    57     /*
    58      * 设置优先级base->nactivequeues,分配数组base->activequeues
    59      * 数组大小和优先级相同
    60      */
    61     /* allocate a single active event queue */
    62     event_base_priority_init(base, 1);
    63 
    64     return (base);
    65 }

    主要做了以下事情:

    (1)给event_base类型变量分配空间

    (2)初始化小根堆【struct min_heap timeheap,位于位于结构体event_base】

    (3)初始化注册事件队列【struct event_list eventqueue,位于位于结构体event_base】

    (4)根据系统支持的系统调用初始化后面真正干活的eventop实例对象【void *evbase,位于结构体event_base】

    (5)调用函数event_base_priority_init() 初始化优先队列,确认的说应该是活跃事件的队列,它是带优先级的,因为这里是最开始的初始化,所以就初始化一个队列,并且它的优先级为1,这个优先级就作为初始化队列的数量。具体见下面函数event_base_priority_init() 的分析

    上面的init以epoll为例,位于:epoll.c

     1 static void *
     2 epoll_init(struct event_base *base)
     3 {
     4     int epfd;
     5     struct epollop *epollop;
     6 
     7     /* Disable epollueue when this environment variable is set */
     8     if (evutil_getenv("EVENT_NOEPOLL"))
     9         return (NULL);
    10 
    11     /* Initalize the kernel queue */
    12     if ((epfd = epoll_create(32000)) == -1) {
    13         if (errno != ENOSYS)
    14             event_warn("epoll_create");
    15         return (NULL);
    16     }
    17 
    18     FD_CLOSEONEXEC(epfd);
    19 
    20     if (!(epollop = calloc(1, sizeof(struct epollop))))
    21         return (NULL);
    22 
    23     epollop->epfd = epfd;
    24 
    25     /* Initalize fields */
    26     epollop->events = malloc(INITIAL_NEVENTS * sizeof(struct epoll_event));
    27     if (epollop->events == NULL) {
    28         free(epollop);
    29         return (NULL);
    30     }
    31     epollop->nevents = INITIAL_NEVENTS;
    32 
    33     epollop->fds = calloc(INITIAL_NFILES, sizeof(struct evepoll));
    34     if (epollop->fds == NULL) {
    35         free(epollop->events);
    36         free(epollop);
    37         return (NULL);
    38     }
    39     epollop->nfds = INITIAL_NFILES;
    40 
    41     evsignal_init(base);
    42 
    43     return (epollop);
    44 }

    调用了系统调用epoll_create,创建出ep_fd,然后初始化了结构体epollop的成员变量。

    1 struct epollop {
    2     struct evepoll *fds;
    3     int nfds;
    4     struct epoll_event *events;
    5     int nevents;
    6     int epfd;
    7 };
    1 struct evepoll {
    2     struct event *evread;
    3     struct event *evwrite;
    4 };

    3、函数event_base_priority_init()

    位于:event.c

     1 int
     2 event_base_priority_init(struct event_base *base, int npriorities)
     3 {
     4     int i;
     5 
     6     /*
     7      * 当前base上有活跃的events则不能设置优先级,返回
     8      */
     9     if (base->event_count_active)
    10         return (-1);
    11 
    12     /*
    13      * 不同,则先释放原先的activequeues数组
    14      */
    15     if (base->nactivequeues && npriorities != base->nactivequeues) {
    16         for (i = 0; i < base->nactivequeues; ++i) {
    17             free(base->activequeues[i]);
    18         }
    19         free(base->activequeues);
    20     }
    21 
    22     /*
    23      * 设置新的优先级
    24      * 设置和优先级值相同大小的event_list数组
    25      */
    26     /* Allocate our priority queues */
    27     base->nactivequeues = npriorities;
    28     base->activequeues = (struct event_list **)
    29         calloc(base->nactivequeues, sizeof(struct event_list *));
    30     
    31     if (base->activequeues == NULL)
    32         event_err(1, "%s: calloc", __func__);
    33 
    34     /*
    35      * 初始化activequeues数组中每个元素
    36      */
    37     for (i = 0; i < base->nactivequeues; ++i) {
    38         base->activequeues[i] = malloc(sizeof(struct event_list));
    39         if (base->activequeues[i] == NULL)
    40             event_err(1, "%s: malloc", __func__);
    41         TAILQ_INIT(base->activequeues[i]);
    42     }
    43 
    44     return (0);
    45 }

    初始化结构体event_base里面的struct event_list **activequeues成员,这是个2维数组,其中的元素activequeues[priority]是一个链表,这个链表里面对应的是相同优先级的事件。

    为了更清晰上面的初始化,附上UML图如下:

    4、函数event_set()

    位于:event.c

     1 void
     2 event_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     ev->ev_base = current_base;
     7 
     8     ev->ev_callback = callback;
     9     ev->ev_arg = arg;
    10     ev->ev_fd = fd;
    11     ev->ev_events = events;
    12     ev->ev_res = 0;
    13     ev->ev_flags = EVLIST_INIT;
    14     ev->ev_ncalls = 0;
    15     ev->ev_pncalls = NULL;
    16 
    17     min_heap_elem_init(ev);
    18 
    19     /* by default, we put new events into the middle priority */
    20     if(current_base)
    21         ev->ev_pri = current_base->nactivequeues/2;
    22 }

    5、函数event_add()

    位于:event.c

     1 int
     2 event_add(struct event *ev, const struct timeval *tv)
     3 {
     4     /*
     5      * 要注册到的event_base
     6      * 得到ev对应的反应堆实例event_base
     7      */
     8     struct event_base *base = ev->ev_base;
     9     const struct eventop *evsel = base->evsel;
    10     void *evbase = base->evbase;
    11     int res = 0;
    12 
    13     event_debug((
    14          "event_add: event: %p, %s%s%scall %p",
    15          ev,
    16          ev->ev_events & EV_READ ? "EV_READ " : " ",
    17          ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
    18          tv ? "EV_TIMEOUT " : " ",
    19          ev->ev_callback));
    20 
    21     assert(!(ev->ev_flags & ~EVLIST_ALL));
    22     
    23     /*
    24      * ev->ev_events表示事件类型
    25      * 如果ev->ev_events是读/写/信号事件,而且ev不在已注册队列或已就绪队列
    26      * 那么调用evbase注册ev事件
    27      */
    28     if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
    29         !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
    30         res = evsel->add(evbase, ev);
    31         if (res != -1)
    32             /*
    33              * 注册成功,插入event到已注册链表中
    34              */
    35             event_queue_insert(base, ev, EVLIST_INSERTED);
    36     }
    37 
    38     return (res);
    39 }

    只留下了关键逻辑,精简了和定时器相关的代码。

    上面的add以epoll为例,位于:epoll.c

     1 static int
     2 epoll_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     /*
    20      * 获得地址,后面给它赋值
    21      */
    22     evep = &epollop->fds[fd];
    23     op = EPOLL_CTL_ADD;
    24     events = 0;
    25 
    26     /*
    27      * 如果原先存在就EPOLL_CTL_MOD而不是EPOLL_CTL_ADD
    28      */
    29     if (evep->evread != NULL) {
    30         events |= EPOLLIN;
    31         op = EPOLL_CTL_MOD;
    32     }
    33     if (evep->evwrite != NULL) {
    34         events |= EPOLLOUT;
    35         op = EPOLL_CTL_MOD;
    36     }
    37 
    38     /*
    39      * 设置关注的事件
    40      */
    41     if (ev->ev_events & EV_READ)
    42         events |= EPOLLIN;
    43     if (ev->ev_events & EV_WRITE)
    44         events |= EPOLLOUT;
    45 
    46     epev.data.fd = fd;
    47     epev.events = events;
    48     if (epoll_ctl(epollop->epfd, op, ev->ev_fd, &epev) == -1)
    49             return (-1);
    50 
    51     /* Update events responsible */
    52     if (ev->ev_events & EV_READ)
    53         evep->evread = ev;
    54     if (ev->ev_events & EV_WRITE)
    55         evep->evwrite = ev;
    56 
    57     return (0);
    58 }

    如果新加入的fd大小大于了之前分配的fd最大个数,则需要调用函数epoll_recalc()重新分配空间,否则就是更新相关的结构体变量,并调用系统调用epoll_ctl来EPOLL_CTL_ADD或EPOLL_CTL_MOD对应的事件。

    函数epoll_recalc()解析如下:

     1 static int
     2 epoll_recalc(struct event_base *base, void *arg, int max)
     3 {
     4     struct epollop *epollop = arg;
     5 
     6     /*
     7      * 当前的fd大于了之前根据最大fd分配的结构体evepoll个数,重新分配,否则直接返回
     8      */
     9     if (max >= epollop->nfds) {
    10         struct evepoll *fds;
    11         int nfds;
    12 
    13         /*
    14           * 每次以2倍大小扩充
    15          */
    16         nfds = epollop->nfds;
    17         while (nfds <= max)
    18             nfds <<= 1;
    19 
    20         /*
    21          * 扩充
    22          */
    23         fds = realloc(epollop->fds, nfds * sizeof(struct evepoll));
    24         if (fds == NULL) {
    25             event_warn("realloc");
    26             return (-1);
    27         }
    28 
    29         /*
    30          * 更新成员变量的值,并且把新扩充的内存清空
    31          */
    32         epollop->fds = fds;
    33         memset(fds + epollop->nfds, 0,
    34             (nfds - epollop->nfds) * sizeof(struct evepoll));
    35         epollop->nfds = nfds;
    36     }
    37 
    38     return (0);
    39 }

    在上面的add完毕后,要把对应的事件放到已注册事件的链表里面。

     1 void
     2 event_queue_insert(struct event_base *base, struct event *ev, int queue)
     3 {
     4     /*
     5      * ev可能已经在激活列表中了,避免重复插入  
     6      */
     7     if (ev->ev_flags & queue) {
     8         /* Double insertion is possible for active events */
     9         if (queue & EVLIST_ACTIVE)
    10             return;
    11 
    12         event_errx(1, "%s: %p(fd %d) already on queue %x", __func__,
    13                ev, ev->ev_fd, queue);
    14     }
    15 
    16     if (~ev->ev_flags & EVLIST_INTERNAL)
    17         base->event_count++;
    18 
    19     /*
    20      * 记录queue标记
    21      */
    22     ev->ev_flags |= queue;
    23     switch (queue) {
    24     /*
    25      * I/O或Signal事件,加入已注册事件链表  
    26      */
    27     case EVLIST_INSERTED:
    28         TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
    29         break;
    30     /*
    31      * 就绪事件,加入激活链表
    32      */
    33     case EVLIST_ACTIVE:
    34         base->event_count_active++;
    35         TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],
    36             ev,ev_active_next);
    37         break;
    38     /*
    39      * 定时事件,加入堆
    40      */
    41     case EVLIST_TIMEOUT: {
    42         min_heap_push(&base->timeheap, ev);
    43         break;
    44     }
    45     default:
    46         event_errx(1, "%s: unknown queue %x", __func__, queue);
    47     }
    48 }

    6、函数event_dispatch()

    位于:event.c

    1 int
    2 event_dispatch(void)
    3 {
    4     return (event_loop(0));
    5 }
    1 /* not thread safe */
    2 
    3 int
    4 event_loop(int flags)
    5 {
    6     return event_base_loop(current_base, flags);
    7 }

    可以看到,用了全局变量current_base,所以它并不是线程安全的。

      1 int
      2 event_base_loop(struct event_base *base, int flags)
      3 {
      4     const struct eventop *evsel = base->evsel;
      5     void *evbase = base->evbase;
      6     struct timeval tv;
      7     struct timeval *tv_p;
      8     int res, done;
      9 
     10     /* clear time cache */
     11     base->tv_cache.tv_sec = 0;
     12     
     13     done = 0;
     14     while (!done) {        
     15         /*
     16          * 校正系统时间,如果系统使用的是非MONOTONIC时间,用户可能会向后调整了系统时间  
     17          * 在timeout_correct函数里,比较last wait time和当前时间
     18          * 如果当前时间< last wait time  表明时间有问题
     19          * 这时需要更新timer_heap中所有定时事件的超时时间。  
     20          */
     21         timeout_correct(base, &tv);
     22 
     23         /*
     24          * 根据timer heap中事件的最小超时时间,计算系统I/O demultiplexer的最大等待时间 
     25          */
     26         tv_p = &tv;
     27         if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) {
     28             timeout_next(base, &tv_p);
     29         } else {
     30             /*
     31              * 依然有未处理的就绪事件,就让I/O demultiplexer立即返回,不必等待  
     32              * 下面会提到,在libevent中,低优先级的就绪事件可能不能立即被处理  
     33              */
     34             /* 
     35              * if we have active events, we just poll new events
     36              * without waiting.
     37              */
     38             evutil_timerclear(&tv);
     39         }
     40         
     41         /* If we have no events, we just exit */
     42         if (!event_haveevents(base)) {
     43             event_debug(("%s: no events registered.", __func__));
     44             return (1);
     45         }
     46 
     47         /* update last old time */
     48         gettime(base, &base->event_tv);
     49 
     50         /* clear time cache */
     51         base->tv_cache.tv_sec = 0;
     52 
     53         /*
     54          * 调用系统I/O demultiplexer等待就绪I/O events,可能是epoll_wait,或者select等;  
     55          * 在evsel->dispatch()中,会把就绪signal event、I/O event插入到激活链表中  
     56          */
     57         res = evsel->dispatch(base, evbase, tv_p);
     58 
     59         if (res == -1)
     60             return (-1);
     61 
     62         /*
     63          * 将time cache赋值为当前系统时间
     64          */
     65         gettime(base, &base->tv_cache);
     66 
     67         /*
     68          * 检查heap中的timer events
     69          * 将就绪的timer event从heap上删除,并插入到激活链表中
     70          */
     71         timeout_process(base);
     72 
     73         /*
     74          * 调用event_process_active()处理激活链表中的就绪event,调用其回调函数执行事件处理  
     75          * 该函数会寻找最高优先级(priority值越小优先级越高)的激活事件链表,  
     76          * 然后处理该链表中的所有就绪事件;  
     77          * 因此低优先级的就绪事件可能得不到及时处理
     78          *
     79          * 见函数event_process_active()的注释:
     80          * Active events are stored in priority queues.  Lower priorities are always
     81          * process before higher priorities.  Low priority events can starve high
     82          * priority ones.
     83          * 
     84          * 在函数event_process_active()里面就是寻找priority值最小的已就绪事件队列
     85          * 找到一个就开始处理里面所有的事件回调了,其他的队列根本就不管了......
     86          * 所以原作者用的Low priority events can starve high priority ones非常贴切
     87          */
     88         if (base->event_count_active) {
     89             /*
     90              * 处理event_base的活跃链表中的事件
     91              * 调用event的回调函数,优先级高的event先处理
     92              */
     93             event_process_active(base);
     94             
     95             if (!base->event_count_active && (flags & EVLOOP_ONCE)) {
     96                 done = 1;
     97             }
     98         } else if (flags & EVLOOP_NONBLOCK) {
     99             done = 1;
    100         }
    101     }
    102 
    103     /* clear time cache */
    104     base->tv_cache.tv_sec = 0;
    105 
    106     event_debug(("%s: asked to terminate loop.", __func__));
    107     return (0);
    108 }

    1、去掉了一些无用的业务逻辑代码。

    2、调用epoll_dispatch来进行事件的分发,激活就绪的事件都弄到激活的链表里面去。

    3、调用timeout_process把超时的事件也弄到激活的链表里面去。

    4、调用event_process_active开始处理,调用对应事件的回调函数;需要注意的是:就是寻找priority值最小的已就绪事件队列,找到一个就开始处理里面所有的事件回调了,其他的队列根本就不管了......所以原作者用的Low priority events can starve high priority ones非常贴切。

    5、关于定时器、时间相关的函数未仔细看。

    函数epoll_dispatch(),位于epoll.c

     1 static int
     2 epoll_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     res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
    19 
    20     if (res == -1) {
    21         if (errno != EINTR) {
    22             event_warn("epoll_wait");
    23             return (-1);
    24         }
    25 
    26         evsignal_process(base);
    27         return (0);
    28     } else if (base->sig.evsignal_caught) {
    29         evsignal_process(base);
    30     }
    31 
    32     event_debug(("%s: epoll_wait reports %d", __func__, res));
    33 
    34     for (i = 0; i < res; i++) {
    35         int what = events[i].events;
    36         struct event *evread = NULL, *evwrite = NULL;
    37         int fd = events[i].data.fd;
    38 
    39         if (fd < 0 || fd >= epollop->nfds)
    40             continue;
    41         evep = &epollop->fds[fd];
    42 
    43         if (what & (EPOLLHUP|EPOLLERR)) {
    44             evread = evep->evread;
    45             evwrite = evep->evwrite;
    46         } else {
    47             if (what & EPOLLIN) {
    48                 evread = evep->evread;
    49             }
    50 
    51             if (what & EPOLLOUT) {
    52                 evwrite = evep->evwrite;
    53             }
    54         }
    55 
    56         if (!(evread||evwrite))
    57             continue;
    58 
    59         if (evread != NULL)
    60             event_active(evread, EV_READ, 1);
    61         if (evwrite != NULL)
    62             event_active(evwrite, EV_WRITE, 1);
    63     }
    64 
    65     if (res == epollop->nevents && epollop->nevents < MAX_NEVENTS) {
    66         /* We used all of the event space this time.  We should
    67            be ready for more events next time. */
    68         int new_nevents = epollop->nevents * 2;
    69         struct epoll_event *new_events;
    70 
    71         new_events = realloc(epollop->events,
    72             new_nevents * sizeof(struct epoll_event));
    73         if (new_events) {
    74             epollop->events = new_events;
    75             epollop->nevents = new_nevents;
    76         }
    77     }
    78 
    79     return (0);
    80 }

    函数event_process_active()

     1 static void
     2 event_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      * 寻找最高优先级(priority值越小优先级越高)的已就绪事件队列
    11      */
    12     for (i = 0; i < base->nactivequeues; ++i) {
    13         if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
    14             activeq = base->activequeues[i];
    15             break;
    16         }
    17     }
    18 
    19     assert(activeq != NULL);
    20 
    21     for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
    22         /*
    23          * 如果有persist标志,则只从激活队列中移除此事件
    24          */
    25         if (ev->ev_events & EV_PERSIST) {
    26             event_queue_remove(base, ev, EVLIST_ACTIVE);
    27         }
    28         /*
    29          * 否则则从激活事件列表、已注册事件、监听事件的兴趣列表中全部干掉此事件
    30          */
    31         else {
    32             event_del(ev);
    33         }
    34         
    35         /* Allows deletes to work */
    36         ncalls = ev->ev_ncalls;
    37         /*
    38          * 每个事件的回调函数的调用次数
    39          */
    40         ev->ev_pncalls = &ncalls;
    41         while (ncalls) {
    42             ncalls--;
    43             ev->ev_ncalls = ncalls;
    44             /*
    45              * 回调
    46              */
    47             (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
    48             if (base->event_break)
    49                 return;
    50         }
    51     }
    52 }

    至此,看了2个下午的libevent事件处理流程收官!

    event-test.c例子中使用一个命名管道(也被称为FIFO文件),它通过读的方式打开一个命名管道,并且监听这个命名管道是否有数据可读,当有数据可读时会执行fifo_read函数,把读取的内容打印出来。

    可以搞一个往这个命名管道写内容的简单的程序,进行测试:

     1 #include <sys/types.h>  
     2 #include <sys/stat.h>  
     3 #include <sys/queue.h>  
     4 #include <sys/time.h>  
     5 #include <fcntl.h>  
     6 #include <stdlib.h>  
     7 #include <stdio.h>  
     8 #include <string.h>  
     9 #include <unistd.h>  
    10 #include <errno.h>  
    11   
    12   
    13 int main(int argc, char **argv)  
    14 {  
    15     char *input = argv[1];  
    16     if (argc != 2)  
    17     {  
    18         input = "hello";  
    19     }  
    20     int fd ;  
    21     fd = open("event.fifo",O_WRONLY);  
    22     if(fd == -1){  
    23         perror("open error");  
    24         exit(EXIT_FAILURE);  
    25     }  
    26   
    27   
    28     write(fd, input, strlen(input));  
    29     close(fd);  
    30     printf("write success
    ");  
    31     return 0;  
    32 }  

    本文参考自:

    http://blog.csdn.net/lyh66/article/details/46328531

    http://www.cnblogs.com/zxiner/category/1010504.html

    http://blog.csdn.net/sparkliang/article/category/660506

  • 相关阅读:
    Js 循环 forEach, map, for, for...in, for...of
    es6 let const
    es6 Symbol类型
    es6 Reflect 与 Proxy
    es6 Map&Set
    es6箭头函数
    es6数组Arrary
    学写网站(一)前端配置之安装nvm、node、npm
    python获取当前执行代码所在文件的地址、主程序所在地址
    scrapy中的选择器下载中间件downloadmiddlewares
  • 原文地址:https://www.cnblogs.com/abc-begin/p/7603130.html
Copyright © 2011-2022 走看看