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