1. 程式人生 > >libevent 信號事件實現方式

libevent 信號事件實現方式

意思 isp turn cte ret argc lec print tail

學會使用libevent,才能真正的掌握其是實現原理,我們先從一個簡短的測試用例開始:

  1 #include <sys/types.h>
  2 #include <sys/stat.h>
  3 #include <sys/queue.h>
  4 #include <unistd.h>
  5 #include <sys/time.h>
  6 
  7 #include <signal.h>
  8 #include <fcntl.h>
  9 #include <stdlib.h>
 10 #include <stdio.h>
 11
#include <string.h> 12 #include <errno.h> 13 #include <event.h> 14 15 16 int called = 0; 17 static void signall_cb(int fd, short event, void *arg) 18 { 19 struct event *signal = arg; 20 printf("%s: got signal %d\n", __func__, EVENT_SIGNAL(signal)); 21 if (called >= 2
) 22 event_del(signal); 23 called++; 24 } 25 int main (int argc, char **argv) 26 { 27 struct event signal_int; 28 /* Initalize the event library */ 29 event_init(); 30 /* Initalize one event */ 31 event_set(&signal_int, SIGINT, EV_SIGNAL|EV_PERSIST, signall_cb, &signal_int);
32 event_add(&signal_int, NULL); 33 event_dispatch(); 34 return (0); 35 }

該代碼的大體意思是:添加一個信號中斷事件,通過CTRL+C,產生中斷信號,再調用中斷處理函數。

首先分析的是函數是event_init函數,現帖出其具體實現方式



194 struct event_base *
 195 event_base_new(void)
 196 {
 197     int i;
 198     struct event_base *base;
 199 
 200     if ((base = calloc(1, sizeof(struct event_base))) == NULL)
 201         event_err(1, "%s: calloc", __func__);
 202 
 203     event_sigcb = NULL;
 204     event_gotsig = 0;
 205 
 206     detect_monotonic();
 207     /*如果第一次使用初始化,需要將時間緩存保留,在event_base中保留了一個事件*/
 208     gettime(base, &base->event_tv);
 209     /*初始化最小堆,這個堆裏存儲的是時間,在I/O復用的函數裏是使用最小堆中堆頂的值
 210     作為等待的時間參數,這裏只介紹epoll_wait作為I/O復用的方法,這個值就是函數的最後
 211     一個參數,當等待的時間結束,函數返回,也就代表著可能是定時事件被激活
 212     這樣也將定時事件集合到I/O事件*/
 213     min_heap_ctor(&base->timeheap);
 214     /*宏作為初始化的,eventqueue是一個event_list,這裏面存儲著這個event_base所關註的
 215     所有事件*/
 216     TAILQ_INIT(&base->eventqueue);
 217     /*這一對套接字是為了將信號事件融合到I/O事件中所特有的,將其中一個套接字添加到被關註的
 218     行列中,信號事件是通過這一對套接字上來傳遞的,信號到達,其中一個套接字上有I/O事件,
 219     那麽信號到達可以讓I/O返回,這樣便可將信號事件添加到激活隊列中去........*/
 220     base->sig.ev_signal_pair[0] = -1;
 221     base->sig.ev_signal_pair[1] = -1;
 222 
 223     base->evbase = NULL;
 224     /*尋找合適的I/O復用機制,在這裏說明,libevent庫使用的I/O機制是在編譯的時候確定的
 225     其實evbase和某一個復用機制的關系就像類和對象的關系一樣,復用機制是evbase的具體實現
 226     */
 227     printf("default is selected %d  %d  %d\n", HAVE_EPOLL, HAVE_POLL, HAVE_SELECT);
 228 
 229         /*eventops 是一個全局的結構體,結構體中都是不同內核所支持的幾種I/O復用機制*/
 230     for (i = 0; eventops[i] && !base->evbase; i++) {
 231         base->evsel = eventops[i];
194 struct event_base *
195 event_base_new(void)
196 {
197 int i;
198 struct event_base *base;
199
200 if ((base = calloc(1, sizeof(struct event_base))) == NULL)
201 event_err(1, "%s: calloc", __func__);
202
203 event_sigcb = NULL;
204 event_gotsig = 0;
205
206 detect_monotonic();
207 /*如果第一次使用初始化,需要將時間緩存保留,在event_base中保留了一個事件*/
208 gettime(base, &base->event_tv);
209 /*初始化最小堆,這個堆裏存儲的是時間,在I/O復用的函數裏是使用最小堆中堆頂的值
210 作為等待的時間參數,這裏只介紹epoll_wait作為I/O復用的方法,這個值就是函數的最後
211 一個參數,當等待的時間結束,函數返回,也就代表著可能是定時事件被激活
212 這樣也將定時事件集合到I/O事件*/
213 min_heap_ctor(&base->timeheap);
214 /*宏作為初始化的,eventqueue是一個event_list,這裏面存儲著這個event_base所關註的
215 所有事件*/
216 TAILQ_INIT(&base->eventqueue);
217 /*這一對套接字是為了將信號事件融合到I/O事件中所特有的,將其中一個套接字添加到被關註的
218 行列中,信號事件是通過這一對套接字上來傳遞的,信號到達,其中一個套接字上有I/O事件,
219 那麽信號到達可以讓I/O返回,這樣便可將信號事件添加到激活隊列中去........*/
220 base->sig.ev_signal_pair[0] = -1;
221 base->sig.ev_signal_pair[1] = -1;
222
223 base->evbase = NULL;
224 /*尋找合適的I/O復用機制,在這裏說明,libevent庫使用的I/O機制是在編譯的時候確定的
225 其實evbase和某一個復用機制的關系就像類和對象的關系一樣,復用機制是evbase的具體實現
226 */
227 printf("default is selected %d %d %d\n", HAVE_EPOLL, HAVE_POLL, HAVE_SELECT);
228
229 /*eventops 是一個全局的結構體,結構體中都是不同內核所支持的幾種I/O復用機制*/
230 for (i = 0; eventops[i] && !base->evbase; i++) {
231 base->evsel = eventops[i];




 

libevent 信號事件實現方式