diff --git a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.h b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.h index 7fd248fdf699d9..4bdc09897eeb21 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.h +++ b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.h @@ -106,16 +106,26 @@ class GenericPlatformManagerImpl_POSIX : public GenericPlatformManagerImpl(this); } - void ProcessDeviceEvents(); +#if CHIP_SYSTEM_CONFIG_USE_LIBEV + static void _DispatchEventViaScheduleWork(System::Layer * aLayer, void * appState); +#else DeviceSafeQueue mChipEventQueue; std::atomic mShouldRunEventLoop; static void * EventLoopTaskMain(void * arg); +#endif + void ProcessDeviceEvents(); + std::atomic mShouldRunEventLoop; }; // Instruct the compiler to instantiate the template only when explicitly told to do so. extern template class GenericPlatformManagerImpl_POSIX; +#if CHIP_SYSTEM_CONFIG_USE_LIBEV +// with external libev mainloop, this should be implemented externally to terminate the mainloop cleanly +// (Note that there is a weak default implementation that just calls chipDie() when the external implementation is missing) +extern void ExitExternalMainLoop(); +#endif } // namespace Internal } // namespace DeviceLayer } // namespace chip diff --git a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.ipp b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.ipp index 4a52152d91d64f..a656d6b7230f7d 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.ipp +++ b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.ipp @@ -128,15 +128,35 @@ CHIP_ERROR GenericPlatformManagerImpl_POSIX::_StartChipTimer(System:: return CHIP_NO_ERROR; } +#if CHIP_SYSTEM_CONFIG_USE_LIBEV +template +void GenericPlatformManagerImpl_POSIX::_DispatchEventViaScheduleWork(System::Layer * aLayer, void * appState) +{ + const ChipDeviceEvent * event = static_cast(appState); + PlatformMgrImpl().DispatchEvent(event); + delete event; +} +#endif // CHIP_SYSTEM_CONFIG_USE_LIBEV + template CHIP_ERROR GenericPlatformManagerImpl_POSIX::_PostEvent(const ChipDeviceEvent * event) { +#if CHIP_SYSTEM_CONFIG_USE_LIBEV + // Schedule dispatching this event via System Layer's ScheduleWork + ChipDeviceEvent * eventCopyP = new ChipDeviceEvent; + VerifyOrDie(eventCopyP != nullptr); + *eventCopyP = *event; + SystemLayer().ScheduleWork(&_DispatchEventViaScheduleWork, eventCopyP); + return CHIP_NO_ERROR; +#else mChipEventQueue.Push(*event); SystemLayerSocketsLoop().Signal(); // Trigger wake select on CHIP thread return CHIP_NO_ERROR; +#endif // CHIP_SYSTEM_CONFIG_USE_LIBEV } +#if !CHIP_SYSTEM_CONFIG_USE_LIBEV template void GenericPlatformManagerImpl_POSIX::ProcessDeviceEvents() { @@ -146,6 +166,7 @@ void GenericPlatformManagerImpl_POSIX::ProcessDeviceEvents() Impl()->DispatchEvent(&event); } } +#endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV template void GenericPlatformManagerImpl_POSIX::_RunEventLoop() @@ -197,6 +218,7 @@ void GenericPlatformManagerImpl_POSIX::_RunEventLoop() pthread_cond_signal(&mEventQueueStoppedCond); } +#if !CHIP_SYSTEM_CONFIG_USE_LIBEV template void * GenericPlatformManagerImpl_POSIX::EventLoopTaskMain(void * arg) { @@ -204,6 +226,7 @@ void * GenericPlatformManagerImpl_POSIX::EventLoopTaskMain(void * arg static_cast *>(arg)->Impl()->RunEventLoop(); return nullptr; } +#endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV template CHIP_ERROR GenericPlatformManagerImpl_POSIX::_StartEventLoopTask() @@ -220,6 +243,10 @@ CHIP_ERROR GenericPlatformManagerImpl_POSIX::_StartEventLoopTask() VerifyOrReturnError(err == 0, CHIP_ERROR_POSIX(err)); #endif +#if CHIP_SYSTEM_CONFIG_USE_LIBEV + // with libev, we dont need our own mainloop + return CHIP_NO_ERROR; +#else // // We need to grab the lock here since we have to protect setting // mHasValidChipTask, which will be read right away upon creating the @@ -237,11 +264,26 @@ CHIP_ERROR GenericPlatformManagerImpl_POSIX::_StartEventLoopTask() pthread_mutex_unlock(&mStateLock); return CHIP_ERROR_POSIX(err); +#endif // CHIP_SYSTEM_CONFIG_USE_LIBEV } +#if CHIP_SYSTEM_CONFIG_USE_LIBEV +// fallback implementation +void __attribute__((weak)) ExitExternalMainLoop() +{ + // FIXME: implement better exit + VerifyOrDieWithMsg(false, DeviceLayer, "Missing custom ExitExternalMainLoop() implementation for clean shutdown -> just die"); +} +#endif // CHIP_SYSTEM_CONFIG_USE_LIBEV + template CHIP_ERROR GenericPlatformManagerImpl_POSIX::_StopEventLoopTask() { +#if CHIP_SYSTEM_CONFIG_USE_LIBEV + // with libev, the mainloop is set up and managed externally + ExitExternalMainLoop(); // this callback needs to be implemented. + return CHIP_NO_ERROR; +#else int err = 0; // @@ -294,6 +336,7 @@ CHIP_ERROR GenericPlatformManagerImpl_POSIX::_StopEventLoopTask() exit: mHasValidChipTask = false; return CHIP_ERROR_POSIX(err); +#endif // CHIP_SYSTEM_CONFIG_USE_LIBEV } template diff --git a/src/system/SystemLayerImplSelect.cpp b/src/system/SystemLayerImplSelect.cpp index aeed665bffdc2f..3ad643ab7454b1 100644 --- a/src/system/SystemLayerImplSelect.cpp +++ b/src/system/SystemLayerImplSelect.cpp @@ -162,10 +162,7 @@ CHIP_ERROR LayerImplSelect::StartTimer(Clock::Timeout delay, TimerCompleteCallba { (void) mTimerList.Add(timer); dispatch_source_t timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, DISPATCH_TIMER_STRICT, dispatchQueue); - if (timerSource == nullptr) - { - chipDie(); - } + VerifyOrDie(timerSource != nullptr); timer->mTimerSource = timerSource; dispatch_source_set_timer( @@ -181,10 +178,7 @@ CHIP_ERROR LayerImplSelect::StartTimer(Clock::Timeout delay, TimerCompleteCallba return CHIP_NO_ERROR; } #elif CHIP_SYSTEM_CONFIG_USE_LIBEV - if (mLibEvLoopP == nullptr) - { - chipDie(); - } + VerifyOrDie(mLibEvLoopP != nullptr); ev_timer_init(&timer->mLibEvTimer, &LayerImplSelect::HandleLibEvTimer, 1, 0); timer->mLibEvTimer.data = timer; auto t = Clock::Milliseconds64(delay).count(); @@ -226,10 +220,7 @@ void LayerImplSelect::CancelTimer(TimerCompleteCallback onComplete, void * appSt dispatch_release(timer->mTimerSource); } #elif CHIP_SYSTEM_CONFIG_USE_LIBEV - if (mLibEvLoopP == nullptr) - { - chipDie(); - } + VerifyOrDie(mLibEvLoopP != nullptr); ev_timer_stop(mLibEvLoopP, &timer->mLibEvTimer); #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH/LIBEV @@ -251,12 +242,20 @@ CHIP_ERROR LayerImplSelect::ScheduleWork(TimerCompleteCallback onComplete, void return CHIP_NO_ERROR; } #elif CHIP_SYSTEM_CONFIG_USE_LIBEV - // just a timer with no delay - return StartTimer(Clock::Timeout(0), onComplete, appState); + // schedule as timer with no delay, but do NOT cancel previous timers with same onComplete/appState! + TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp(), onComplete, appState); + VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY); + VerifyOrDie(mLibEvLoopP != nullptr); + ev_timer_init(&timer->mLibEvTimer, &LayerImplSelect::HandleLibEvTimer, 1, 0); + timer->mLibEvTimer.data = timer; + auto t = Clock::Milliseconds64(0).count(); + ev_timer_set(&timer->mLibEvTimer, static_cast(t) / 1E3, 0.); + (void) mTimerList.Add(timer); + ev_timer_start(mLibEvLoopP, &timer->mLibEvTimer); + return CHIP_NO_ERROR; #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH/LIBEV #if !CHIP_SYSTEM_CONFIG_USE_LIBEV // Note: dispatch based implementation needs this as fallback, but not LIBEV (and dead code is not allowed with -Werror) - // Ideally we would not use a timer here at all, but if we try to just // ScheduleLambda the lambda needs to capture the following: // 1) onComplete @@ -371,10 +370,7 @@ CHIP_ERROR LayerImplSelect::RequestCallbackOnPendingRead(SocketWatchToken token) } } #elif CHIP_SYSTEM_CONFIG_USE_LIBEV - if (mLibEvLoopP == nullptr) - { - chipDie(); - } + VerifyOrDie(mLibEvLoopP != nullptr); int evs = (watch->mPendingIO.Has(SocketEventFlags::kRead) ? EV_READ : 0) | (watch->mPendingIO.Has(SocketEventFlags::kWrite) ? EV_WRITE : 0); if (!ev_is_active(&watch->mIoWatcher)) @@ -434,10 +430,7 @@ CHIP_ERROR LayerImplSelect::RequestCallbackOnPendingWrite(SocketWatchToken token } } #elif CHIP_SYSTEM_CONFIG_USE_LIBEV - if (mLibEvLoopP == nullptr) - { - chipDie(); - } + VerifyOrDie(mLibEvLoopP != nullptr); int evs = (watch->mPendingIO.Has(SocketEventFlags::kRead) ? EV_READ : 0) | (watch->mPendingIO.Has(SocketEventFlags::kWrite) ? EV_WRITE : 0); if (!ev_is_active(&watch->mIoWatcher)) @@ -651,9 +644,9 @@ void LayerImplSelect::HandleTimerComplete(TimerList::Node * timer) void LayerImplSelect::HandleLibEvTimer(EV_P_ struct ev_timer * t, int revents) { TimerList::Node * timer = static_cast(t->data); - VerifyOrDie(timer); + VerifyOrDie(timer != nullptr); LayerImplSelect * layerP = dynamic_cast(timer->mCallback.mSystemLayer); - VerifyOrDie(layerP); + VerifyOrDie(layerP != nullptr); layerP->mTimerList.Remove(timer); layerP->mTimerPool.Invoke(timer); } diff --git a/src/system/SystemTimer.h b/src/system/SystemTimer.h index cd27fefcf11ef2..70d08d87850b24 100644 --- a/src/system/SystemTimer.h +++ b/src/system/SystemTimer.h @@ -100,7 +100,7 @@ class DLL_EXPORT TimerData #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH // Not defined - TimerData(const TimerData &) = delete; + TimerData(const TimerData &) = delete; TimerData & operator=(const TimerData &) = delete; };