LCOV - code coverage report
Current view: top level - system - SystemLayerImplSelect.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 161 167 96.4 %
Date: 2024-02-15 08:20:41 Functions: 20 20 100.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2020-2021 Project CHIP Authors
       4             :  *    Copyright (c) 2014-2017 Nest Labs, Inc.
       5             :  *
       6             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7             :  *    you may not use this file except in compliance with the License.
       8             :  *    You may obtain a copy of the License at
       9             :  *
      10             :  *        http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  *    Unless required by applicable law or agreed to in writing, software
      13             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  *    See the License for the specific language governing permissions and
      16             :  *    limitations under the License.
      17             :  */
      18             : 
      19             : /**
      20             :  *    @file
      21             :  *      This file implements Layer using select().
      22             :  */
      23             : 
      24             : #include <lib/support/CodeUtils.h>
      25             : #include <lib/support/TimeUtils.h>
      26             : #include <platform/LockTracker.h>
      27             : #include <system/SystemFaultInjection.h>
      28             : #include <system/SystemLayer.h>
      29             : #include <system/SystemLayerImplSelect.h>
      30             : 
      31             : #include <errno.h>
      32             : 
      33             : // Choose an approximation of PTHREAD_NULL if pthread.h doesn't define one.
      34             : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING && !defined(PTHREAD_NULL)
      35             : #define PTHREAD_NULL 0
      36             : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING && !defined(PTHREAD_NULL)
      37             : 
      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             : 
      49             : namespace chip {
      50             : namespace System {
      51             : 
      52             : constexpr Clock::Seconds64 kDefaultMinSleepPeriod = Clock::Seconds64(60 * 60 * 24 * 30); // Month [sec]
      53             : 
      54          80 : CHIP_ERROR LayerImplSelect::Init()
      55             : {
      56          80 :     VerifyOrReturnError(mLayerState.SetInitializing(), CHIP_ERROR_INCORRECT_STATE);
      57             : 
      58          80 :     RegisterPOSIXErrorFormatter();
      59             : 
      60        5200 :     for (auto & w : mSocketWatchPool)
      61             :     {
      62        5120 :         w.Clear();
      63             :     }
      64             : 
      65             : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
      66          80 :     mHandleSelectThread = PTHREAD_NULL;
      67             : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
      68             : 
      69             : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
      70             :     // Create an event to allow an arbitrary thread to wake the thread in the select loop.
      71          80 :     ReturnErrorOnFailure(mWakeEvent.Open(*this));
      72             : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
      73             : 
      74          80 :     VerifyOrReturnError(mLayerState.SetInitialized(), CHIP_ERROR_INCORRECT_STATE);
      75          80 :     return CHIP_NO_ERROR;
      76             : }
      77             : 
      78          80 : void LayerImplSelect::Shutdown()
      79             : {
      80          80 :     VerifyOrReturn(mLayerState.SetShuttingDown());
      81             : 
      82             : #if CHIP_SYSTEM_CONFIG_USE_DISPATCH
      83             :     TimerList::Node * timer;
      84             :     while ((timer = mTimerList.PopEarliest()) != nullptr)
      85             :     {
      86             :         if (timer->mTimerSource != nullptr)
      87             :         {
      88             :             dispatch_source_cancel(timer->mTimerSource);
      89             :             dispatch_release(timer->mTimerSource);
      90             :         }
      91             :     }
      92             :     mTimerPool.ReleaseAll();
      93             : 
      94             :     for (auto & w : mSocketWatchPool)
      95             :     {
      96             :         w.DisableAndClear();
      97             :     }
      98             : #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
      99             :     TimerList::Node * timer;
     100             :     while ((timer = mTimerList.PopEarliest()) != nullptr)
     101             :     {
     102             :         if (ev_is_active(&timer->mLibEvTimer))
     103             :         {
     104             :             ev_timer_stop(mLibEvLoopP, &timer->mLibEvTimer);
     105             :         }
     106             :     }
     107             :     mTimerPool.ReleaseAll();
     108             : 
     109             :     for (auto & w : mSocketWatchPool)
     110             :     {
     111             :         w.DisableAndClear();
     112             :     }
     113             : #else
     114          80 :     mTimerList.Clear();
     115          80 :     mTimerPool.ReleaseAll();
     116             : #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH/LIBEV
     117             : 
     118             : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
     119          80 :     mWakeEvent.Close(*this);
     120             : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
     121             : 
     122          80 :     mLayerState.ResetFromShuttingDown(); // Return to uninitialized state to permit re-initialization.
     123             : }
     124             : 
     125     8104585 : void LayerImplSelect::Signal()
     126             : {
     127             : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     128             :     ChipLogError(DeviceLayer, "Signal() should not be called in CHIP_SYSTEM_CONFIG_USE_LIBEV builds (might be ok in tests)");
     129             : #else
     130             :     /*
     131             :      * Wake up the I/O thread by writing a single byte to the wake pipe.
     132             :      *
     133             :      * If this is being called from within an I/O event callback, then writing to the wake pipe can be skipped,
     134             :      * since the I/O thread is already awake.
     135             :      *
     136             :      * Furthermore, we don't care if this write fails as the only reasonably likely failure is that the pipe is full, in which
     137             :      * case the select calling thread is going to wake up anyway.
     138             :      */
     139             : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     140     8104585 :     if (pthread_equal(mHandleSelectThread, pthread_self()))
     141             :     {
     142       32841 :         return;
     143             :     }
     144             : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     145             : 
     146             :     // Send notification to wake up the select call.
     147     8071744 :     CHIP_ERROR status = mWakeEvent.Notify();
     148     8071744 :     if (status != CHIP_NO_ERROR)
     149             :     {
     150             : 
     151           1 :         ChipLogError(chipSystemLayer, "System wake event notify failed: %" CHIP_ERROR_FORMAT, status.Format());
     152             :     }
     153             : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
     154             : }
     155             : 
     156     4121931 : CHIP_ERROR LayerImplSelect::StartTimer(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState)
     157             : {
     158     4121931 :     assertChipStackLockedByCurrentThread();
     159             : 
     160     4121931 :     VerifyOrReturnError(mLayerState.IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     161             : 
     162     4121930 :     CHIP_SYSTEM_FAULT_INJECT(FaultInjection::kFault_TimeoutImmediate, delay = System::Clock::kZero);
     163             : 
     164     4121930 :     CancelTimer(onComplete, appState);
     165             : 
     166     4121930 :     TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp() + delay, onComplete, appState);
     167     4121930 :     VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY);
     168             : 
     169             : #if CHIP_SYSTEM_CONFIG_USE_DISPATCH
     170             :     dispatch_queue_t dispatchQueue = GetDispatchQueue();
     171             :     if (dispatchQueue)
     172             :     {
     173             :         (void) mTimerList.Add(timer);
     174             :         dispatch_source_t timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, DISPATCH_TIMER_STRICT, dispatchQueue);
     175             :         VerifyOrDie(timerSource != nullptr);
     176             : 
     177             :         timer->mTimerSource = timerSource;
     178             :         dispatch_source_set_timer(
     179             :             timerSource, dispatch_walltime(nullptr, static_cast<int64_t>(Clock::Milliseconds64(delay).count() * NSEC_PER_MSEC)),
     180             :             DISPATCH_TIME_FOREVER, 2 * NSEC_PER_MSEC);
     181             :         dispatch_source_set_event_handler(timerSource, ^{
     182             :             dispatch_source_cancel(timerSource);
     183             :             dispatch_release(timerSource);
     184             : 
     185             :             this->HandleTimerComplete(timer);
     186             :         });
     187             :         dispatch_resume(timerSource);
     188             :         return CHIP_NO_ERROR;
     189             :     }
     190             : #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
     191             :     VerifyOrDie(mLibEvLoopP != nullptr);
     192             :     ev_timer_init(&timer->mLibEvTimer, &LayerImplSelect::HandleLibEvTimer, 1, 0);
     193             :     timer->mLibEvTimer.data = timer;
     194             :     auto t                  = Clock::Milliseconds64(delay).count();
     195             :     // Note: libev uses the time when events started processing as the "now" reference for relative timers,
     196             :     //   for efficiency reasons. This point in time is represented by ev_now().
     197             :     //   The real time is represented by ev_time().
     198             :     //   Without correction, this leads to timers firing a bit too early relative to the time StartTimer()
     199             :     //   is called. So the relative value passed to ev_timer_set() is adjusted (increased) here.
     200             :     // Note: Still, slightly early (and of course, late) firing timers are something the caller MUST be prepared for,
     201             :     //   because edge cases like system clock adjustments may cause them even with the correction applied here.
     202             :     ev_timer_set(&timer->mLibEvTimer, (static_cast<double>(t) / 1E3) + ev_time() - ev_now(mLibEvLoopP), 0.);
     203             :     (void) mTimerList.Add(timer);
     204             :     ev_timer_start(mLibEvLoopP, &timer->mLibEvTimer);
     205             :     return CHIP_NO_ERROR;
     206             : #endif
     207             : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
     208             :     // Note: dispatch based implementation needs this as fallback, but not LIBEV (and dead code is not allowed with -Werror)
     209     4121930 :     if (mTimerList.Add(timer) == timer)
     210             :     {
     211             :         // The new timer is the earliest, so the time until the next event has probably changed.
     212     3976811 :         Signal();
     213             :     }
     214     4121930 :     return CHIP_NO_ERROR;
     215             : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
     216             : }
     217             : 
     218           6 : CHIP_ERROR LayerImplSelect::ExtendTimerTo(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState)
     219             : {
     220           6 :     VerifyOrReturnError(delay.count() > 0, CHIP_ERROR_INVALID_ARGUMENT);
     221             : 
     222           5 :     assertChipStackLockedByCurrentThread();
     223             : 
     224           5 :     Clock::Timeout remainingTime = mTimerList.GetRemainingTime(onComplete, appState);
     225           5 :     if (remainingTime.count() < delay.count())
     226             :     {
     227           3 :         if (remainingTime == Clock::kZero)
     228             :         {
     229             :             // If remaining time is Clock::kZero, it might possible that our timer is in
     230             :             // the mExpiredTimers list and about to be fired. Remove it from that list, since we are extending it.
     231           1 :             mExpiredTimers.Remove(onComplete, appState);
     232             :         }
     233           3 :         return StartTimer(delay, onComplete, appState);
     234             :     }
     235             : 
     236           2 :     return CHIP_NO_ERROR;
     237             : }
     238             : 
     239          18 : bool LayerImplSelect::IsTimerActive(TimerCompleteCallback onComplete, void * appState)
     240             : {
     241          18 :     bool timerIsActive = (mTimerList.GetRemainingTime(onComplete, appState) > Clock::kZero);
     242             : 
     243          18 :     if (!timerIsActive)
     244             :     {
     245             :         // check if the timer is in the mExpiredTimers list about to be fired.
     246           5 :         for (TimerList::Node * timer = mExpiredTimers.Earliest(); timer != nullptr; timer = timer->mNextTimer)
     247             :         {
     248           0 :             if (timer->GetCallback().GetOnComplete() == onComplete && timer->GetCallback().GetAppState() == appState)
     249             :             {
     250           0 :                 return true;
     251             :             }
     252             :         }
     253             :     }
     254             : 
     255          18 :     return timerIsActive;
     256             : }
     257             : 
     258     4154792 : void LayerImplSelect::CancelTimer(TimerCompleteCallback onComplete, void * appState)
     259             : {
     260     4154792 :     assertChipStackLockedByCurrentThread();
     261             : 
     262     4154792 :     VerifyOrReturn(mLayerState.IsInitialized());
     263             : 
     264     4154792 :     TimerList::Node * timer = mTimerList.Remove(onComplete, appState);
     265     4154792 :     if (timer == nullptr)
     266             :     {
     267             :         // The timer was not in our "will fire in the future" list, but it might
     268             :         // be in the "we're about to fire these" chunk we already grabbed from
     269             :         // that list.  Check for it there too, and if found there we still want
     270             :         // to cancel it.
     271       33120 :         timer = mExpiredTimers.Remove(onComplete, appState);
     272             :     }
     273     4154792 :     VerifyOrReturn(timer != nullptr);
     274             : 
     275             : #if CHIP_SYSTEM_CONFIG_USE_DISPATCH
     276             :     if (timer->mTimerSource != nullptr)
     277             :     {
     278             :         dispatch_source_cancel(timer->mTimerSource);
     279             :         dispatch_release(timer->mTimerSource);
     280             :     }
     281             : #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
     282             :     VerifyOrDie(mLibEvLoopP != nullptr);
     283             :     ev_timer_stop(mLibEvLoopP, &timer->mLibEvTimer);
     284             : #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH/LIBEV
     285             : 
     286     4121689 :     mTimerPool.Release(timer);
     287             : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
     288             :     // LIBEV has no I/O wakeup thread, so must not call Signal()
     289     4121689 :     Signal();
     290             : #endif
     291             : }
     292             : 
     293       11166 : CHIP_ERROR LayerImplSelect::ScheduleWork(TimerCompleteCallback onComplete, void * appState)
     294             : {
     295       11166 :     assertChipStackLockedByCurrentThread();
     296             : 
     297       11166 :     VerifyOrReturnError(mLayerState.IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     298             : 
     299             : #if CHIP_SYSTEM_CONFIG_USE_DISPATCH
     300             :     dispatch_queue_t dispatchQueue = GetDispatchQueue();
     301             :     if (dispatchQueue)
     302             :     {
     303             :         dispatch_async(dispatchQueue, ^{
     304             :             onComplete(this, appState);
     305             :         });
     306             :         return CHIP_NO_ERROR;
     307             :     }
     308             : #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
     309             :     // schedule as timer with no delay, but do NOT cancel previous timers with same onComplete/appState!
     310             :     TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp(), onComplete, appState);
     311             :     VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY);
     312             :     VerifyOrDie(mLibEvLoopP != nullptr);
     313             :     ev_timer_init(&timer->mLibEvTimer, &LayerImplSelect::HandleLibEvTimer, 1, 0);
     314             :     timer->mLibEvTimer.data = timer;
     315             :     auto t                  = Clock::Milliseconds64(0).count();
     316             :     ev_timer_set(&timer->mLibEvTimer, static_cast<double>(t) / 1E3, 0.);
     317             :     (void) mTimerList.Add(timer);
     318             :     ev_timer_start(mLibEvLoopP, &timer->mLibEvTimer);
     319             :     return CHIP_NO_ERROR;
     320             : #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH/LIBEV
     321             : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
     322             :     // Note: dispatch based implementation needs this as fallback, but not LIBEV (and dead code is not allowed with -Werror)
     323             :     // Ideally we would not use a timer here at all, but if we try to just
     324             :     // ScheduleLambda the lambda needs to capture the following:
     325             :     // 1) onComplete
     326             :     // 2) appState
     327             :     // 3) The `this` pointer, because onComplete needs to be passed a pointer to
     328             :     //    the System::Layer.
     329             :     //
     330             :     // On a 64-bit system that's 24 bytes, but lambdas passed to ScheduleLambda
     331             :     // are capped at CHIP_CONFIG_LAMBDA_EVENT_SIZE which is 16 bytes.
     332             :     //
     333             :     // So for now use a timer as a poor-man's closure that captures `this` and
     334             :     // onComplete and appState in a single pointer, so we fit inside the size
     335             :     // limit.
     336             :     //
     337             :     // TODO: We could do something here where we compile-time condition on the
     338             :     // sizes of things and use a direct ScheduleLambda if it would fit and this
     339             :     // setup otherwise.
     340             :     //
     341             :     // TODO: But also, unit tests seem to do SystemLayer::ScheduleWork without
     342             :     // actually running a useful event loop (in the PlatformManager sense),
     343             :     // which breaks if we use ScheduleLambda here, since that does rely on the
     344             :     // PlatformManager event loop. So for now, keep scheduling an expires-ASAP
     345             :     // timer, but just make sure we don't cancel existing timers with the same
     346             :     // callback and appState, so ScheduleWork invocations don't stomp on each
     347             :     // other.
     348       11166 :     TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp(), onComplete, appState);
     349       11166 :     VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY);
     350             : 
     351       11166 :     if (mTimerList.Add(timer) == timer)
     352             :     {
     353             :         // The new timer is the earliest, so the time until the next event has probably changed.
     354        5783 :         Signal();
     355             :     }
     356       11166 :     return CHIP_NO_ERROR;
     357             : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
     358             : }
     359             : 
     360         171 : CHIP_ERROR LayerImplSelect::StartWatchingSocket(int fd, SocketWatchToken * tokenOut)
     361             : {
     362             :     // Find a free slot.
     363         171 :     SocketWatch * watch = nullptr;
     364       11115 :     for (auto & w : mSocketWatchPool)
     365             :     {
     366       10944 :         if (w.mFD == fd)
     367             :         {
     368             :             // Duplicate registration is an error.
     369           0 :             return CHIP_ERROR_INVALID_ARGUMENT;
     370             :         }
     371       10944 :         if ((w.mFD == kInvalidFd) && (watch == nullptr))
     372             :         {
     373         171 :             watch = &w;
     374             :         }
     375             :     }
     376         171 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_ENDPOINT_POOL_FULL);
     377             : 
     378         171 :     watch->mFD = fd;
     379             : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     380             :     ev_io_init(&watch->mIoWatcher, &LayerImplSelect::HandleLibEvIoWatcher, 0, 0);
     381             :     watch->mIoWatcher.data   = watch;
     382             :     watch->mLayerImplSelectP = this;
     383             : #endif
     384             : 
     385         171 :     *tokenOut = reinterpret_cast<SocketWatchToken>(watch);
     386         171 :     return CHIP_NO_ERROR;
     387             : }
     388             : 
     389         170 : CHIP_ERROR LayerImplSelect::SetCallback(SocketWatchToken token, SocketWatchCallback callback, intptr_t data)
     390             : {
     391         170 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
     392         170 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     393             : 
     394         170 :     watch->mCallback     = callback;
     395         170 :     watch->mCallbackData = data;
     396         170 :     return CHIP_NO_ERROR;
     397             : }
     398             : 
     399         170 : CHIP_ERROR LayerImplSelect::RequestCallbackOnPendingRead(SocketWatchToken token)
     400             : {
     401         170 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
     402         170 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     403             : 
     404         170 :     watch->mPendingIO.Set(SocketEventFlags::kRead);
     405             : 
     406             : #if CHIP_SYSTEM_CONFIG_USE_DISPATCH
     407             :     if (watch->mRdSource == nullptr)
     408             :     {
     409             :         // First time requesting callback for read events: install a dispatch source
     410             :         dispatch_queue_t dispatchQueue = GetDispatchQueue();
     411             :         if (dispatchQueue == nullptr)
     412             :         {
     413             :             // Note: if no dispatch queue is available, callbacks most probably will not work,
     414             :             //       unless, as in some tests from a test-specific local loop,
     415             :             //       the select based event handling (Prepare/WaitFor/HandleEvents) is invoked.
     416             :             ChipLogError(DeviceLayer,
     417             :                          "RequestCallbackOnPendingRead with no dispatch queue: callback may not work (might be ok in tests)");
     418             :         }
     419             :         else
     420             :         {
     421             :             watch->mRdSource =
     422             :                 dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, static_cast<uintptr_t>(watch->mFD), 0, dispatchQueue);
     423             :             ReturnErrorCodeIf(watch->mRdSource == nullptr, CHIP_ERROR_NO_MEMORY);
     424             :             dispatch_source_set_event_handler(watch->mRdSource, ^{
     425             :                 if (watch->mPendingIO.Has(SocketEventFlags::kRead) && watch->mCallback != nullptr)
     426             :                 {
     427             :                     SocketEvents events;
     428             :                     events.Set(SocketEventFlags::kRead);
     429             :                     watch->mCallback(events, watch->mCallbackData);
     430             :                 }
     431             :             });
     432             :             // only now we are sure the source exists and can become active
     433             :             dispatch_activate(watch->mRdSource);
     434             :         }
     435             :     }
     436             : #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
     437             :     VerifyOrDie(mLibEvLoopP != nullptr);
     438             :     int evs = (watch->mPendingIO.Has(SocketEventFlags::kRead) ? EV_READ : 0) |
     439             :         (watch->mPendingIO.Has(SocketEventFlags::kWrite) ? EV_WRITE : 0);
     440             :     if (!ev_is_active(&watch->mIoWatcher))
     441             :     {
     442             :         // First time actually using that watch
     443             :         ev_io_set(&watch->mIoWatcher, watch->mFD, evs);
     444             :         ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
     445             :     }
     446             :     else
     447             :     {
     448             :         // already active, just change flags
     449             :         // Note: changing flags only reliably works when the watcher is stopped
     450             :         ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
     451             :         ev_io_modify(&watch->mIoWatcher, evs);
     452             :         ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
     453             :     }
     454             : #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH
     455             : 
     456         170 :     return CHIP_NO_ERROR;
     457             : }
     458             : 
     459           9 : CHIP_ERROR LayerImplSelect::RequestCallbackOnPendingWrite(SocketWatchToken token)
     460             : {
     461           9 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
     462           9 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     463             : 
     464           9 :     watch->mPendingIO.Set(SocketEventFlags::kWrite);
     465             : 
     466             : #if CHIP_SYSTEM_CONFIG_USE_DISPATCH
     467             :     if (watch->mWrSource == nullptr)
     468             :     {
     469             :         // First time requesting callback for read events: install a dispatch source
     470             :         dispatch_queue_t dispatchQueue = GetDispatchQueue();
     471             :         if (dispatchQueue == nullptr)
     472             :         {
     473             :             // Note: if no dispatch queue is available, callbacks most probably will not work,
     474             :             //       unless, as in some tests from a test-specific local loop,
     475             :             //       the select based event handling (Prepare/WaitFor/HandleEvents) is invoked.
     476             :             ChipLogError(DeviceLayer,
     477             :                          "RequestCallbackOnPendingWrite with no dispatch queue: callback may not work (might be ok in tests)");
     478             :         }
     479             :         else
     480             :         {
     481             :             watch->mWrSource =
     482             :                 dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, static_cast<uintptr_t>(watch->mFD), 0, dispatchQueue);
     483             :             ReturnErrorCodeIf(watch->mWrSource == nullptr, CHIP_ERROR_NO_MEMORY);
     484             :             dispatch_source_set_event_handler(watch->mWrSource, ^{
     485             :                 if (watch->mPendingIO.Has(SocketEventFlags::kWrite) && watch->mCallback != nullptr)
     486             :                 {
     487             :                     SocketEvents events;
     488             :                     events.Set(SocketEventFlags::kWrite);
     489             :                     watch->mCallback(events, watch->mCallbackData);
     490             :                 }
     491             :             });
     492             :             // only now we are sure the source exists and can become active
     493             :             dispatch_activate(watch->mWrSource);
     494             :         }
     495             :     }
     496             : #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
     497             :     VerifyOrDie(mLibEvLoopP != nullptr);
     498             :     int evs = (watch->mPendingIO.Has(SocketEventFlags::kRead) ? EV_READ : 0) |
     499             :         (watch->mPendingIO.Has(SocketEventFlags::kWrite) ? EV_WRITE : 0);
     500             :     if (!ev_is_active(&watch->mIoWatcher))
     501             :     {
     502             :         // First time actually using that watch
     503             :         ev_io_set(&watch->mIoWatcher, watch->mFD, evs);
     504             :         ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
     505             :     }
     506             :     else
     507             :     {
     508             :         // already active, just change flags
     509             :         // Note: changing flags only reliably works when the watcher is stopped
     510             :         ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
     511             :         ev_io_modify(&watch->mIoWatcher, evs);
     512             :         ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
     513             :     }
     514             : #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH
     515             : 
     516           9 :     return CHIP_NO_ERROR;
     517             : }
     518             : 
     519           3 : CHIP_ERROR LayerImplSelect::ClearCallbackOnPendingRead(SocketWatchToken token)
     520             : {
     521           3 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
     522           3 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     523             : 
     524           3 :     watch->mPendingIO.Clear(SocketEventFlags::kRead);
     525             : 
     526             : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     527             :     if (ev_is_active(&watch->mIoWatcher) && watch->mPendingIO.Raw() == 0)
     528             :     {
     529             :         // all flags cleared now, stop watching
     530             :         ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
     531             :     }
     532             : #endif
     533             : 
     534           3 :     return CHIP_NO_ERROR;
     535             : }
     536             : 
     537           3 : CHIP_ERROR LayerImplSelect::ClearCallbackOnPendingWrite(SocketWatchToken token)
     538             : {
     539           3 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
     540           3 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     541             : 
     542           3 :     watch->mPendingIO.Clear(SocketEventFlags::kWrite);
     543             : 
     544             : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     545             :     if (ev_is_active(&watch->mIoWatcher) && watch->mPendingIO.Raw() == 0)
     546             :     {
     547             :         // all flags cleared now, stop watching
     548             :         ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
     549             :     }
     550             : #endif
     551             : 
     552           3 :     return CHIP_NO_ERROR;
     553             : }
     554             : 
     555         171 : CHIP_ERROR LayerImplSelect::StopWatchingSocket(SocketWatchToken * tokenInOut)
     556             : {
     557         171 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(*tokenInOut);
     558         171 :     *tokenInOut         = InvalidSocketWatchToken();
     559             : 
     560         171 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     561         171 :     VerifyOrReturnError(watch->mFD >= 0, CHIP_ERROR_INCORRECT_STATE);
     562             : 
     563             : #if CHIP_SYSTEM_CONFIG_USE_DISPATCH || CHIP_SYSTEM_CONFIG_USE_LIBEV
     564             :     watch->DisableAndClear();
     565             : #else
     566         171 :     watch->Clear();
     567             : 
     568             :     // Wake the thread calling select so that it stops selecting on the socket.
     569         171 :     Signal();
     570             : #endif
     571             : 
     572         171 :     return CHIP_NO_ERROR;
     573             : }
     574             : 
     575             : /**
     576             :  *  Set the read, write or exception bit flags for the specified socket based on its status in
     577             :  *  the corresponding file descriptor sets.
     578             :  *
     579             :  *  @param[in]    socket    The file descriptor for which the bit flags are being set.
     580             :  *
     581             :  *  @param[in]    readfds   A pointer to the set of readable file descriptors.
     582             :  *
     583             :  *  @param[in]    writefds  A pointer to the set of writable file descriptors.
     584             :  *
     585             :  *  @param[in]    exceptfds  A pointer to the set of file descriptors with errors.
     586             :  */
     587     4092707 : SocketEvents LayerImplSelect::SocketEventsFromFDs(int socket, const fd_set & readfds, const fd_set & writefds,
     588             :                                                   const fd_set & exceptfds)
     589             : {
     590     4092707 :     SocketEvents res;
     591             : 
     592     4092707 :     if (socket >= 0)
     593             :     {
     594             :         // POSIX does not define the fd_set parameter of FD_ISSET() as const, even though it isn't modified.
     595     4092707 :         if (FD_ISSET(socket, const_cast<fd_set *>(&readfds)))
     596     4092545 :             res.Set(SocketEventFlags::kRead);
     597     4092707 :         if (FD_ISSET(socket, const_cast<fd_set *>(&writefds)))
     598           3 :             res.Set(SocketEventFlags::kWrite);
     599     4092707 :         if (FD_ISSET(socket, const_cast<fd_set *>(&exceptfds)))
     600           0 :             res.Set(SocketEventFlags::kExcept);
     601             :     }
     602             : 
     603     4092707 :     return res;
     604             : }
     605             : 
     606     4092525 : void LayerImplSelect::PrepareEvents()
     607             : {
     608     4092525 :     assertChipStackLockedByCurrentThread();
     609             : 
     610     4092525 :     const Clock::Timestamp currentTime = SystemClock().GetMonotonicTimestamp();
     611     4092525 :     Clock::Timestamp awakenTime        = currentTime + kDefaultMinSleepPeriod;
     612             : 
     613     4092525 :     TimerList::Node * timer = mTimerList.Earliest();
     614     4092525 :     if (timer && timer->AwakenTime() < awakenTime)
     615             :     {
     616     4092500 :         awakenTime = timer->AwakenTime();
     617             :     }
     618             : 
     619     4092525 :     const Clock::Timestamp sleepTime = (awakenTime > currentTime) ? (awakenTime - currentTime) : Clock::kZero;
     620     4092525 :     Clock::ToTimeval(sleepTime, mNextTimeout);
     621             : 
     622     4092525 :     mMaxFd = -1;
     623             : 
     624             :     // NOLINTBEGIN(clang-analyzer-security.insecureAPI.bzero)
     625             :     //
     626             :     // NOTE: darwin uses bzero to clear out FD sets. This is not a security concern.
     627    69572925 :     FD_ZERO(&mSelected.mReadSet);
     628    69572925 :     FD_ZERO(&mSelected.mWriteSet);
     629    69572925 :     FD_ZERO(&mSelected.mErrorSet);
     630             :     // NOLINTEND(clang-analyzer-security.insecureAPI.bzero)
     631             : 
     632   266014125 :     for (auto & w : mSocketWatchPool)
     633             :     {
     634   261921600 :         if (w.mFD != kInvalidFd)
     635             :         {
     636     4092704 :             if (mMaxFd < w.mFD)
     637             :             {
     638     4092704 :                 mMaxFd = w.mFD;
     639             :             }
     640     4092704 :             if (w.mPendingIO.Has(SocketEventFlags::kRead))
     641             :             {
     642     4092701 :                 FD_SET(w.mFD, &mSelected.mReadSet);
     643             :             }
     644     4092704 :             if (w.mPendingIO.Has(SocketEventFlags::kWrite))
     645             :             {
     646           3 :                 FD_SET(w.mFD, &mSelected.mWriteSet);
     647             :             }
     648             :         }
     649             :     }
     650     4092525 : }
     651             : 
     652     4092525 : void LayerImplSelect::WaitForEvents()
     653             : {
     654     4092525 :     mSelectResult = select(mMaxFd + 1, &mSelected.mReadSet, &mSelected.mWriteSet, &mSelected.mErrorSet, &mNextTimeout);
     655     4092525 : }
     656             : 
     657     4092525 : void LayerImplSelect::HandleEvents()
     658             : {
     659     4092525 :     assertChipStackLockedByCurrentThread();
     660             : 
     661     4092525 :     if (!IsSelectResultValid())
     662             :     {
     663           0 :         ChipLogError(DeviceLayer, "Select failed: %" CHIP_ERROR_FORMAT, CHIP_ERROR_POSIX(errno).Format());
     664           0 :         return;
     665             :     }
     666             : 
     667             : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     668     4092525 :     mHandleSelectThread = pthread_self();
     669             : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     670             : 
     671             :     // Obtain the list of currently expired timers. Any new timers added by timer callback are NOT handled on this pass,
     672             :     // since that could result in infinite handling of new timers blocking any other progress.
     673     4092525 :     VerifyOrDieWithMsg(mExpiredTimers.Empty(), DeviceLayer, "Re-entry into HandleEvents from a timer callback?");
     674     4092525 :     mExpiredTimers          = mTimerList.ExtractEarlier(Clock::Timeout(1) + SystemClock().GetMonotonicTimestamp());
     675     4092525 :     TimerList::Node * timer = nullptr;
     676     4103893 :     while ((timer = mExpiredTimers.PopEarliest()) != nullptr)
     677             :     {
     678       11368 :         mTimerPool.Invoke(timer);
     679             :     }
     680             : 
     681   266014125 :     for (auto & w : mSocketWatchPool)
     682             :     {
     683   261921600 :         if (w.mFD != kInvalidFd)
     684             :         {
     685     4092707 :             SocketEvents events = SocketEventsFromFDs(w.mFD, mSelected.mReadSet, mSelected.mWriteSet, mSelected.mErrorSet);
     686     4092707 :             if (events.HasAny() && w.mCallback != nullptr)
     687             :             {
     688     4092548 :                 w.mCallback(events, w.mCallbackData);
     689             :             }
     690             :         }
     691             :     }
     692             : 
     693             : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     694     4092525 :     mHandleSelectThread = PTHREAD_NULL;
     695             : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     696             : }
     697             : 
     698             : #if CHIP_SYSTEM_CONFIG_USE_DISPATCH
     699             : 
     700             : void LayerImplSelect::HandleTimerComplete(TimerList::Node * timer)
     701             : {
     702             :     mTimerList.Remove(timer);
     703             :     mTimerPool.Invoke(timer);
     704             : }
     705             : 
     706             : #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
     707             : 
     708             : void LayerImplSelect::HandleLibEvTimer(EV_P_ struct ev_timer * t, int revents)
     709             : {
     710             :     TimerList::Node * timer = static_cast<TimerList::Node *>(t->data);
     711             :     VerifyOrDie(timer != nullptr);
     712             :     LayerImplSelect * layerP = dynamic_cast<LayerImplSelect *>(timer->mCallback.mSystemLayer);
     713             :     VerifyOrDie(layerP != nullptr);
     714             :     layerP->mTimerList.Remove(timer);
     715             :     layerP->mTimerPool.Invoke(timer);
     716             : }
     717             : 
     718             : void LayerImplSelect::HandleLibEvIoWatcher(EV_P_ struct ev_io * i, int revents)
     719             : {
     720             :     SocketWatch * watch = static_cast<SocketWatch *>(i->data);
     721             :     if (watch != nullptr && watch->mCallback != nullptr && watch->mLayerImplSelectP != nullptr)
     722             :     {
     723             :         SocketEvents events;
     724             :         if (revents & EV_READ)
     725             :         {
     726             :             events.Set(SocketEventFlags::kRead);
     727             :         }
     728             :         if (revents & EV_WRITE)
     729             :         {
     730             :             events.Set(SocketEventFlags::kWrite);
     731             :         }
     732             :         if (events.HasAny())
     733             :         {
     734             :             watch->mCallback(events, watch->mCallbackData);
     735             :         }
     736             :     }
     737             : }
     738             : 
     739             : #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH/LIBEV
     740             : 
     741        5291 : void LayerImplSelect::SocketWatch::Clear()
     742             : {
     743        5291 :     mFD = kInvalidFd;
     744        5291 :     mPendingIO.ClearAll();
     745        5291 :     mCallback     = nullptr;
     746        5291 :     mCallbackData = 0;
     747             : #if CHIP_SYSTEM_CONFIG_USE_DISPATCH
     748             :     mRdSource = nullptr;
     749             :     mWrSource = nullptr;
     750             : #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
     751             :     mLayerImplSelectP = nullptr;
     752             : #endif
     753        5291 : }
     754             : 
     755             : #if CHIP_SYSTEM_CONFIG_USE_DISPATCH
     756             : void LayerImplSelect::SocketWatch::DisableAndClear()
     757             : {
     758             :     if (mRdSource)
     759             :     {
     760             :         dispatch_source_cancel(mRdSource);
     761             :         dispatch_release(mRdSource);
     762             :     }
     763             :     if (mWrSource)
     764             :     {
     765             :         dispatch_source_cancel(mWrSource);
     766             :         dispatch_release(mWrSource);
     767             :     }
     768             :     Clear();
     769             : }
     770             : #elif CHIP_SYSTEM_CONFIG_USE_LIBEV
     771             : void LayerImplSelect::SocketWatch::DisableAndClear()
     772             : {
     773             :     if (mLayerImplSelectP != nullptr && mLayerImplSelectP->mLibEvLoopP != nullptr)
     774             :     {
     775             :         ev_io_stop(mLayerImplSelectP->mLibEvLoopP, &mIoWatcher);
     776             :     }
     777             :     Clear();
     778             : }
     779             : #endif // CHIP_SYSTEM_CONFIG_USE_DISPATCH/LIBEV
     780             : 
     781             : } // namespace System
     782             : } // namespace chip

Generated by: LCOV version 1.14