//-------------------------------------------------------------------------------------------------- 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)); } }
//-------------------------------------------------------------------------------------------------- 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); }