Esempio n. 1
0
//--------------------------------------------------------------------------------------------------
le_result_t le_event_ServiceLoop
(
    void
)
{
    event_PerThreadRec_t* perThreadRecPtr = thread_GetEventRecPtr();
    int epollFd = CONTAINER_OF(perThreadRecPtr,
                               event_LinuxPerThreadRec_t,
                               portablePerThreadRec)->epollFd;
    struct epoll_event epollEventList[MAX_EPOLL_EVENTS];

    LE_DEBUG("perThreadRecPtr->liveEventCount is" "%" PRIu64, perThreadRecPtr->liveEventCount);

    // If there are still live events remaining in the queue, process a single event, then return
    if (perThreadRecPtr->liveEventCount > 0)
    {
        perThreadRecPtr->liveEventCount--;

        // This function assumes the mutex is NOT locked.
        event_ProcessOneEventReport(perThreadRecPtr);

        return LE_OK;
    }

    int result;

    do
    {
        // If no events on the queue, try to refill the event queue.
        // Ask epoll what, if anything, has happened on any of the file descriptors that we are
        // monitoring using our epoll fd.  (NOTE: This is non-blocking.)
        result = epoll_wait(epollFd, epollEventList, NUM_ARRAY_MEMBERS(epollEventList), 0);

        if ((result < 0) && (EINTR == errno))
        {
            // If epoll was interrupted,
            // Check if someone has cancelled the thread and terminate the thread now, if so.
            pthread_testcancel();
        }
    }
    while ((result < 0) && (EINTR == errno));

    // If something happened on one or more of the monitored file descriptors,
    if (result > 0)
    {
        int i;

        // Check if someone has cancelled the thread and terminate the thread now, if so.
        pthread_testcancel();

        // For each fd event reported by epoll_wait(), if it is any file descriptor other
        // than the eventfd (which is used to indicate that there is something on the
        // Event Queue), queue an Event Report to the Event Queue for that fd.
        for (i = 0; i < result; i++)
        {
            // Get the pointer that we registered with epoll_ctl(2) along with this fd.
            // The value of this pointer will either be NULL or a Safe Reference for an
            // FD Monitor object.  If it is NULL, then the Event Queue's eventfd is the
            // fd that experienced the event, which we will deal with later in this function.
            void* safeRef = epollEventList[i].data.ptr;

            if (safeRef != NULL)
            {
                fdMon_Report(safeRef, EPollToPoll(epollEventList[i].events));
            }
        }
    }
    // Otherwise, check if an epoll_wait() reported an error.
    // Interruptions are tested above, so this is always a fatal error.
    else if (result < 0)
    {
        LE_FATAL("epoll_wait() failed.  errno = %d.", errno);
    }
    // Otherwise, if epoll_wait() returned zero, then either this function was called without
    // waiting for the eventfd to be readable, or the eventfd was readable momentarily, but
    // something changed between the time the application code detected the readable condition
    // and now that made the eventfd not readable anymore.
    else
    {
        LE_DEBUG("epoll_wait() returned zero.");

        return LE_WOULD_BLOCK;
    }

    // Read the eventfd to reset it to zero so epoll stops telling us about it until more
    // are added.
    perThreadRecPtr->liveEventCount = fa_event_WaitForEvent(perThreadRecPtr);

    LE_DEBUG("perThreadRecPtr->liveEventCount is" "%" PRIu64, perThreadRecPtr->liveEventCount);

    // If events were read, process the top event
    if (perThreadRecPtr->liveEventCount > 0)
    {
        perThreadRecPtr->liveEventCount--;
        event_ProcessOneEventReport(perThreadRecPtr);

        return LE_OK;
    }
    else
    {
        return LE_WOULD_BLOCK;
    }
}
Esempio n. 2
0
//--------------------------------------------------------------------------------------------------
static void DispatchToHandler
(
    void* param1Ptr,    ///< FD Monitor safe reference.
    void* param2Ptr     ///< epoll() event flags.
)
//--------------------------------------------------------------------------------------------------
{
    uint32_t epollEventFlags = (uint32_t)(size_t)param2Ptr;

    LOCK

    // Get a pointer to the FD Monitor object for this fd.
    FdMonitor_t* fdMonitorPtr = le_ref_Lookup(FdMonitorRefMap, param1Ptr);

    UNLOCK

    // If the FD Monitor object has been deleted, we can just ignore this.
    if (fdMonitorPtr == NULL)
    {
        TRACE("Discarding events for non-existent FD Monitor %p.", param1Ptr);
        return;
    }

    // Sanity check: The FD monitor must belong to the current thread.
    LE_ASSERT(thread_GetEventRecPtr() == fdMonitorPtr->threadRecPtr);

    // Mask out any events that have been disabled since epoll_wait() reported these events to us.
    epollEventFlags &= (fdMonitorPtr->epollEvents | EPOLLERR | EPOLLHUP | EPOLLRDHUP);

    // If there's nothing left to report to the handler, don't call it.
    if (epollEventFlags == 0)
    {
        // Note: if the fd is always ready to read or write (is not supported by epoll()), then
        //       we will only end up in here if both POLLIN and POLLOUT are disabled, in which case
        //       returning now will prevent re-queuing of DispatchToHandler(), which is what we
        //       want.  When either POLLIN or POLLOUT are re-enabled, le_fdMonitor_Enable() will
        //       call fdMon_Report() to get things going again.
        return;
    }

    // Translate the epoll() events into poll() events.
    short pollEvents = EPollToPoll(epollEventFlags);

    if (IS_TRACE_ENABLED())
    {
        char eventsTextBuff[128];

        TRACE("Calling event handler for FD Monitor %s (fd %d, events %s).",
              fdMonitorPtr->name,
              fdMonitorPtr->fd,
              GetPollEventsText(eventsTextBuff, sizeof(eventsTextBuff), pollEvents));
    }

    // Increment the reference count on the Monitor object in case the handler deletes it.
    le_mem_AddRef(fdMonitorPtr);

    // Store a pointer to the FD Monitor as thread-specific data so le_fdMonitor_GetMonitor()
    // and le_fdMonitor_GetContextPtr() can find it.
    LE_ASSERT(pthread_setspecific(FDMonitorPtrKey, fdMonitorPtr) == 0);

    // Set the thread's event loop Context Pointer.
    event_SetCurrentContextPtr(fdMonitorPtr->contextPtr);

    // Call the handler function.
    fdMonitorPtr->handlerFunc(fdMonitorPtr->fd, pollEvents);

    // Clear the thread-specific pointer to the FD Monitor.
    LE_ASSERT(pthread_setspecific(FDMonitorPtrKey, NULL) == 0);

    // If this fd is always ready (is not supported by epoll) and either POLLIN or POLLOUT
    // are enabled, then queue up another dispatcher for this FD Monitor.
    // If neither are enabled, then le_fdMonitor_Enable() will queue the dispatcher
    // when one of them is re-enabled.
    if ((fdMonitorPtr->isAlwaysReady) && (fdMonitorPtr->epollEvents & (EPOLLIN | EPOLLOUT)))
    {
        fdMon_Report(fdMonitorPtr->safeRef, fdMonitorPtr->epollEvents & (EPOLLIN | EPOLLOUT));
    }

    // Release our reference.  We don't need the Monitor object anymore.
    le_mem_Release(fdMonitorPtr);
}
Esempio n. 3
0
//--------------------------------------------------------------------------------------------------
void fa_event_RunLoop
(
    void
)
{
    event_PerThreadRec_t* perThreadRecPtr = thread_GetEventRecPtr();

    int epollFd = CONTAINER_OF(perThreadRecPtr,
                               event_LinuxPerThreadRec_t,
                               portablePerThreadRec)->epollFd;
    struct epoll_event epollEventList[MAX_EPOLL_EVENTS];

    // Make sure nobody calls this function more than once in the same thread.
    LE_ASSERT(perThreadRecPtr->state == LE_EVENT_LOOP_INITIALIZED);

    // Update the state of the Event Loop.
    perThreadRecPtr->state = LE_EVENT_LOOP_RUNNING;

    // Enter the infinite loop itself.
    for (;;)
    {
        // Wait for something to happen on one of the file descriptors that we are monitoring
        // using our epoll fd.
        int result = epoll_wait(epollFd, epollEventList, NUM_ARRAY_MEMBERS(epollEventList), -1);

        // If something happened on one or more of the monitored file descriptors,
        if (result > 0)
        {
            int i;

            // Check if someone has cancelled the thread and terminate the thread now, if so.
            pthread_testcancel();

            // For each fd event reported by epoll_wait(), if it is any file descriptor other
            // than the eventfd (which is used to indicate that there is something on the
            // Event Queue), queue an Event Report to the Event Queue for that fd.
            for (i = 0; i < result; i++)
            {
                // Get the pointer that we registered with epoll_ctl(2) along with this fd.
                // The value of this pointer will either be NULL or a Safe Reference for an
                // FD Monitor object.  If it is NULL, then the Event Queue's eventfd is the
                // fd that experienced the event.
                void* safeRef = epollEventList[i].data.ptr;

                if (safeRef != NULL)
                {
                    fdMon_Report(safeRef, EPollToPoll(epollEventList[i].events));
                }
            }

            // Process all the Event Reports on the Event Queue.
            event_ProcessEventReports(perThreadRecPtr);
        }
        // Otherwise, if an epoll_wait() reported an error, hopefully it's just an interruption
        // by a signal (EINTR).  Anything else is a fatal error.
        else if (result < 0)
        {
            if (errno != EINTR)
            {
                LE_FATAL("epoll_wait() failed.  errno = %d.", errno);
            }

            // It was just EINTR, so we are okay to go back to sleep.  But first,
            // check if someone has cancelled the thread and terminate the thread now, if so.
            pthread_testcancel();
        }
        // Otherwise, if epoll_wait() returned zero, something has gone horribly wrong, because
        // it should never return zero.
        else
        {
            LE_FATAL("epoll_wait() returned zero!");
        }
    }
}