live555中env->taskScheduler().doEventLoop()

live555为单线程执行,直接执行sleep(),会导致消息接受函数得不到执行,而且会停止所有的工作。

如何在等待的同时,可以进行其他的工作

在live555中使用env->taskScheduler().doEventLoop()进行消息等待。

    void BasicTaskScheduler0::doEventLoop(char* watchVariable) {
        // Repeatedly loop, handling readble sockets and timed events:
        while (1) {
            if (watchVariable != NULL && *watchVariable != 0)
                break;
            SingleStep();
        }
    }

SingleStep()干嘛的呢

SingleStep()每次执行任务队列中的一个,任务队列有以下三种类型:
1.应执行的
2.应响应的
3.应执行的延迟任务



    //循坏中主要执行的函数
    void BasicTaskScheduler::SingleStep(unsigned maxDelayTime) {
        fd_set readSet = fReadSet; // make a copy for this select() call
        fd_set writeSet = fWriteSet; // ditto
        fd_set exceptionSet = fExceptionSet; // ditto

        //计算select socket们时的超时时间。
        DelayInterval const& timeToDelay = fDelayQueue.timeToNextAlarm();
        struct timeval tv_timeToDelay;
        tv_timeToDelay.tv_sec = timeToDelay.seconds();
        tv_timeToDelay.tv_usec = timeToDelay.useconds();
        // Very large "tv_sec" values cause select() to fail.
        // Don't make it any larger than 1 million seconds (11.5 days)
        const long MAX_TV_SEC = MILLION;
        if (tv_timeToDelay.tv_sec > MAX_TV_SEC) {
            tv_timeToDelay.tv_sec = MAX_TV_SEC;
        }
        // Also check our "maxDelayTime" parameter (if it's > 0):
        if (maxDelayTime > 0
                && (tv_timeToDelay.tv_sec > (long) maxDelayTime / MILLION
                        || (tv_timeToDelay.tv_sec == (long) maxDelayTime / MILLION
                                && tv_timeToDelay.tv_usec
                                        > (long) maxDelayTime % MILLION))) {
            tv_timeToDelay.tv_sec = maxDelayTime / MILLION;
            tv_timeToDelay.tv_usec = maxDelayTime % MILLION;
        }

        //先执行socket的select操作,以确定哪些socket任务(handler)需要执行。
        int selectResult = select(fMaxNumSockets,
                &readSet, &writeSet,&exceptionSet,
                &tv_timeToDelay);

        if (selectResult < 0) {
    //#if defined(__WIN32__) || defined(_WIN32)
            int err = WSAGetLastError();
            // For some unknown reason, select() in Windoze sometimes fails with WSAEINVAL if
            // it was called with no entries set in "readSet". If this happens, ignore it:
            if (err == WSAEINVAL && readSet.fd_count == 0) {
                err = EINTR;
                // To stop this from happening again, create a dummy socket:
                int dummySocketNum = socket(AF_INET, SOCK_DGRAM, 0);
                FD_SET((unsigned) dummySocketNum, &fReadSet);
            }
            if (err != EINTR) {
    //#else
    //        if (errno != EINTR && errno != EAGAIN) {
    //#endif
                // Unexpected error - treat this as fatal:
    //#if !defined(_WIN32_WCE)
    //            perror("BasicTaskScheduler::SingleStep(): select() fails");
    //#endif
                internalError();
            }
        }

        // Call the handler function for one readable socket:
        HandlerIterator iter(*fHandlers);
        HandlerDescriptor* handler;
        // To ensure forward progress through the handlers, begin past the last
        // socket number that we handled:
        if (fLastHandledSocketNum >= 0) {
            //找到上次执行的socket handler的下一个
            while ((handler = iter.next()) != NULL) {
                if (handler->socketNum == fLastHandledSocketNum)
                    break;
            }
            if (handler == NULL) {
                fLastHandledSocketNum = -1;
                iter.reset(); // start from the beginning instead
            }
        }

        //从找到的handler开始,找一个可以执行的handler,不论其状态是可读,可写,还是出错,执行之。
        while ((handler = iter.next()) != NULL) {
            int sock = handler->socketNum; // alias
            int resultConditionSet = 0;
            if (FD_ISSET(sock, &readSet)
                    && FD_ISSET(sock, &fReadSet)/*sanity check*/)
                resultConditionSet |= SOCKET_READABLE;
            if (FD_ISSET(sock, &writeSet)
                    && FD_ISSET(sock, &fWriteSet)/*sanity check*/)
                resultConditionSet |= SOCKET_WRITABLE;
            if (FD_ISSET(sock, &exceptionSet)
                    && FD_ISSET(sock, &fExceptionSet)/*sanity check*/)
                resultConditionSet |= SOCKET_EXCEPTION;
            if ((resultConditionSet & handler->conditionSet)
                    != 0 && handler->handlerProc != NULL) {
                fLastHandledSocketNum = sock;
                // Note: we set "fLastHandledSocketNum" before calling the handler,
                // in case the handler calls "doEventLoop()" reentrantly.
                (*handler->handlerProc)(handler->clientData, resultConditionSet);
                break;
            }
        }

        //如果寻找完了依然没有执行任何handle,则从头再找。
        if (handler == NULL && fLastHandledSocketNum >= 0) {
            // We didn't call a handler, but we didn't get to check all of them,
            // so try again from the beginning:
            iter.reset();
            while ((handler = iter.next()) != NULL) {
                int sock = handler->socketNum; // alias
                int resultConditionSet = 0;
                if (FD_ISSET(sock, &readSet)&& FD_ISSET(sock, &fReadSet)/*sanity check*/)
                    resultConditionSet |= SOCKET_READABLE;
                if (FD_ISSET(sock, &writeSet)&& FD_ISSET(sock, &fWriteSet)/*sanity check*/)
                    resultConditionSet |= SOCKET_WRITABLE;
                if (FD_ISSET(sock, &exceptionSet)    && FD_ISSET(sock, &fExceptionSet)/*sanity check*/)
                    resultConditionSet |= SOCKET_EXCEPTION;
                if ((resultConditionSet & handler->conditionSet)
                        != 0 && handler->handlerProc != NULL) {
                    fLastHandledSocketNum = sock;
                    // Note: we set "fLastHandledSocketNum" before calling the handler,
                    // in case the handler calls "doEventLoop()" reentrantly.
                    (*handler->handlerProc)(handler->clientData, resultConditionSet);
                    break;
                }
            }

            //依然没有找到可执行的handler。
            if (handler == NULL)
                fLastHandledSocketNum = -1; //because we didn't call a handler
        }

        //响应事件
        // Also handle any newly-triggered event
        // (Note that we do this *after* calling a socket handler,
        // in case the triggered event handler modifies The set of readable sockets.)
        if (fTriggersAwaitingHandling != 0) {
            if (fTriggersAwaitingHandling == fLastUsedTriggerMask) {
                // Common-case optimization for a single event trigger:
                fTriggersAwaitingHandling = 0;
                if (fTriggeredEventHandlers[fLastUsedTriggerNum] != NULL) {
                    //执行一个事件处理函数
                    (*fTriggeredEventHandlers[fLastUsedTriggerNum])(fTriggeredEventClientDatas[fLastUsedTriggerNum]);
                }
            } else {
                // Look for an event trigger that needs handling
                // (making sure that we make forward progress through all possible triggers):
                unsigned i = fLastUsedTriggerNum;
                EventTriggerId mask = fLastUsedTriggerMask;

                do {
                    i = (i + 1) % MAX_NUM_EVENT_TRIGGERS;
                    mask >>= 1;
                    if (mask == 0)
                        mask = 0x80000000;

                    if ((fTriggersAwaitingHandling & mask) != 0) {
                        //执行一个事件响应
                        fTriggersAwaitingHandling &= ~mask;
                        if (fTriggeredEventHandlers[i] != NULL) {
                            (*fTriggeredEventHandlers[i])(fTriggeredEventClientDatas[i]);
                        }

                        fLastUsedTriggerMask = mask;
                        fLastUsedTriggerNum = i;
                        break;
                    }
                } while (i != fLastUsedTriggerNum);
            }
        }

        //执行一个最迫切的延迟任务。
        // Also handle any delayed event that may have come due.
        fDelayQueue.handleAlarm();
    }

转载

live555学习笔记3-消息循环

posted @ 2020-08-31 11:37  cyssmile  阅读(640)  评论(0编辑  收藏  举报