예제 #1
0
bool BProcess::InsertHandler(BHandler **handlerP, BHandler *handler)
{
    BHandler *p = *handlerP;

    if (!p) {
        *handlerP = handler;
        handler->m_next = handler->m_prev = NULL;
        return true;
    }

    const nsecs_t msgTime = handler->NextMessageTime(NULL);
    if (p->NextMessageTime(NULL) > msgTime) {
        (*handlerP)->m_prev = handler;
        *handlerP = handler;
        handler->m_next = p;
        handler->m_prev = NULL;
    } else {
        while (p->m_next && (p->m_next->NextMessageTime(NULL) < msgTime)) p = p->m_next;
        handler->m_next = p->m_next;
        handler->m_prev = p;
        if (p->m_next) p->m_next->m_prev = handler;
        p->m_next = handler;
    }
    return false;
}
예제 #2
0
void BProcess::DispatchMessage(SLooper* looper)
{
    //bout << "BProcess::DispatchMessage: (" << SysCurrentThread() << ")@" << SysGetRunTime() << endl;
    BHandler* handler = NULL;
    int32_t priority = B_NORMAL_PRIORITY;
    bool firstTime = true;

    m_lock.LockQuick();
    //DbgOnlyFatalErrorIf(m_currentEventConcurrency >= m_maxEventConcurrency, "We have gone past the limit on concurrent handlers!");
    if (m_currentEventConcurrency >= m_maxEventConcurrency) {
        m_lock.Unlock();
        return;
    }
    m_currentEventConcurrency++;

    // The binder driver clears its event time when processing an event,
    // so we always must inform it if there is another one to schedule.
    m_nextEventTime = B_INFINITE_TIMEOUT;

    nsecs_t curTime = exact_SysGetRunTime();

    while (1) {
        if ((handler = m_pendingHandlers) != NULL
                && handler->NextMessageTime(&priority) <= curTime) {
            m_pendingHandlers = handler->m_next;
            handler->m_next = handler->m_prev = NULL;
            if (m_pendingHandlers) m_pendingHandlers->m_prev = NULL;
            handler->defer_scheduling();
        } else {
            // Nothing to do right now, time to leave.
            break;
        }

        // If this is the first time through the loop, we need to schedule
        // the next pending handler so that another SLooper thread can be
        // activated to execute it.
        if (firstTime) {
            ScheduleNextEvent();
            firstTime = false;
        }

        // We are now going to enter user code, don't hold the lock.
        m_lock.Unlock();

        if (handler->AttemptAcquire(this)) {
shortcutDispatch:
            // bout << "BProcess: Thread " << SysCurrentThread() << " dispatch to " << handler << " at pri " << priority << endl;
            looper->_SetThreadPriority(priority);
            handler->dispatch_message();
            // bout << "BProcess: Thread " << SysCurrentThread() << " returned from dispatch!" << endl;

            // Update our concept of the time.
            curTime = approx_SysGetRunTime();

            // Big shortcut (one could even call this an optimization
            // for a particular performance test).  If this handler
            // has the next message that will be processed, just do
            // it right now.
            m_lock.LockQuick();
            // We can do this if...  there is a pending message and it is next...
            const nsecs_t when = handler->NextMessageTime(&priority);
            if (m_pendingHandlers == NULL || when <= m_pendingHandlers->NextMessageTime(NULL)) {
                // And ResumeScheduling() wasn't called while processing the message...
                if (ResumingScheduling()) {
                    // The above flagged that this thread called ResumeScheduling(), but it
                    // really hasn't.  Psych!!
                    ClearSchedulingResumed();
                    // And it is time for the message.
                    if (when <= curTime) {
                        m_lock.Unlock();
                        // Whoosh!
                        // bout << "BProcess: Thread " << SysCurrentThread() << " redispatch to same handler!" << endl;
                        goto shortcutDispatch;
                    }
                }
            }
            m_lock.Unlock();

            handler->ResumeScheduling();
            ClearSchedulingResumed();
            handler->Release(this);
        }
        handler->DecRefs(this);

        m_lock.LockQuick();
    }

    // We have handled all available messages.  While still holding the
    // lock, reduce concurrency and schedule the next event to make sure
    // the binder is up-to-date about when it is to occur.
    m_currentEventConcurrency--;
    ScheduleNextEvent();

    m_lock.Unlock();

    // bout << "BProcess::DispatchMessage Exit: (" << SysCurrentThread() << ")@" << SysGetRunTime() << endl;

#if TARGET_HOST == TARGET_HOST_WIN32
    // Handler thread pool is implemented entirely in user space on Windows.
    looper->_SetThreadPriority(B_REAL_TIME_PRIORITY);
#endif
}