libevent源代码分析--event_dispatch() (一)

来源:互联网 发布:淘宝网开通淘金币活动 编辑:程序博客网 时间:2024/05/16 00:42

event_dispatch这个函数是以上所有处理都结束以后,最后的一个借口调用,其实和这个函数类似的函数有好几个,接下来一一分析。

int 405 event_dispatch(void) 406 { 407     return (event_loop(0)); 408 }
可以返现event_dispatch只有一个调用event_loop(),
但是event_loop函数的调用呢

int 467 event_loop(int flags) 468 { 469     return event_base_loop(current_base, flags); 470 } 471 
event_loop的调用也是嵌套了一个函数,event_base_loop,那么我们看看这个event_base_loop函数总共被几个函数所调用

int 411 event_base_dispatch(struct event_base *event_base) 412 { 413   return (event_base_loop(event_base, 0)); 414 }
其实最终的调用都是event_base_loop函数,但是不同之处就是传递的第一个参数,这个参数决定了event术语那个event_base,如果使用默认的情况就是current_base,如果是

用户自己的event_base就使用eventbase_diapatch函数。下面分析event_base_loop函数:

int 473 event_base_loop(struct event_base *base, int flags) 474 { 475     const struct eventop *evsel = base->evsel; 476     void *evbase = base->evbase; 477     struct timeval tv; 478     struct timeval *tv_p; 479     int res, done; 480  481     /* clear time cache */             // 清空事件缓冲 482     base->tv_cache.tv_sec = 0; 483       //evsignal_base是全局变量,在处理signale时,用于指出signal所属的event_base实例 484     if (base->sig.ev_signal_added) 485         evsignal_base = base; 486     done = 0; 487     while (!done) { // 事件主循环 查看是否需要跳出循环 程序可以调用event_loopexit_cb()设置event_gotterm标记 调用event_base_loopbreak()设置event_base标记 488         /* Terminate the loop if we have been asked to */ 489         if (base->event_gotterm) { 490             base->event_gotterm = 0; 491             break; 492         } 493  494         if (base->event_break) { 495             base->event_break = 0; 496             break; 497         } 498  499         /* You cannot use this interface for multi-threaded apps */ 500         while (event_gotsig) { 501             event_gotsig = 0; 502             if (event_sigcb) { 503                 res = (*event_sigcb)(); 504                 if (res == -1) { 505                     errno = EINTR; 506                     return (-1); 507                 } 508             } 509         }    510 /// 校正系统时间,如果系统使用的是非MONOTONIC时间,用户可能会向后调整了系统时间 // 在timeout_correct函数里,比较last wait time和当前时间,如果当前时间< last wait time // 表明时间有问题,这是需要更新timer_heap中所有定时事件的超时时间。  511         timeout_correct(base, &tv); 512 // 根据timer heap中事件的最小超时时间,计算系统I/O demultiplexer的最大等待时间  513         tv_p = &tv; 514         if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) { 515             timeout_next(base, &tv_p); 516         } else { /*  518              * if we have active events, we just poll new events 519              * without waiting. 520              */// 依然有未处理的就绪时间,就让I/O demultiplexer立即返回,不必等待 // 下面会提到,在libevent中,低优先级的就绪事件可能不能立即被处理  521             evutil_timerclear(&tv); 522         } 523  524         /* If we have no events, we just exit */// 如果当前没有注册事件,就退出  525         if (!event_haveevents(base)) { 526             event_debug(("%s: no events registered.", __func__)); 527             return (1); 528         } 529  530         /* update last old time */ 531         gettime(base, &base->event_tv); 532  533         /* clear time cache */ 534         base->tv_cache.tv_sec = 0;  535 // 调用系统I/O demultiplexer等待就绪I/O events,可能是epoll_wait,或者select等; // 在evsel->dispatch()中,会把就绪signal event、I/O event插入到激活链表中  536         res = evsel->dispatch(base, evbase, tv_p); 537  538         if (res == -1) 539             return (-1);// 将time cache赋值为当前系统时间   540         gettime(base, &base->tv_cache);  541  // 检查heap中的timer events,将就绪的timer event从heap上删除,并插入到激活链表中  542         timeout_process(base); 543 // 调用event_process_active()处理激活链表中的就绪event,调用其回调函数执行事件处理 // 该函数会寻找最高优先级(priority值越小优先级越高)的激活事件链表, // 然后处理链表中的所有就绪事件; // 因此低优先级的就绪事件可能得不到及时处理;  544         if (base->event_count_active) { 545             event_process_active(base); 546             if (!base->event_count_active && (flags & EVLOOP_ONCE)) 547                 done = 1; 548         } else if (flags & EVLOOP_NONBLOCK) 549             done = 1; 550     } 551  552     /* clear time cache */// 循环结束,清空时间缓存 553     base->tv_cache.tv_sec = 0; 554  555     event_debug(("%s: asked to terminate loop.", __func__)); 556     return (0); 557 }

现在想来,这个函数相当于自己写程序中的I/O复用机制的那个死循环,这个函数操作的对象就是event_base,要么是自己宠幸申请的event_base,要么是系统中的全局current_base,不管是哪个event_base,只要操作这个event_base中所属的event即可,首先找到这个event_base的evsel,这个类型的关系和evbase(现在应该仍然记得evsel和evbase的关系尚且认识是类和对象的关系吧!!!还记得上面欠的两个解释么,没解释的内容和这个以后再详解,姑且这么不理解着吧!!!)

while(!done)循环中头两个if判断都是为了看是够需要退出当前的循环而设立的,往下开始修正系统时间.

timeout_next是取出小根堆中最小的元素,也就是时间最小的。这个最小的事件作为将来系统调用中最大的等待事件,进入timeout_next的判断条件,不是非阻塞,并且没有

被激活的事件。注意取得事件赋值给了tv_p,这个变量在536行又被作为参数传递,这里不得不再欠一个解释,也就是536行的evsel->dispatch.主要的循环解释道这里,下面的这篇文章解释这个函数中使用到的几个重要的函数。

请注意,到目前为止,还没有讲解事件处理的业务逻辑,其实这个函数中,的event_process_active()已经处理了。536行的dispatch知识将就绪的signal event i/o event插入到激活链表中。并没有将时间处理,而timeout_process()是讲就绪的timer event从堆中删除并且插入到激活链表中。而event_process_actibe才是真正的业务逻辑核心部分。

364 static void 365 event_process_active(struct event_base *base) 366 { 367     struct event *ev; 368     struct event_list *activeq = NULL; 369     int i; 370     short ncalls; 371  372     for (i = 0; i < base->nactivequeues; ++i) { 373         if (TAILQ_FIRST(base->activequeues[i]) != NULL) { 374             activeq = base->activequeues[i]; 375             break; 376         } 377     } 378  379     assert(activeq != NULL); 380  381     for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) { 382         if (ev->ev_events & EV_PERSIST) 383             event_queue_remove(base, ev, EVLIST_ACTIVE); 384         else 385             event_del(ev); 386  387         /* Allows deletes to work */ 388         ncalls = ev->ev_ncalls; 389         ev->ev_pncalls = &ncalls; 390         while (ncalls) { 391             ncalls--; 392             ev->ev_ncalls = ncalls; 393             (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg); 394             if (event_gotsig || base->event_break) 395                 return; 396         } 397     } 398 }
首先第一个for循环是从二级链表中查找一个优先级最高的队列,然后从优先级最高的队列中挑选排在第一个的事件进行处理,处理用哪一个函数呢,就是注册过得ev_callback,这个函数还记得怎么来的么?第一个函数event_set,这个函数已经将某一个函数绑定到了某一个event上。这段代码的逻辑应该很简单。

2 0