Example #1
0
//--------------------------------------------------------------------------------------------------
static void DeleteFdMonitor
(
    FdMonitor_t*            fdMonitorPtr        ///< [in] Pointer to the FD Monitor to be deleted.
)
//--------------------------------------------------------------------------------------------------
{
    event_PerThreadRec_t*   perThreadRecPtr = thread_GetEventRecPtr();

    LE_ASSERT(perThreadRecPtr == fdMonitorPtr->threadRecPtr);

    // Remove the FD Monitor from the thread's FD Monitor List.
    le_dls_Remove(&perThreadRecPtr->fdMonitorList, &fdMonitorPtr->link);

    LOCK

    // Delete the Safe References used for the FD Monitor and any of its Handler objects.
    le_ref_DeleteRef(FdMonitorRefMap, fdMonitorPtr->safeRef);

    UNLOCK

    // Tell epoll(7) to stop monitoring this fd.
    StopMonitoringFd(fdMonitorPtr);

    // Release the object back to it's pool.
    le_mem_Release(fdMonitorPtr);
}
Example #2
0
//--------------------------------------------------------------------------------------------------
void le_fdMonitor_Enable
(
    le_fdMonitor_Ref_t  monitorRef, ///< [in] Reference to the File Descriptor Monitor object.
    short               events      ///< [in] Bit map of events.
)
//--------------------------------------------------------------------------------------------------
{
    // Look up the File Descriptor Monitor object using the safe reference provided.
    // Note that the safe reference map is shared by all threads in the process, so it
    // must be protected using the mutex.  The File Descriptor Monitor objects, on the other
    // hand, are only allowed to be accessed by the one thread that created them, so it is
    // safe to unlock the mutex after doing the safe reference lookup.
    LOCK
    FdMonitor_t* monitorPtr = le_ref_Lookup(FdMonitorRefMap, monitorRef);
    UNLOCK

    LE_FATAL_IF(monitorPtr == NULL, "File Descriptor Monitor %p doesn't exist!", monitorRef);
    LE_FATAL_IF(thread_GetEventRecPtr() != monitorPtr->threadRecPtr,
                "FD Monitor '%s' (fd %d) is owned by another thread.",
                monitorPtr->name,
                monitorPtr->fd);

    short filteredEvents = events & (POLLIN | POLLOUT | POLLPRI);

    if (filteredEvents != events)
    {
        char textBuff[64];

        LE_WARN("Attempt to enable events that can't be disabled (%s).",
                GetPollEventsText(textBuff, sizeof(textBuff), events & ~filteredEvents));
    }

    uint32_t epollEvents = PollToEPoll(filteredEvents);

    // If the fd doesn't support epoll, we assume it is always ready for read and write.
    // As long as EPOLLIN or EPOLLOUT (or both) is enabled for one of these fds, DispatchToHandler()
    // keeps re-queueing itself to the thread's event queue.  But it will stop doing that if
    // EPOLLIN and EPOLLOUT are both disabled.  So, here is where we get things going again when
    // EPOLLIN or EPOLLOUT is enabled outside DispatchToHandler() for that fd.
    if ( (monitorPtr->isAlwaysReady)
        && (epollEvents & (EPOLLIN | EPOLLOUT))
        && ((monitorPtr->epollEvents & (EPOLLIN | EPOLLOUT)) == 0) )
    {
        // Fetch the pointer to the FD Monitor from thread-specific data.
        // This will be NULL if we are not inside an FD Monitor handler.
        FdMonitor_t* handlerMonitorPtr = pthread_getspecific(FDMonitorPtrKey);

        // If no handler is running or some other fd's handler is running,
        if ((handlerMonitorPtr == NULL) || (handlerMonitorPtr->safeRef == monitorRef))
        {
            // Queue up DispatchToHandler() for this fd.
            fdMon_Report(monitorRef, epollEvents & (EPOLLIN | EPOLLOUT));
        }
    }

    // Bit-wise OR the newly enabled event flags into the FD Monitor's epoll(7) flags set.
    monitorPtr->epollEvents |= epollEvents;

    UpdateEpollFd(monitorPtr);
}
Example #3
0
//--------------------------------------------------------------------------------------------------
void le_fdMonitor_SetDeferrable
(
    le_fdMonitor_Ref_t monitorRef,  ///< [in] Reference to the File Descriptor Monitor object.
    bool               isDeferrable ///< [in] true (deferrable) or false (urgent).
)
//--------------------------------------------------------------------------------------------------
{
    // Look up the File Descriptor Monitor object using the safe reference provided.
    // Note that the safe reference map is shared by all threads in the process, so it
    // must be protected using the mutex.  The File Descriptor Monitor objects, on the other
    // hand, are only allowed to be accessed by the one thread that created them, so it is
    // safe to unlock the mutex after doing the safe reference lookup.
    LOCK
    FdMonitor_t* monitorPtr = le_ref_Lookup(FdMonitorRefMap, monitorRef);
    UNLOCK

    LE_FATAL_IF(monitorPtr == NULL, "File Descriptor Monitor %p doesn't exist!", monitorRef);
    LE_FATAL_IF(thread_GetEventRecPtr() != monitorPtr->threadRecPtr,
                "FD Monitor '%s' (fd %d) is owned by another thread.",
                monitorPtr->name,
                monitorPtr->fd);

    // Set/clear the EPOLLWAKEUP flag in the FD Monitor's epoll(7) flags set.
    if (isDeferrable)
    {
        monitorPtr->epollEvents &= ~EPOLLWAKEUP;
    }
    else
    {
        monitorPtr->epollEvents |= EPOLLWAKEUP;
    }

    UpdateEpollFd(monitorPtr);
}
Example #4
0
//--------------------------------------------------------------------------------------------------
static void DeleteFdMonitor
(
    FdMonitor_t*            fdMonitorPtr        ///< [in] Pointer to the FD Monitor to be deleted.
)
//--------------------------------------------------------------------------------------------------
{
    int i;
    event_PerThreadRec_t*   perThreadRecPtr = thread_GetEventRecPtr();

    LE_ASSERT(perThreadRecPtr == fdMonitorPtr->threadRecPtr);

    // Remove the FD Monitor from the thread's FD Monitor List.
    le_dls_Remove(&perThreadRecPtr->fdMonitorList, &fdMonitorPtr->link);

    LOCK

    // Delete the Safe References used for the FD Monitor and any of its Handler objects.
    le_ref_DeleteRef(FdMonitorRefMap, fdMonitorPtr->safeRef);
    for (i = 0; i < LE_EVENT_NUM_FD_EVENT_TYPES; i++)
    {
        void* safeRef = fdMonitorPtr->handlerArray[i].safeRef;
        if (safeRef != NULL)
        {
            le_ref_DeleteRef(HandlerRefMap, safeRef);
        }
    }

    UNLOCK

    // Tell epoll(7) to stop monitoring this fd.
    StopMonitoringFd(fdMonitorPtr);

    // Release the object back to it's pool.
    le_mem_Release(fdMonitorPtr);
}
Example #5
0
//--------------------------------------------------------------------------------------------------
int le_event_GetFd
(
    void
)
{
    return CONTAINER_OF(thread_GetEventRecPtr(),
                        event_LinuxPerThreadRec_t,
                        portablePerThreadRec)->epollFd;
}
Example #6
0
//--------------------------------------------------------------------------------------------------
le_event_FdMonitorRef_t le_event_CreateFdMonitor
(
    const char*     name,       ///< [in] Name of the object (for diagnostics).
    int             fd          ///< [in] File descriptor to be monitored for events.
)
//--------------------------------------------------------------------------------------------------
{
    // Get a pointer to the thread-specific event loop data record.
    event_PerThreadRec_t* perThreadRecPtr = thread_GetEventRecPtr();

    // Allocate the object.
    FdMonitor_t* fdMonitorPtr = le_mem_ForceAlloc(FdMonitorPool);

    // Initialize the object.
    fdMonitorPtr->link = LE_DLS_LINK_INIT;
    fdMonitorPtr->fd = fd;
    fdMonitorPtr->threadRecPtr = perThreadRecPtr;
    memset(fdMonitorPtr->handlerArray, 0, sizeof(fdMonitorPtr->handlerArray));

    // To start with, no events are in the set to be monitored.  They will be added as handlers
    // are registered for them. (Although, EPOLLHUP and EPOLLERR will always be monitored
    // regardless of what flags we specify).  We use epoll in "level-triggered mode".
    fdMonitorPtr->epollEvents = 0;

    // Assume that the event should wake up the system; can be changed later.
    fdMonitorPtr->wakeUp = true;

    // Copy the name into it.
    if (le_utf8_Copy(fdMonitorPtr->name, name, sizeof(fdMonitorPtr->name), NULL) == LE_OVERFLOW)
    {
        LE_WARN("FD Monitor object name '%s' truncated to '%s'.", name, fdMonitorPtr->name);
    }

    LOCK

    // Create a safe reference for the object.
    fdMonitorPtr->safeRef = le_ref_CreateRef(FdMonitorRefMap, fdMonitorPtr);

    // Add it to the thread's FD Monitor list.
    le_dls_Queue(&perThreadRecPtr->fdMonitorList, &fdMonitorPtr->link);

    // Tell epoll(7) to start monitoring this fd.
    struct epoll_event ev;
    ev.events = fdMonitorPtr->epollEvents;
    ev.data.ptr = fdMonitorPtr->safeRef;
    if (epoll_ctl(perThreadRecPtr->epollFd, EPOLL_CTL_ADD, fd, &ev) == -1)
    {
        LE_FATAL("epoll_ctl(ADD) failed for fd %d. errno = %d (%m)", fd, errno);
    }

    UNLOCK

    return fdMonitorPtr->safeRef;
}
Example #7
0
//--------------------------------------------------------------------------------------------------
static void DispatchToHandler
(
    void* param1Ptr,    ///< FD Monitor safe reference.
    void* param2Ptr     ///< FD event type.
)
//--------------------------------------------------------------------------------------------------
{
    le_event_FdEventType_t eventType = (le_event_FdEventType_t)param2Ptr;
    event_PerThreadRec_t* perThreadRecPtr = thread_GetEventRecPtr();

    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)
    {
        LE_ASSERT(perThreadRecPtr == fdMonitorPtr->threadRecPtr);

        Handler_t* handlerPtr = &(fdMonitorPtr->handlerArray[eventType]);

        if (handlerPtr->handlerFunc != NULL)
        {
            // Set the thread's Context Pointer.
            event_SetCurrentContextPtr(handlerPtr->contextPtr);

            // Call the handler function.
            handlerPtr->handlerFunc(fdMonitorPtr->fd);
        }
        else
        {
            TRACE("Discarding event %s for FD Monitor %s (fd %d).",
                  GetFdEventTypeName(eventType),
                  fdMonitorPtr->name,
                  fdMonitorPtr->fd);

            // If this is a write hang-up, then we need to tell epoll to stop monitoring
            // this fd, because otherwise we could end up wasting power and spamming the
            // log with debug messages while we detect and discard this event over and over.
            if (eventType == LE_EVENT_FD_WRITE_HANG_UP)
            {
                StopMonitoringFd(fdMonitorPtr);
            }
        }
    }
    else
    {
        TRACE("Discarding event %s for non-existent FD Monitor.", GetFdEventTypeName(eventType));
    }
}
Example #8
0
//--------------------------------------------------------------------------------------------------
le_event_FdHandlerRef_t le_event_SetFdHandler
(
    le_event_FdMonitorRef_t  monitorRef, ///< [in] Reference to the File Descriptor Monitor object.
    le_event_FdEventType_t   eventType,  ///< [in] The type of event to be reported to this handler.
    le_event_FdHandlerFunc_t handlerFunc ///< [in] The handler function.
)
//--------------------------------------------------------------------------------------------------
{
    LE_ASSERT(handlerFunc != NULL);

    // Look up the File Descriptor Monitor object using the safe reference provided.
    // Note that the safe reference map is shared by all threads in the process, so it
    // must be protected using the mutex.  The File Descriptor Monitor objects, on the other
    // hand, are only allowed to be accessed by the one thread that created them, so it is
    // safe to unlock the mutex after doing the safe reference lookup.
    LOCK
    FdMonitor_t* monitorPtr = le_ref_Lookup(FdMonitorRefMap, monitorRef);
    UNLOCK

    LE_FATAL_IF(monitorPtr == NULL, "File Descriptor Monitor %p doesn't exist!", monitorRef);
    LE_FATAL_IF(thread_GetEventRecPtr() != monitorPtr->threadRecPtr,
                "FD Monitor '%s' (fd %d) is owned by another thread.",
                monitorPtr->name,
                monitorPtr->fd);

    // Get a pointer to the Handler object in the appropriate spot for this type of event in the
    // FD Monitor's array of handlers.
    Handler_t* handlerPtr = &(monitorPtr->handlerArray[eventType]);

    // Double check that no one has tried setting this handler yet.
    LE_FATAL_IF(handlerPtr->handlerFunc != NULL,
                "FD handler already set for event '%s' on FD Monitor '%s' (fd %d).",
                GetFdEventTypeName(eventType),
                monitorPtr->name,
                monitorPtr->fd);

    // Initialize the Handler object.
    handlerPtr->handlerFunc = handlerFunc;
    handlerPtr->contextPtr = NULL;
    handlerPtr->monitorPtr = monitorPtr;
    LOCK
    handlerPtr->safeRef = le_ref_CreateRef(HandlerRefMap, handlerPtr);
    UNLOCK

    // Enable the monitoring of this event.
    EnableFdMonitoring(monitorPtr, eventType);

    return handlerPtr->safeRef;
}
Example #9
0
//--------------------------------------------------------------------------------------------------
void le_event_ClearFdHandlerByEventType
(
    le_event_FdMonitorRef_t  monitorRef, ///< [in] Reference to the File Descriptor Monitor object.
    le_event_FdEventType_t   eventType   ///< [in] The type of event to clear the handler for.
)
//--------------------------------------------------------------------------------------------------
{
    LE_ASSERT(eventType < LE_EVENT_NUM_FD_EVENT_TYPES);

    // Look up the File Descriptor Monitor object using the safe reference provided.
    // Note that the safe reference map is shared by all threads in the process, so it
    // must be protected using the mutex.  The File Descriptor Monitor objects, on the other
    // hand, are only allowed to be accessed by the one thread that created them, so it is
    // safe to unlock the mutex after doing the safe reference lookup.
    LOCK
    FdMonitor_t* monitorPtr = le_ref_Lookup(FdMonitorRefMap, monitorRef);
    UNLOCK

    LE_FATAL_IF(monitorPtr == NULL, "File Descriptor Monitor %p doesn't exist!", monitorRef);
    LE_FATAL_IF(thread_GetEventRecPtr() != monitorPtr->threadRecPtr,
                "FD Monitor '%s' (fd %d) is owned by another thread.",
                monitorPtr->name,
                monitorPtr->fd);

    // Get a pointer to the Handler object in the appropriate spot for this type of event in the
    // FD Monitor's array of handlers.
    Handler_t* handlerPtr = &(monitorPtr->handlerArray[eventType]);

    LE_CRIT_IF(handlerPtr->handlerFunc == NULL,
               "Handler cleared when not set for FD Monitor '%s' (fd %d), event type %d.",
               monitorPtr->name,
               monitorPtr->fd,
               eventType);

    // Clear the Handler object.
    handlerPtr->handlerFunc = NULL;
    handlerPtr->contextPtr = NULL;
    LOCK
    le_ref_DeleteRef(HandlerRefMap, handlerPtr->safeRef);
    UNLOCK
    handlerPtr->safeRef = NULL;

    // Disable the monitoring of this event.
    DisableFdMonitoring(monitorPtr, eventType);
}
Example #10
0
//--------------------------------------------------------------------------------------------------
void le_fdMonitor_Delete
(
    le_fdMonitor_Ref_t monitorRef  ///< [in] Reference to the File Descriptor Monitor object.
)
//--------------------------------------------------------------------------------------------------
{
    LOCK
    FdMonitor_t* monitorPtr = le_ref_Lookup(FdMonitorRefMap, monitorRef);
    UNLOCK

    LE_FATAL_IF(monitorPtr == NULL, "FD Monitor object %p does not exist!", monitorRef);

    LE_FATAL_IF(monitorPtr->threadRecPtr != thread_GetEventRecPtr(),
                "FD Monitor '%s' (%d) is owned by another thread.",
                monitorPtr->name,
                monitorPtr->fd);

    DeleteFdMonitor(monitorPtr);
}
Example #11
0
//--------------------------------------------------------------------------------------------------
void le_event_ClearFdHandler
(
    le_event_FdHandlerRef_t  handlerRef  ///< [in] Reference to the handler.
)
//--------------------------------------------------------------------------------------------------
{
    // Look up the Handler object using the safe reference provided.
    // Note that the safe reference map is shared by all threads in the process, so it
    // must be protected using the mutex.  The Handler objects, on the other
    // hand, are only allowed to be accessed by the one thread that created them, so it is
    // safe to unlock the mutex after doing the safe reference lookup.
    LOCK
    Handler_t* handlerPtr = le_ref_Lookup(HandlerRefMap, handlerRef);
    UNLOCK

    LE_FATAL_IF(handlerPtr == NULL, "FD event handler %p doesn't exist!", handlerRef);

    FdMonitor_t* monitorPtr = handlerPtr->monitorPtr;

    LE_FATAL_IF(thread_GetEventRecPtr() != monitorPtr->threadRecPtr,
                "FD Monitor '%s' (fd %d) is owned by another thread.",
                monitorPtr->name,
                monitorPtr->fd);

    LE_ASSERT(handlerPtr->handlerFunc != NULL);

    le_event_FdEventType_t eventType = INDEX_OF_ARRAY_MEMBER(monitorPtr->handlerArray, handlerPtr);
    LE_ASSERT(eventType < LE_EVENT_NUM_FD_EVENT_TYPES);

    // Clear the Handler object.
    handlerPtr->handlerFunc = NULL;
    handlerPtr->contextPtr = NULL;
    LOCK
    le_ref_DeleteRef(HandlerRefMap, handlerPtr->safeRef);
    UNLOCK
    handlerPtr->safeRef = NULL;

    // Disable the monitoring of this event.
    DisableFdMonitoring(monitorPtr, eventType);
}
Example #12
0
//--------------------------------------------------------------------------------------------------
void le_fdMonitor_SetContextPtr
(
    le_fdMonitor_Ref_t  monitorRef, ///< [in] Reference to the File Descriptor Monitor.
    void*               contextPtr  ///< [in] Opaque context pointer value.
)
//--------------------------------------------------------------------------------------------------
{
    // Look up the File Descriptor Monitor object using the safe reference provided.
    // Note that the safe reference map is shared by all threads in the process, so it
    // must be protected using the mutex.  The File Descriptor Monitor objects, on the other
    // hand, are only allowed to be accessed by the one thread that created them, so it is
    // safe to unlock the mutex after doing the safe reference lookup.
    LOCK
    FdMonitor_t* monitorPtr = le_ref_Lookup(FdMonitorRefMap, monitorRef);
    UNLOCK

    LE_FATAL_IF(monitorPtr == NULL, "File Descriptor Monitor %p doesn't exist!", monitorRef);
    LE_FATAL_IF(thread_GetEventRecPtr() != monitorPtr->threadRecPtr,
                "FD Monitor '%s' (fd %d) is owned by another thread.",
                monitorPtr->name,
                monitorPtr->fd);

    monitorPtr->contextPtr = contextPtr;
}
Example #13
0
//--------------------------------------------------------------------------------------------------
void le_event_WakeUp
(
    le_event_FdMonitorRef_t  monitorRef, ///< [in] Reference to the File Descriptor Monitor object.
    bool                     wakeUp      ///< [in] Optional EPOLLWAKEUP flag for epoll_wait().
)
//--------------------------------------------------------------------------------------------------
{
    // Look up the File Descriptor Monitor object using the safe reference provided.
    // Note that the safe reference map is shared by all threads in the process, so it
    // must be protected using the mutex.  The File Descriptor Monitor objects, on the other
    // hand, are only allowed to be accessed by the one thread that created them, so it is
    // safe to unlock the mutex after doing the safe reference lookup.
    LOCK
    FdMonitor_t* monitorPtr = le_ref_Lookup(FdMonitorRefMap, monitorRef);
    UNLOCK

    LE_FATAL_IF(monitorPtr == NULL, "File Descriptor Monitor %p doesn't exist!", monitorRef);
    LE_FATAL_IF(thread_GetEventRecPtr() != monitorPtr->threadRecPtr,
                "FD Monitor '%s' (fd %d) is owned by another thread.",
                monitorPtr->name,
                monitorPtr->fd);

    monitorPtr->wakeUp = wakeUp;
}
Example #14
0
//--------------------------------------------------------------------------------------------------
void le_fdMonitor_Disable
(
    le_fdMonitor_Ref_t  monitorRef, ///< [in] Reference to the File Descriptor Monitor object.
    short               events      ///< [in] Bit map of events.
)
//--------------------------------------------------------------------------------------------------
{
    // Look up the File Descriptor Monitor object using the safe reference provided.
    // Note that the safe reference map is shared by all threads in the process, so it
    // must be protected using the mutex.  The File Descriptor Monitor objects, on the other
    // hand, are only allowed to be accessed by the one thread that created them, so it is
    // safe to unlock the mutex after doing the safe reference lookup.
    LOCK
    FdMonitor_t* monitorPtr = le_ref_Lookup(FdMonitorRefMap, monitorRef);
    UNLOCK

    LE_FATAL_IF(monitorPtr == NULL, "File Descriptor Monitor %p doesn't exist!", monitorRef);
    LE_FATAL_IF(thread_GetEventRecPtr() != monitorPtr->threadRecPtr,
                "FD Monitor '%s' (fd %d) is owned by another thread.",
                monitorPtr->name,
                monitorPtr->fd);

    short filteredEvents = events & (POLLIN | POLLOUT | POLLPRI);

    LE_WARN_IF(filteredEvents != events,
               "Only POLLIN, POLLOUT, and POLLPRI events can be disabled. (fd monitor '%s')",
               monitorPtr->name);

    // Convert the events from POLLxx events to EPOLLxx events.
    uint32_t epollEvents = PollToEPoll(filteredEvents);

    // Remove them from the FD Monitor's epoll(7) flags set.
    monitorPtr->epollEvents &= (~epollEvents);

    UpdateEpollFd(monitorPtr);
}
Example #15
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;
    }
}
Example #16
0
//--------------------------------------------------------------------------------------------------
le_fdMonitor_Ref_t le_fdMonitor_Create
(
    const char*             name,       ///< [in] Name of the object (for diagnostics).
    int                     fd,         ///< [in] File descriptor to be monitored for events.
    le_fdMonitor_HandlerFunc_t handlerFunc, ///< [in] Handler function.
    short                   events      ///< [in] Initial set of events to be monitored.
)
//--------------------------------------------------------------------------------------------------
{
    // Get a pointer to the thread-specific event loop data record.
    event_PerThreadRec_t* perThreadRecPtr = thread_GetEventRecPtr();

    // Allocate the object.
    FdMonitor_t* fdMonitorPtr = le_mem_ForceAlloc(FdMonitorPool);

    // Initialize the object.
    fdMonitorPtr->link = LE_DLS_LINK_INIT;
    fdMonitorPtr->fd = fd;
    fdMonitorPtr->epollEvents = PollToEPoll(events) | EPOLLWAKEUP;  // Non-deferrable by default.
    fdMonitorPtr->isAlwaysReady = false;
    fdMonitorPtr->threadRecPtr = perThreadRecPtr;
    fdMonitorPtr->handlerFunc = handlerFunc;
    fdMonitorPtr->contextPtr = NULL;

    // Copy the name into it.
    if (le_utf8_Copy(fdMonitorPtr->name, name, sizeof(fdMonitorPtr->name), NULL) == LE_OVERFLOW)
    {
        LE_WARN("FD Monitor object name '%s' truncated to '%s'.", name, fdMonitorPtr->name);
    }

    LOCK

    // Create a safe reference for the object.
    fdMonitorPtr->safeRef = le_ref_CreateRef(FdMonitorRefMap, fdMonitorPtr);

    // Add it to the thread's FD Monitor list.
    le_dls_Queue(&perThreadRecPtr->fdMonitorList, &fdMonitorPtr->link);

    // Tell epoll(7) to start monitoring this fd.
    struct epoll_event ev;
    memset(&ev, 0, sizeof(ev));
    ev.events = fdMonitorPtr->epollEvents;
    ev.data.ptr = fdMonitorPtr->safeRef;
    if (epoll_ctl(perThreadRecPtr->epollFd, EPOLL_CTL_ADD, fd, &ev) == -1)
    {
        if (errno == EPERM)
        {
            LE_DEBUG("fd %d doesn't support epoll(), assuming always readable and writeable.", fd);
            fdMonitorPtr->isAlwaysReady = true;

            // If either EPOLLIN or EPOLLOUT are enabled, queue up the handler for this now.
            uint32_t epollEvents = fdMonitorPtr->epollEvents & (EPOLLIN | EPOLLOUT);
            if (epollEvents != 0)
            {
                fdMon_Report(fdMonitorPtr->safeRef, epollEvents);
            }
        }
        else
        {
            LE_FATAL("epoll_ctl(ADD) failed for fd %d. errno = %d (%m)", fd, errno);
        }
    }

    UNLOCK

    return fdMonitorPtr->safeRef;
}
Example #17
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);
}
Example #18
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!");
        }
    }
}