libevent源碼學習_event_test

對應的sample文件中提供了event_test.c,裏面就是關於事件的簡單示例,具體以下:html

 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\n",
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\n");
43         return;
44     }
45 
46     buf[len] = '\0';
47 
48     fprintf(stdout, "Read: %s\n", 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\n", 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安全

下面分步來解析這些函數。socket

一、函數event_init()函數

位於:event.coop

 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。測試

 

二、函數event_base_new()this

位於:event.cspa

 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\n",
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 }

主要作了如下事情:.net

(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 };

 

三、函數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圖以下:

 

四、函數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 }

 

五、函數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 }

 

 

六、函數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 }

一、去掉了一些無用的業務邏輯代碼。

二、調用epoll_dispatch來進行事件的分發,激活就緒的事件都弄到激活的鏈表裏面去。

三、調用timeout_process把超時的事件也弄到激活的鏈表裏面去。

四、調用event_process_active開始處理,調用對應事件的回調函數;須要注意的是:就是尋找priority值最小的已就緒事件隊列,找到一個就開始處理裏面全部的事件回調了,其餘的隊列根本就無論了......因此原做者用的Low priority events can starve high priority ones很是貼切。

五、關於定時器、時間相關的函數未仔細看。

 

函數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\n");  
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

相關文章
相關標籤/搜索