對應的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