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

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上。这段代码的逻辑应该很简单。

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

上一篇:warning: incompatible implicit declaration of built-in function 'exit'


下一篇:poi读写word模板 / java生成word文档