3.7.5 event_loop:事件循环

来源:互联网 发布:淘宝的消费总额怎么看 编辑:程序博客网 时间:2024/06/07 21:10

当完成了文件描述符与回调函数的“绑定”后,可执行事件循环:循环选择触发事件的文件描述符,执行其回调函数。在event_loop中也执行了定时事件。

/util/event.c998 void    event_loop(int delay)999 {1000     const char *myname = "event_loop";1001     static int nested;10021003 #if(EVENTS_STYLE == EVENTS_STYLE_SELECT)1004     fd_set rmask;1005     fd_set wmask;1006     fd_set xmask;1007     struct timeval tv;1008     struct timeval *tvp;1009     int    new_max_fd;10101011 #else1012     EVENT_BUFFER event_buf[100];1013     EVENT_BUFFER *bp;10141015 #endif

1003-1015 为select多路复用函数准备各个参数。

1016     int    event_count;1017     EVENT_TIMER *timer;1018     int    fd;1019     EVENT_FDTABLE *fdp;1020     int    select_delay;10211022     if (EVENT_INIT_NEEDED())1023         event_init();

1022-1023 如果event_init没有运行,先运行event_init。

10241025     /*1026      * XXX Also print the select() masks?1027      */1028     if (msg_verbose > 2) {1029         RING  *ring;10301031         FOREACH_QUEUE_ENTRY(ring,&event_timer_head) {1032             timer = RING_TO_TIMER(ring);1033             msg_info("%s: time left %3dfor 0x%lx 0x%lx", myname,1034                      (int) (timer->when -event_present),1035                      (long) timer->callback,(long) timer->context);1036         }1037     }10381039     /*1040      * Find out when the next timer would gooff. Timer requests are sorted.1041      * If any timer is scheduled, adjust thedelay appropriately.1042      */1043     if ((timer =FIRST_TIMER(&event_timer_head)) != 0) {1044         event_present = time((time_t *) 0);1045         if ((select_delay = timer->when -event_present) < 0) {1046             select_delay = 0;1047         } else if (delay >= 0 &&select_delay > delay) {1048             select_delay = delay;1049         }1050     } else {1051         select_delay = delay;1052     }

1043-1052 确定多路复用函数的等待时间

 

多路复用函数有等待时间参数。event_loop的参数delay就是用来确定这个值的——但不是唯一由它确定。由于多路复用函数会引发阻塞,所以确定等待时间的原则是:如果当前定时事件已经超时,来不及执行,则将select的等待时间置0,即检查后立即返回,以免妨碍下一个时间事件的执行。否则,如果当前时间事件还来得及执行,那多路复用函数可以阻塞到这个时间事件执行前——这样一方面多路复用函数可以有机会捕获事件,同时也不会影响定时事件的执行。

1053     if (msg_verbose > 2)1054         msg_info("event_loop:select_delay %d", select_delay);10551056     /*1057      * Negative delay means: wait untilsomething happens. Zero delay means:1058      * poll. Positive delay means: wait atmost this long.1059      */1060 #if(EVENTS_STYLE == EVENTS_STYLE_SELECT)1061     if (select_delay < 0) {1062         tvp = 0;1063     } else {1064         tvp = &tv;1065         tv.tv_usec = 0;1066         tv.tv_sec = select_delay;1067     }10681069     /*1070      * Pause until the next event happens.When select() has a problem, don't1071      * go into a tight loop. Allow select() tobe interrupted due to the1072      * arrival of a signal.1073      */1074     rmask = event_rmask;1075     wmask = event_wmask;1076     xmask = event_xmask;10771078     event_count = select(event_max_fd + 1,&rmask, &wmask, &xmask, tvp);1079     if (event_count < 0) {1080         if (errno != EINTR)1081             msg_fatal("event_loop:select: %m");1082         return;1083     }1084 #else


//执行其他I/O多路复用函数

1093 #endif

 

1060-1093 执行多路复用函数。

10941095     /*1096      * Before entering the applicationcall-back routines, make sure we1097      * aren't being called from a call-backroutine. Doing so would make us1098      * vulnerable to all kinds of raceconditions.1099      */1100     if (nested++ > 0)1101         msg_panic("event_loop: recursivecall");11021103     /*1104      * Deliver timer events. Allow theapplication to add/delete timer queue1105      * requests while it is being called back.Requests are sorted: we keep1106      * running over the timer request queuefrom the start, and stop when we1107      * reach the future or the list end. Wealso stop when we reach a timer1108      * request that was added by a call-backthat was invoked from this1109      * event_loop() call instance, for reasonsthat are explained below.1110      *1111      * To avoid dangling pointer problems 1)we must remove a request from the1112      * timer queue before delivering its eventto the application and 2) we1113      * must look up the next timer request*after* calling the application.1114      * The latter complicates the handling ofzero-delay timer requests that1115      * are added by event_loop() call-backfunctions.1116      *1117      * XXX When a timer event call-backfunction adds a new timer request,1118      * event_request_timer() labels therequest with the event_loop() call1119      * instance that invoked the timer eventcall-back. We use this instance1120      * label here to prevent zero-delay timerrequests from running in a1121      * tight loop and starving I/O events. Tomake this solution work,1122      * event_request_timer() appends a newrequest after existing requests1123      * for the same time slot.1124      */1125     event_present = time((time_t *) 0);1126     event_loop_instance += 1;11271128     while ((timer =FIRST_TIMER(&event_timer_head)) != 0) {1129         if (timer->when > event_present)1130             break;1131         if (timer->loop_instance ==event_loop_instance)1132             break;1133         ring_detach(&timer->ring);              /* first this */1134         if (msg_verbose > 2)1135             msg_info("%s: timer 0x%lx0x%lx", myname,1136                      (long)timer->callback, (long) timer->context);1137         timer->callback(EVENT_TIME,timer->context);    /* then this */1138         myfree((void *) timer);1139     }

 

1128-1139 执行时间事件。取得当前未执行的时间事件(EVENT_TIMER节点),如果该时间事件已过期,则跳出。如果该时间事件不是当前上下文的时间事件,则跳出。否则取下当前EVENT_TIMER节点,执行其回调函数。由于event_loop函数总会在循环中被调用。所以在每一轮循环中会选择一个当前可执行时间事件执行。

11401141    /*1142     * Deliver I/O events. Allow the application to cancel event requests1143     * while it is being called back. To this end, we keep an eye on the1144     * contents of event_xmask, so that we deliver only events that are still1145     * wanted. We do not change the event request masks. It is up to the1146     * application to determine when a read or write is complete.1147     */1148 #if (EVENTS_STYLE ==EVENTS_STYLE_SELECT)1149    if (event_count > 0) {1150        for (new_max_fd = 0, fd = 0; fd <= event_max_fd; fd++) {1151             if (FD_ISSET(fd,&event_xmask)) {1152                 new_max_fd = fd;1153                 /* In case event_fdtable isupdated. */1154                 fdp = event_fdtable + fd;1155                 if (FD_ISSET(fd, &xmask)){1156                     if (msg_verbose > 2)1157                         msg_info("%s:exception fd=%d act=0x%lx 0x%lx", myname,1158                              fd, (long)fdp->callback, (long) fdp->context);1159                    fdp->callback(EVENT_XCPT, fdp->context);1160                 } else if (FD_ISSET(fd,&wmask)) {1161                     if (msg_verbose > 2)1162                         msg_info("%s:write fd=%d act=0x%lx 0x%lx", myname,1163                              fd, (long)fdp->callback, (long) fdp->context);1164                    fdp->callback(EVENT_WRITE, fdp->context);1165                 } else if (FD_ISSET(fd,&rmask)) {1166                     if (msg_verbose > 2)1167                         msg_info("%s:read fd=%d act=0x%lx 0x%lx", myname,1168                              fd, (long)fdp->callback, (long) fdp->context);1169                    fdp->callback(EVENT_READ, fdp->context);1170                 }1171             }1172        }1173        event_max_fd = new_max_fd;1174    }1175 #else//执行其他I/O多路复用函数的回调函数。1201 #endif1202    nested--;1203 }

 

1148-1203 扫描多路复用函数文件描述符组,执行读、写、异常事件。

0 0
原创粉丝点击