3535#define PTHREAD_NULL 0
3636#endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING && !defined(PTHREAD_NULL)
3737
38+ #if CHIP_SYSTEM_CONFIG_USE_LIBEV
39+ // older libev do not yet have ev_io_modify
40+ #ifndef ev_io_modify
41+ #define ev_io_modify (ev, events_ ) \
42+ do \
43+ { \
44+ (ev)->events = ((ev)->events & EV__IOFDSET) | (events_); \
45+ } while (0 )
46+ #endif // ev_io_modify
47+ #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
48+
3849namespace chip {
3950namespace System {
4051
@@ -82,11 +93,25 @@ void LayerImplSelect::Shutdown()
8293 {
8394 w.DisableAndClear ();
8495 }
96+ #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
97+ TimerList::Node * timer;
98+ while ((timer = mTimerList .PopEarliest ()) != nullptr )
99+ {
100+ if (ev_is_active (&timer->mLibEvTimer ))
101+ {
102+ ev_timer_stop (mLibEvLoopP , &timer->mLibEvTimer );
103+ }
104+ }
105+ mTimerPool .ReleaseAll ();
85106
86- #else // CHIP_SYSTEM_CONFIG_USE_DISPATCH
107+ for (auto & w : mSocketWatchPool )
108+ {
109+ w.DisableAndClear ();
110+ }
111+ #else
87112 mTimerList .Clear ();
88113 mTimerPool .ReleaseAll ();
89- #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH
114+ #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH/LIBEV
90115
91116 mWakeEvent .Close (*this );
92117
@@ -155,14 +180,28 @@ CHIP_ERROR LayerImplSelect::StartTimer(Clock::Timeout delay, TimerCompleteCallba
155180 dispatch_resume (timerSource);
156181 return CHIP_NO_ERROR;
157182 }
158- #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH
159-
183+ #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
184+ if (mLibEvLoopP == nullptr )
185+ {
186+ chipDie ();
187+ }
188+ ev_timer_init (&timer->mLibEvTimer , &LayerImplSelect::HandleLibEvTimer, 1 , 0 );
189+ timer->mLibEvTimer .data = timer;
190+ auto t = Clock::Milliseconds64 (delay).count ();
191+ ev_timer_set (&timer->mLibEvTimer , static_cast <double >(t) / 1E3 , 0 .);
192+ (void ) mTimerList .Add (timer);
193+ ev_timer_start (mLibEvLoopP , &timer->mLibEvTimer );
194+ return CHIP_NO_ERROR;
195+ #endif
196+ #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
197+ // Note: dispatch based implementation needs this as fallback, but not LIBEV (and dead code is not allowed with -Werror)
160198 if (mTimerList .Add (timer) == timer)
161199 {
162200 // The new timer is the earliest, so the time until the next event has probably changed.
163201 Signal ();
164202 }
165203 return CHIP_NO_ERROR;
204+ #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
166205}
167206
168207void LayerImplSelect::CancelTimer (TimerCompleteCallback onComplete, void * appState)
@@ -186,7 +225,13 @@ void LayerImplSelect::CancelTimer(TimerCompleteCallback onComplete, void * appSt
186225 dispatch_source_cancel (timer->mTimerSource );
187226 dispatch_release (timer->mTimerSource );
188227 }
189- #endif
228+ #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
229+ if (mLibEvLoopP == nullptr )
230+ {
231+ chipDie ();
232+ }
233+ ev_timer_stop (mLibEvLoopP , &timer->mLibEvTimer );
234+ #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH/LIBEV
190235
191236 mTimerPool .Release (timer);
192237 Signal ();
@@ -205,7 +250,12 @@ CHIP_ERROR LayerImplSelect::ScheduleWork(TimerCompleteCallback onComplete, void
205250 });
206251 return CHIP_NO_ERROR;
207252 }
208- #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH
253+ #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
254+ // just a timer with no delay
255+ return StartTimer (Clock::Timeout (0 ), onComplete, appState);
256+ #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH/LIBEV
257+ #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
258+ // Note: dispatch based implementation needs this as fallback, but not LIBEV (and dead code is not allowed with -Werror)
209259
210260 // Ideally we would not use a timer here at all, but if we try to just
211261 // ScheduleLambda the lambda needs to capture the following:
@@ -241,6 +291,7 @@ CHIP_ERROR LayerImplSelect::ScheduleWork(TimerCompleteCallback onComplete, void
241291 Signal ();
242292 }
243293 return CHIP_NO_ERROR;
294+ #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
244295}
245296
246297CHIP_ERROR LayerImplSelect::StartWatchingSocket (int fd, SocketWatchToken * tokenOut)
@@ -262,6 +313,11 @@ CHIP_ERROR LayerImplSelect::StartWatchingSocket(int fd, SocketWatchToken * token
262313 VerifyOrReturnError (watch != nullptr , CHIP_ERROR_ENDPOINT_POOL_FULL);
263314
264315 watch->mFD = fd;
316+ #if CHIP_SYSTEM_CONFIG_USE_LIBEV
317+ ev_io_init (&watch->mIoWatcher , &LayerImplSelect::HandleLibEvIoWatcher, 0 , 0 );
318+ watch->mIoWatcher .data = watch;
319+ watch->mLayerImplSelectP = this ;
320+ #endif
265321
266322 *tokenOut = reinterpret_cast <SocketWatchToken>(watch);
267323 return CHIP_NO_ERROR;
@@ -314,6 +370,27 @@ CHIP_ERROR LayerImplSelect::RequestCallbackOnPendingRead(SocketWatchToken token)
314370 dispatch_activate (watch->mRdSource );
315371 }
316372 }
373+ #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
374+ if (mLibEvLoopP == nullptr )
375+ {
376+ chipDie ();
377+ }
378+ int evs = (watch->mPendingIO .Has (SocketEventFlags::kRead ) ? EV_READ : 0 ) |
379+ (watch->mPendingIO .Has (SocketEventFlags::kWrite ) ? EV_WRITE : 0 );
380+ if (!ev_is_active (&watch->mIoWatcher ))
381+ {
382+ // First time actually using that watch
383+ ev_io_set (&watch->mIoWatcher , watch->mFD , evs);
384+ ev_io_start (mLibEvLoopP , &watch->mIoWatcher );
385+ }
386+ else
387+ {
388+ // already active, just change flags
389+ // Note: changing flags only reliably works when the watcher is stopped
390+ ev_io_stop (mLibEvLoopP , &watch->mIoWatcher );
391+ ev_io_modify (&watch->mIoWatcher , evs);
392+ ev_io_start (mLibEvLoopP , &watch->mIoWatcher );
393+ }
317394#endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH
318395
319396 return CHIP_NO_ERROR;
@@ -353,10 +430,30 @@ CHIP_ERROR LayerImplSelect::RequestCallbackOnPendingWrite(SocketWatchToken token
353430 }
354431 });
355432 // only now we are sure the source exists and can become active
356- watch->mPendingIO .Set (SocketEventFlags::kWrite );
357433 dispatch_activate (watch->mWrSource );
358434 }
359435 }
436+ #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
437+ if (mLibEvLoopP == nullptr )
438+ {
439+ chipDie ();
440+ }
441+ int evs = (watch->mPendingIO .Has (SocketEventFlags::kRead ) ? EV_READ : 0 ) |
442+ (watch->mPendingIO .Has (SocketEventFlags::kWrite ) ? EV_WRITE : 0 );
443+ if (!ev_is_active (&watch->mIoWatcher ))
444+ {
445+ // First time actually using that watch
446+ ev_io_set (&watch->mIoWatcher , watch->mFD , evs);
447+ ev_io_start (mLibEvLoopP , &watch->mIoWatcher );
448+ }
449+ else
450+ {
451+ // already active, just change flags
452+ // Note: changing flags only reliably works when the watcher is stopped
453+ ev_io_stop (mLibEvLoopP , &watch->mIoWatcher );
454+ ev_io_modify (&watch->mIoWatcher , evs);
455+ ev_io_start (mLibEvLoopP , &watch->mIoWatcher );
456+ }
360457#endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH
361458
362459 return CHIP_NO_ERROR;
@@ -369,6 +466,14 @@ CHIP_ERROR LayerImplSelect::ClearCallbackOnPendingRead(SocketWatchToken token)
369466
370467 watch->mPendingIO .Clear (SocketEventFlags::kRead );
371468
469+ #if CHIP_SYSTEM_CONFIG_USE_LIBEV
470+ if (ev_is_active (&watch->mIoWatcher ) && watch->mPendingIO .Raw () == 0 )
471+ {
472+ // all flags cleared now, stop watching
473+ ev_io_stop (mLibEvLoopP , &watch->mIoWatcher );
474+ }
475+ #endif
476+
372477 return CHIP_NO_ERROR;
373478}
374479
@@ -379,6 +484,14 @@ CHIP_ERROR LayerImplSelect::ClearCallbackOnPendingWrite(SocketWatchToken token)
379484
380485 watch->mPendingIO .Clear (SocketEventFlags::kWrite );
381486
487+ #if CHIP_SYSTEM_CONFIG_USE_LIBEV
488+ if (ev_is_active (&watch->mIoWatcher ) && watch->mPendingIO .Raw () == 0 )
489+ {
490+ // all flags cleared now, stop watching
491+ ev_io_stop (mLibEvLoopP , &watch->mIoWatcher );
492+ }
493+ #endif
494+
382495 return CHIP_NO_ERROR;
383496}
384497
@@ -390,7 +503,7 @@ CHIP_ERROR LayerImplSelect::StopWatchingSocket(SocketWatchToken * tokenInOut)
390503 VerifyOrReturnError (watch != nullptr , CHIP_ERROR_INVALID_ARGUMENT);
391504 VerifyOrReturnError (watch->mFD >= 0 , CHIP_ERROR_INCORRECT_STATE);
392505
393- #if CHIP_SYSTEM_CONFIG_USE_DISPATCH
506+ #if CHIP_SYSTEM_CONFIG_USE_DISPATCH || CHIP_SYSTEM_CONFIG_USE_LIBEV
394507 watch->DisableAndClear ();
395508#else
396509 watch->Clear ();
@@ -526,12 +639,47 @@ void LayerImplSelect::HandleEvents()
526639}
527640
528641#if CHIP_SYSTEM_CONFIG_USE_DISPATCH
642+
529643void LayerImplSelect::HandleTimerComplete (TimerList::Node * timer)
530644{
531645 mTimerList .Remove (timer);
532646 mTimerPool .Invoke (timer);
533647}
534- #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH
648+
649+ #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
650+
651+ void LayerImplSelect::HandleLibEvTimer (EV_P_ struct ev_timer * t, int revents)
652+ {
653+ TimerList::Node * timer = static_cast <TimerList::Node *>(t->data );
654+ VerifyOrDie (timer);
655+ LayerImplSelect * layerP = dynamic_cast <LayerImplSelect *>(timer->mCallback .mSystemLayer );
656+ VerifyOrDie (layerP);
657+ layerP->mTimerList .Remove (timer);
658+ layerP->mTimerPool .Invoke (timer);
659+ }
660+
661+ void LayerImplSelect::HandleLibEvIoWatcher (EV_P_ struct ev_io * i, int revents)
662+ {
663+ SocketWatch * watch = static_cast <SocketWatch *>(i->data );
664+ if (watch != nullptr && watch->mCallback != nullptr && watch->mLayerImplSelectP != nullptr )
665+ {
666+ SocketEvents events;
667+ if (revents & EV_READ)
668+ {
669+ events.Set (SocketEventFlags::kRead );
670+ }
671+ if (revents & EV_WRITE)
672+ {
673+ events.Set (SocketEventFlags::kWrite );
674+ }
675+ if (events.HasAny ())
676+ {
677+ watch->mCallback (events, watch->mCallbackData );
678+ }
679+ }
680+ }
681+
682+ #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH/LIBEV
535683
536684void LayerImplSelect::SocketWatch::Clear ()
537685{
@@ -542,6 +690,8 @@ void LayerImplSelect::SocketWatch::Clear()
542690#if CHIP_SYSTEM_CONFIG_USE_DISPATCH
543691 mRdSource = nullptr ;
544692 mWrSource = nullptr ;
693+ #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
694+ mLayerImplSelectP = nullptr ;
545695#endif
546696}
547697
@@ -560,7 +710,16 @@ void LayerImplSelect::SocketWatch::DisableAndClear()
560710 }
561711 Clear ();
562712}
563- #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH
713+ #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
714+ void LayerImplSelect::SocketWatch::DisableAndClear ()
715+ {
716+ if (mLayerImplSelectP != nullptr && mLayerImplSelectP ->mLibEvLoopP != nullptr )
717+ {
718+ ev_io_stop (mLayerImplSelectP ->mLibEvLoopP , &mIoWatcher );
719+ }
720+ Clear ();
721+ }
722+ #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH/LIBEV
564723
565724} // namespace System
566725} // namespace chip
0 commit comments