1. 程式人生 > >13.Redis事件模型

13.Redis事件模型

void aeMain(aeEventLoop *eventLoop) {

    eventLoop->stop = 0;

    while (!eventLoop->stop) {

        // 進入事件迴圈可能會進入睡眠狀態。在睡眠之前,執行預設定的函式 aeSetBeforeSleepProc()。

        if (eventLoop->beforesleep != NULL)

            eventLoop->beforesleep(eventLoop);

        // AE_ALL_EVENTS 表示處理所有的事件

        aeProcessEvents(eventLoop, AE_ALL_EVENTS);

    }

}

// 先處理定時事件,然後處理套接字事件

int aeProcessEvents(aeEventLoop *eventLoop, int flags)

{

    int processed = 0, numevents;

    /* Nothing to do? return ASAP */

    if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0;

    /* Note that we want call select() even if there are no

     * file events to process as long as we want to process time

     * events, in order to sleep until the next time event is ready

     * to fire. */

    if (eventLoop->maxfd != -1 ||

        ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) {

        int j;

        aeTimeEvent *shortest = NULL;

        // tvp 會在 IO 多路複用的函式呼叫中用到,表示超時時間

        struct timeval tv, *tvp;

        // 得到最短將來會發生的定時事件

        if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT))

            shortest = aeSearchNearestTimer(eventLoop);

        // 計算睡眠的最短時間

        if (shortest) { // 存在定時事件

            long now_sec, now_ms;

            /* Calculate the time missing for the nearest

             * timer to fire. */

            // 得到當前時間

            aeGetTime(&now_sec, &now_ms);

            tvp = &tv;

            tvp->tv_sec = shortest->when_sec - now_sec;

            if (shortest->when_ms < now_ms) { // 需要借位

                // 減法中的借位,毫秒向秒借位

                tvp->tv_usec = ((shortest->when_ms+1000) - now_ms)*1000;

                tvp->tv_sec --;

            } else { // 不需要借位,直接減

                tvp->tv_usec = (shortest->when_ms - now_ms)*1000;

            }

            // 當前系統時間已經超過定時事件設定的時間

            if (tvp->tv_sec < 0) tvp->tv_sec = 0;

            if (tvp->tv_usec < 0) tvp->tv_usec = 0;

        } else {

            /* If we have to check for events but need to return

             * ASAP because of AE_DONT_WAIT we need to set the timeout

             * to zero */

            // 如果沒有定時事件,見機行事

            if (flags & AE_DONT_WAIT) {

                tv.tv_sec = tv.tv_usec = 0;

                tvp = &tv;

            } else {

                /* Otherwise we can block */

                tvp = NULL; /* wait forever */

            }

        }

        // 呼叫 IO 多路複用函式阻塞監聽

        numevents = aeApiPoll(eventLoop, tvp);

        // 處理已經觸發的事件

        for (j = 0; j < numevents; j++) {

            // 找到 I/O 事件表中儲存的資料

            aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];

            int mask = eventLoop->fired[j].mask;

            int fd = eventLoop->fired[j].fd;

            int rfired = 0;

         /* note the fe->mask & mask & ... code: maybe an already processed

             * event removed an element that fired and we still didn't

             * processed, so we check if the event is still valid. */

            // 讀事件

            if (fe->mask & mask & AE_READABLE) {

                rfired = 1;

                fe->rfileProc(eventLoop,fd,fe->clientData,mask);

            }

            // 寫事件

            if (fe->mask & mask & AE_WRITABLE) {

                if (!rfired || fe->wfileProc != fe->rfileProc)

                    fe->wfileProc(eventLoop,fd,fe->clientData,mask);

            }

            processed++;

        }

    }

    // 處理定時事件

    /* Check time events */

    if (flags & AE_TIME_EVENTS)

        processed += processTimeEvents(eventLoop);

    return processed; /* return the number of processed file/time events */

}