Matter SDK Coverage Report
Current view: top level - system - SystemLayerImplSelect.cpp (source / functions) Coverage Total Hit
Test: SHA:855bd8ef7df315d5b55d9ae34fbcec00a14e08ec Lines: 96.4 % 195 188
Test Date: 2025-05-31 07:10:49 Functions: 100.0 % 23 23

            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 <algorithm>
      32              : #include <errno.h>
      33              : 
      34              : // Choose an approximation of PTHREAD_NULL if pthread.h doesn't define one.
      35              : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING && !defined(PTHREAD_NULL)
      36              : #define PTHREAD_NULL 0
      37              : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING && !defined(PTHREAD_NULL)
      38              : 
      39              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
      40              : // older libev do not yet have ev_io_modify
      41              : #ifndef ev_io_modify
      42              : #define ev_io_modify(ev, events_)                                                                                                  \
      43              :     do                                                                                                                             \
      44              :     {                                                                                                                              \
      45              :         (ev)->events = ((ev)->events & EV__IOFDSET) | (events_);                                                                   \
      46              :     } while (0)
      47              : #endif // ev_io_modify
      48              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
      49              : 
      50              : namespace chip {
      51              : namespace System {
      52              : 
      53              : constexpr Clock::Seconds64 kDefaultMinSleepPeriod = Clock::Seconds64(60 * 60 * 24 * 30); // Month [sec]
      54              : 
      55          104 : CHIP_ERROR LayerImplSelect::Init()
      56              : {
      57          104 :     VerifyOrReturnError(mLayerState.SetInitializing(), CHIP_ERROR_INCORRECT_STATE);
      58              : 
      59          104 :     RegisterPOSIXErrorFormatter();
      60              : 
      61         6760 :     for (auto & w : mSocketWatchPool)
      62              :     {
      63         6656 :         w.Clear();
      64              :     }
      65              : 
      66              : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
      67          104 :     mHandleSelectThread = PTHREAD_NULL;
      68              : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
      69              : 
      70              : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
      71              :     // Create an event to allow an arbitrary thread to wake the thread in the select loop.
      72          104 :     ReturnErrorOnFailure(mWakeEvent.Open(*this));
      73              : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
      74              : 
      75          104 :     VerifyOrReturnError(mLayerState.SetInitialized(), CHIP_ERROR_INCORRECT_STATE);
      76          104 :     return CHIP_NO_ERROR;
      77              : }
      78              : 
      79          104 : void LayerImplSelect::Shutdown()
      80              : {
      81          104 :     VerifyOrReturn(mLayerState.SetShuttingDown());
      82              : 
      83              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
      84              :     TimerList::Node * timer;
      85              :     while ((timer = mTimerList.PopEarliest()) != nullptr)
      86              :     {
      87              :         if (ev_is_active(&timer->mLibEvTimer))
      88              :         {
      89              :             ev_timer_stop(mLibEvLoopP, &timer->mLibEvTimer);
      90              :         }
      91              :     }
      92              :     mTimerPool.ReleaseAll();
      93              : 
      94              :     for (auto & w : mSocketWatchPool)
      95              :     {
      96              :         w.DisableAndClear();
      97              :     }
      98              : #else
      99          104 :     mTimerList.Clear();
     100          104 :     mTimerPool.ReleaseAll();
     101              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     102              : 
     103              : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
     104          104 :     mWakeEvent.Close(*this);
     105              : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
     106              : 
     107          104 :     mLayerState.ResetFromShuttingDown(); // Return to uninitialized state to permit re-initialization.
     108              : }
     109              : 
     110     43541017 : void LayerImplSelect::Signal()
     111              : {
     112              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     113              :     ChipLogError(DeviceLayer, "Signal() should not be called in CHIP_SYSTEM_CONFIG_USE_LIBEV builds (might be ok in tests)");
     114              : #else
     115              :     /*
     116              :      * Wake up the I/O thread by writing a single byte to the wake pipe.
     117              :      *
     118              :      * If this is being called from within an I/O event callback, then writing to the wake pipe can be skipped,
     119              :      * since the I/O thread is already awake.
     120              :      *
     121              :      * Furthermore, we don't care if this write fails as the only reasonably likely failure is that the pipe is full, in which
     122              :      * case the select calling thread is going to wake up anyway.
     123              :      */
     124              : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     125     43541017 :     if (pthread_equal(mHandleSelectThread, pthread_self()))
     126              :     {
     127        51176 :         return;
     128              :     }
     129              : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     130              : 
     131              :     // Send notification to wake up the select call.
     132     43489841 :     CHIP_ERROR status = mWakeEvent.Notify();
     133     43489841 :     if (status != CHIP_NO_ERROR)
     134              :     {
     135              : 
     136           11 :         ChipLogError(chipSystemLayer, "System wake event notify failed: %" CHIP_ERROR_FORMAT, status.Format());
     137              :     }
     138              : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
     139              : }
     140              : 
     141     21889379 : CHIP_ERROR LayerImplSelect::StartTimer(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState)
     142              : {
     143     21889379 :     assertChipStackLockedByCurrentThread();
     144              : 
     145     21889379 :     VerifyOrReturnError(mLayerState.IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     146              : 
     147     21889378 :     CHIP_SYSTEM_FAULT_INJECT(FaultInjection::kFault_TimeoutImmediate, delay = System::Clock::kZero);
     148              : 
     149     21889378 :     CancelTimer(onComplete, appState);
     150              : 
     151     21889378 :     TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp() + delay, onComplete, appState);
     152     21889378 :     VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY);
     153              : 
     154              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     155              :     VerifyOrDie(mLibEvLoopP != nullptr);
     156              :     ev_timer_init(&timer->mLibEvTimer, &LayerImplSelect::HandleLibEvTimer, 1, 0);
     157              :     timer->mLibEvTimer.data = timer;
     158              :     auto t                  = Clock::Milliseconds64(delay).count();
     159              :     // Note: libev uses the time when events started processing as the "now" reference for relative timers,
     160              :     //   for efficiency reasons. This point in time is represented by ev_now().
     161              :     //   The real time is represented by ev_time().
     162              :     //   Without correction, this leads to timers firing a bit too early relative to the time StartTimer()
     163              :     //   is called. So the relative value passed to ev_timer_set() is adjusted (increased) here.
     164              :     // Note: Still, slightly early (and of course, late) firing timers are something the caller MUST be prepared for,
     165              :     //   because edge cases like system clock adjustments may cause them even with the correction applied here.
     166              :     ev_timer_set(&timer->mLibEvTimer, (static_cast<double>(t) / 1E3) + ev_time() - ev_now(mLibEvLoopP), 0.);
     167              :     (void) mTimerList.Add(timer);
     168              :     ev_timer_start(mLibEvLoopP, &timer->mLibEvTimer);
     169              : #else
     170     21889378 :     if (mTimerList.Add(timer) == timer)
     171              :     {
     172              :         // The new timer is the earliest, so the time until the next event has probably changed.
     173     21644436 :         Signal();
     174              :     }
     175              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     176              : 
     177     21889378 :     return CHIP_NO_ERROR;
     178              : }
     179              : 
     180           15 : CHIP_ERROR LayerImplSelect::ExtendTimerTo(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState)
     181              : {
     182           15 :     VerifyOrReturnError(delay.count() > 0, CHIP_ERROR_INVALID_ARGUMENT);
     183              : 
     184           14 :     assertChipStackLockedByCurrentThread();
     185              : 
     186           14 :     Clock::Timeout remainingTime = mTimerList.GetRemainingTime(onComplete, appState);
     187           14 :     if (remainingTime.count() < delay.count())
     188              :     {
     189           11 :         if (remainingTime == Clock::kZero)
     190              :         {
     191              :             // If remaining time is Clock::kZero, it might possible that our timer is in
     192              :             // the mExpiredTimers list and about to be fired. Remove it from that list, since we are extending it.
     193            1 :             mExpiredTimers.Remove(onComplete, appState);
     194              :         }
     195           11 :         return StartTimer(delay, onComplete, appState);
     196              :     }
     197              : 
     198            3 :     return CHIP_NO_ERROR;
     199              : }
     200              : 
     201           22 : bool LayerImplSelect::IsTimerActive(TimerCompleteCallback onComplete, void * appState)
     202              : {
     203           22 :     bool timerIsActive = (mTimerList.GetRemainingTime(onComplete, appState) > Clock::kZero);
     204              : 
     205           22 :     if (!timerIsActive)
     206              :     {
     207              :         // check if the timer is in the mExpiredTimers list about to be fired.
     208            8 :         for (TimerList::Node * timer = mExpiredTimers.Earliest(); timer != nullptr; timer = timer->mNextTimer)
     209              :         {
     210            0 :             if (timer->GetCallback().GetOnComplete() == onComplete && timer->GetCallback().GetAppState() == appState)
     211              :             {
     212            0 :                 return true;
     213              :             }
     214              :         }
     215              :     }
     216              : 
     217           22 :     return timerIsActive;
     218              : }
     219              : 
     220            4 : Clock::Timeout LayerImplSelect::GetRemainingTime(TimerCompleteCallback onComplete, void * appState)
     221              : {
     222            4 :     return mTimerList.GetRemainingTime(onComplete, appState);
     223              : }
     224              : 
     225     21941213 : void LayerImplSelect::CancelTimer(TimerCompleteCallback onComplete, void * appState)
     226              : {
     227     21941213 :     assertChipStackLockedByCurrentThread();
     228              : 
     229     21941213 :     VerifyOrReturn(mLayerState.IsInitialized());
     230              : 
     231     21941213 :     TimerList::Node * timer = mTimerList.Remove(onComplete, appState);
     232     21941213 :     if (timer == nullptr)
     233              :     {
     234              :         // The timer was not in our "will fire in the future" list, but it might
     235              :         // be in the "we're about to fire these" chunk we already grabbed from
     236              :         // that list.  Check for it there too, and if found there we still want
     237              :         // to cancel it.
     238        52126 :         timer = mExpiredTimers.Remove(onComplete, appState);
     239              :     }
     240     21941213 :     VerifyOrReturn(timer != nullptr);
     241              : 
     242              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     243              :     VerifyOrDie(mLibEvLoopP != nullptr);
     244              :     ev_timer_stop(mLibEvLoopP, &timer->mLibEvTimer);
     245              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     246              : 
     247     21889104 :     mTimerPool.Release(timer);
     248              : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
     249              :     // LIBEV builds does not include an I/O wakeup thread, so must not call Signal().
     250     21889104 :     Signal();
     251              : #endif
     252              : }
     253              : 
     254        16667 : CHIP_ERROR LayerImplSelect::ScheduleWork(TimerCompleteCallback onComplete, void * appState)
     255              : {
     256        16667 :     assertChipStackLockedByCurrentThread();
     257              : 
     258        16667 :     VerifyOrReturnError(mLayerState.IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     259              : 
     260              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     261              :     // schedule as timer with no delay, but do NOT cancel previous timers with same onComplete/appState!
     262              :     TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp(), onComplete, appState);
     263              :     VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY);
     264              :     VerifyOrDie(mLibEvLoopP != nullptr);
     265              :     ev_timer_init(&timer->mLibEvTimer, &LayerImplSelect::HandleLibEvTimer, 1, 0);
     266              :     timer->mLibEvTimer.data = timer;
     267              :     auto t                  = Clock::Milliseconds64(0).count();
     268              :     ev_timer_set(&timer->mLibEvTimer, static_cast<double>(t) / 1E3, 0.);
     269              :     (void) mTimerList.Add(timer);
     270              :     ev_timer_start(mLibEvLoopP, &timer->mLibEvTimer);
     271              : #else
     272              :     // Ideally we would not use a timer here at all, but if we try to just
     273              :     // ScheduleLambda the lambda needs to capture the following:
     274              :     // 1) onComplete
     275              :     // 2) appState
     276              :     // 3) The `this` pointer, because onComplete needs to be passed a pointer to
     277              :     //    the System::Layer.
     278              :     //
     279              :     // On a 64-bit system that's 24 bytes, but lambdas passed to ScheduleLambda
     280              :     // are capped at CHIP_CONFIG_LAMBDA_EVENT_SIZE which is 16 bytes.
     281              :     //
     282              :     // So for now use a timer as a poor-man's closure that captures `this` and
     283              :     // onComplete and appState in a single pointer, so we fit inside the size
     284              :     // limit.
     285              :     //
     286              :     // TODO: We could do something here where we compile-time condition on the
     287              :     // sizes of things and use a direct ScheduleLambda if it would fit and this
     288              :     // setup otherwise.
     289              :     //
     290              :     // TODO: But also, unit tests seem to do SystemLayer::ScheduleWork without
     291              :     // actually running a useful event loop (in the PlatformManager sense),
     292              :     // which breaks if we use ScheduleLambda here, since that does rely on the
     293              :     // PlatformManager event loop. So for now, keep scheduling an expires-ASAP
     294              :     // timer, but just make sure we don't cancel existing timers with the same
     295              :     // callback and appState, so ScheduleWork invocations don't stomp on each
     296              :     // other.
     297        16667 :     TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp(), onComplete, appState);
     298        16667 :     VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY);
     299              : 
     300        16667 :     if (mTimerList.Add(timer) == timer)
     301              :     {
     302              :         // The new timer is the earliest, so the time until the next event has probably changed.
     303         7093 :         Signal();
     304              :     }
     305              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     306              : 
     307        16667 :     return CHIP_NO_ERROR;
     308              : }
     309              : 
     310          213 : CHIP_ERROR LayerImplSelect::StartWatchingSocket(int fd, SocketWatchToken * tokenOut)
     311              : {
     312              :     // Find a free slot.
     313          213 :     SocketWatch * watch = nullptr;
     314        13845 :     for (auto & w : mSocketWatchPool)
     315              :     {
     316        13632 :         if (w.mFD == fd)
     317              :         {
     318              :             // Already registered, return the existing token
     319            0 :             *tokenOut = reinterpret_cast<SocketWatchToken>(&w);
     320            0 :             return CHIP_NO_ERROR;
     321              :         }
     322        13632 :         if ((w.mFD == kInvalidFd) && (watch == nullptr))
     323              :         {
     324          213 :             watch = &w;
     325              :         }
     326              :     }
     327          213 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_ENDPOINT_POOL_FULL);
     328              : 
     329          213 :     watch->mFD = fd;
     330              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     331              :     ev_io_init(&watch->mIoWatcher, &LayerImplSelect::HandleLibEvIoWatcher, 0, 0);
     332              :     watch->mIoWatcher.data   = watch;
     333              :     watch->mLayerImplSelectP = this;
     334              : #endif
     335              : 
     336          213 :     *tokenOut = reinterpret_cast<SocketWatchToken>(watch);
     337          213 :     return CHIP_NO_ERROR;
     338              : }
     339              : 
     340          212 : CHIP_ERROR LayerImplSelect::SetCallback(SocketWatchToken token, SocketWatchCallback callback, intptr_t data)
     341              : {
     342          212 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
     343          212 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     344              : 
     345          212 :     watch->mCallback     = callback;
     346          212 :     watch->mCallbackData = data;
     347          212 :     return CHIP_NO_ERROR;
     348              : }
     349              : 
     350          212 : CHIP_ERROR LayerImplSelect::RequestCallbackOnPendingRead(SocketWatchToken token)
     351              : {
     352          212 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
     353          212 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     354              : 
     355          212 :     watch->mPendingIO.Set(SocketEventFlags::kRead);
     356              : 
     357              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     358              :     VerifyOrDie(mLibEvLoopP != nullptr);
     359              :     int evs = (watch->mPendingIO.Has(SocketEventFlags::kRead) ? EV_READ : 0) |
     360              :         (watch->mPendingIO.Has(SocketEventFlags::kWrite) ? EV_WRITE : 0);
     361              :     if (!ev_is_active(&watch->mIoWatcher))
     362              :     {
     363              :         // First time actually using that watch
     364              :         ev_io_set(&watch->mIoWatcher, watch->mFD, evs);
     365              :         ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
     366              :     }
     367              :     else
     368              :     {
     369              :         // already active, just change flags
     370              :         // Note: changing flags only reliably works when the watcher is stopped
     371              :         ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
     372              :         ev_io_modify(&watch->mIoWatcher, evs);
     373              :         ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
     374              :     }
     375              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     376              : 
     377          212 :     return CHIP_NO_ERROR;
     378              : }
     379              : 
     380           27 : CHIP_ERROR LayerImplSelect::RequestCallbackOnPendingWrite(SocketWatchToken token)
     381              : {
     382           27 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
     383           27 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     384              : 
     385           27 :     watch->mPendingIO.Set(SocketEventFlags::kWrite);
     386              : 
     387              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     388              :     VerifyOrDie(mLibEvLoopP != nullptr);
     389              :     int evs = (watch->mPendingIO.Has(SocketEventFlags::kRead) ? EV_READ : 0) |
     390              :         (watch->mPendingIO.Has(SocketEventFlags::kWrite) ? EV_WRITE : 0);
     391              :     if (!ev_is_active(&watch->mIoWatcher))
     392              :     {
     393              :         // First time actually using that watch
     394              :         ev_io_set(&watch->mIoWatcher, watch->mFD, evs);
     395              :         ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
     396              :     }
     397              :     else
     398              :     {
     399              :         // already active, just change flags
     400              :         // Note: changing flags only reliably works when the watcher is stopped
     401              :         ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
     402              :         ev_io_modify(&watch->mIoWatcher, evs);
     403              :         ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
     404              :     }
     405              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     406              : 
     407           27 :     return CHIP_NO_ERROR;
     408              : }
     409              : 
     410            9 : CHIP_ERROR LayerImplSelect::ClearCallbackOnPendingRead(SocketWatchToken token)
     411              : {
     412            9 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
     413            9 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     414              : 
     415            9 :     watch->mPendingIO.Clear(SocketEventFlags::kRead);
     416              : 
     417              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     418              :     if (ev_is_active(&watch->mIoWatcher) && watch->mPendingIO.Raw() == 0)
     419              :     {
     420              :         // all flags cleared now, stop watching
     421              :         ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
     422              :     }
     423              : #endif
     424              : 
     425            9 :     return CHIP_NO_ERROR;
     426              : }
     427              : 
     428            5 : CHIP_ERROR LayerImplSelect::ClearCallbackOnPendingWrite(SocketWatchToken token)
     429              : {
     430            5 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
     431            5 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     432              : 
     433            5 :     watch->mPendingIO.Clear(SocketEventFlags::kWrite);
     434              : 
     435              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     436              :     if (ev_is_active(&watch->mIoWatcher) && watch->mPendingIO.Raw() == 0)
     437              :     {
     438              :         // all flags cleared now, stop watching
     439              :         ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
     440              :     }
     441              : #endif
     442              : 
     443            5 :     return CHIP_NO_ERROR;
     444              : }
     445              : 
     446          213 : CHIP_ERROR LayerImplSelect::StopWatchingSocket(SocketWatchToken * tokenInOut)
     447              : {
     448          213 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(*tokenInOut);
     449          213 :     *tokenInOut         = InvalidSocketWatchToken();
     450              : 
     451          213 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     452          213 :     VerifyOrReturnError(watch->mFD >= 0, CHIP_ERROR_INCORRECT_STATE);
     453              : 
     454              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     455              :     watch->DisableAndClear();
     456              : #else
     457          213 :     watch->Clear();
     458              : 
     459              :     // Wake the thread calling select so that it stops selecting on the socket.
     460          213 :     Signal();
     461              : #endif
     462              : 
     463          213 :     return CHIP_NO_ERROR;
     464              : }
     465              : 
     466              : /**
     467              :  *  Set the read, write or exception bit flags for the specified socket based on its status in
     468              :  *  the corresponding file descriptor sets.
     469              :  *
     470              :  *  @param[in]    socket    The file descriptor for which the bit flags are being set.
     471              :  *
     472              :  *  @param[in]    readfds   A pointer to the set of readable file descriptors.
     473              :  *
     474              :  *  @param[in]    writefds  A pointer to the set of writable file descriptors.
     475              :  *
     476              :  *  @param[in]    exceptfds  A pointer to the set of file descriptors with errors.
     477              :  */
     478     21842204 : SocketEvents LayerImplSelect::SocketEventsFromFDs(int socket, const fd_set & readfds, const fd_set & writefds,
     479              :                                                   const fd_set & exceptfds)
     480              : {
     481     21842204 :     SocketEvents res;
     482              : 
     483     21842204 :     if (socket >= 0)
     484              :     {
     485              :         // POSIX does not define the fd_set parameter of FD_ISSET() as const, even though it isn't modified.
     486     21842204 :         if (FD_ISSET(socket, const_cast<fd_set *>(&readfds)))
     487     21842132 :             res.Set(SocketEventFlags::kRead);
     488     21842204 :         if (FD_ISSET(socket, const_cast<fd_set *>(&writefds)))
     489           11 :             res.Set(SocketEventFlags::kWrite);
     490     21842204 :         if (FD_ISSET(socket, const_cast<fd_set *>(&exceptfds)))
     491            0 :             res.Set(SocketEventFlags::kExcept);
     492              :     }
     493              : 
     494     21842204 :     return res;
     495              : }
     496              : 
     497              : enum : intptr_t
     498              : {
     499              :     kLoopHandlerInactive = 0, // default value for EventLoopHandler::mState
     500              :     kLoopHandlerPending,
     501              :     kLoopHandlerActive,
     502              : };
     503              : 
     504            2 : void LayerImplSelect::AddLoopHandler(EventLoopHandler & handler)
     505              : {
     506              :     // Add the handler as pending because this method can be called at any point
     507              :     // in a PrepareEvents() / WaitForEvents() / HandleEvents() sequence.
     508              :     // It will be marked active when we call PrepareEvents() on it for the first time.
     509            2 :     auto & state = LoopHandlerState(handler);
     510            2 :     VerifyOrDie(state == kLoopHandlerInactive);
     511            2 :     state = kLoopHandlerPending;
     512            2 :     mLoopHandlers.PushBack(&handler);
     513            2 : }
     514              : 
     515            2 : void LayerImplSelect::RemoveLoopHandler(EventLoopHandler & handler)
     516              : {
     517            2 :     mLoopHandlers.Remove(&handler);
     518            2 :     LoopHandlerState(handler) = kLoopHandlerInactive;
     519            2 : }
     520              : 
     521     21842105 : void LayerImplSelect::PrepareEvents()
     522              : {
     523     21842105 :     assertChipStackLockedByCurrentThread();
     524              : 
     525     21842105 :     const Clock::Timestamp currentTime = SystemClock().GetMonotonicTimestamp();
     526     21842105 :     Clock::Timestamp awakenTime        = currentTime + kDefaultMinSleepPeriod;
     527              : 
     528     21842105 :     TimerList::Node * timer = mTimerList.Earliest();
     529     21842105 :     if (timer)
     530              :     {
     531     21842088 :         awakenTime = std::min(awakenTime, timer->AwakenTime());
     532              :     }
     533              : 
     534              :     // Activate added EventLoopHandlers and call PrepareEvents on active handlers.
     535     21842105 :     auto loopIter = mLoopHandlers.begin();
     536     21842109 :     while (loopIter != mLoopHandlers.end())
     537              :     {
     538            4 :         auto & loop = *loopIter++; // advance before calling out, in case a list modification clobbers the `next` pointer
     539            4 :         switch (auto & state = LoopHandlerState(loop))
     540              :         {
     541            2 :         case kLoopHandlerPending:
     542            2 :             state = kLoopHandlerActive;
     543              :             [[fallthrough]];
     544            4 :         case kLoopHandlerActive:
     545            4 :             awakenTime = std::min(awakenTime, loop.PrepareEvents(currentTime));
     546            4 :             break;
     547              :         }
     548              :     }
     549              : 
     550     21842105 :     const Clock::Timestamp sleepTime = (awakenTime > currentTime) ? (awakenTime - currentTime) : Clock::kZero;
     551     21842105 :     Clock::ToTimeval(sleepTime, mNextTimeout);
     552              : 
     553     21842105 :     mMaxFd = -1;
     554              : 
     555              :     // NOLINTBEGIN(clang-analyzer-security.insecureAPI.bzero)
     556              :     //
     557              :     // NOTE: darwin uses bzero to clear out FD sets. This is not a security concern.
     558    371315785 :     FD_ZERO(&mSelected.mReadSet);
     559    371315785 :     FD_ZERO(&mSelected.mWriteSet);
     560    371315785 :     FD_ZERO(&mSelected.mErrorSet);
     561              :     // NOLINTEND(clang-analyzer-security.insecureAPI.bzero)
     562              : 
     563   1419736825 :     for (auto & w : mSocketWatchPool)
     564              :     {
     565   1397894720 :         if (w.mFD != kInvalidFd)
     566              :         {
     567     21842205 :             if (mMaxFd < w.mFD)
     568              :             {
     569     21842205 :                 mMaxFd = w.mFD;
     570              :             }
     571     21842205 :             if (w.mPendingIO.Has(SocketEventFlags::kRead))
     572              :             {
     573     21842194 :                 FD_SET(w.mFD, &mSelected.mReadSet);
     574              :             }
     575     21842205 :             if (w.mPendingIO.Has(SocketEventFlags::kWrite))
     576              :             {
     577           11 :                 FD_SET(w.mFD, &mSelected.mWriteSet);
     578              :             }
     579              :         }
     580              :     }
     581     21842105 : }
     582              : 
     583     21842105 : void LayerImplSelect::WaitForEvents()
     584              : {
     585     21842105 :     mSelectResult = select(mMaxFd + 1, &mSelected.mReadSet, &mSelected.mWriteSet, &mSelected.mErrorSet, &mNextTimeout);
     586     21842105 : }
     587              : 
     588     21842105 : void LayerImplSelect::HandleEvents()
     589              : {
     590     21842105 :     assertChipStackLockedByCurrentThread();
     591              : 
     592     21842105 :     if (!IsSelectResultValid())
     593              :     {
     594            0 :         ChipLogError(DeviceLayer, "Select failed: %" CHIP_ERROR_FORMAT, CHIP_ERROR_POSIX(errno).Format());
     595            0 :         return;
     596              :     }
     597              : 
     598              : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     599     21842105 :     mHandleSelectThread = pthread_self();
     600              : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     601              : 
     602              :     // Obtain the list of currently expired timers. Any new timers added by timer callback are NOT handled on this pass,
     603              :     // since that could result in infinite handling of new timers blocking any other progress.
     604     21842105 :     VerifyOrDieWithMsg(mExpiredTimers.Empty(), DeviceLayer, "Re-entry into HandleEvents from a timer callback?");
     605     21842105 :     mExpiredTimers          = mTimerList.ExtractEarlier(Clock::Timeout(1) + SystemClock().GetMonotonicTimestamp());
     606     21842105 :     TimerList::Node * timer = nullptr;
     607     21859001 :     while ((timer = mExpiredTimers.PopEarliest()) != nullptr)
     608              :     {
     609        16896 :         mTimerPool.Invoke(timer);
     610              :     }
     611              : 
     612              :     // Process socket events, if any
     613     21842105 :     if (mSelectResult > 0)
     614              :     {
     615   1419736045 :         for (auto & w : mSocketWatchPool)
     616              :         {
     617   1397893952 :             if (w.mFD != kInvalidFd && w.mCallback != nullptr)
     618              :             {
     619     21842204 :                 SocketEvents events = SocketEventsFromFDs(w.mFD, mSelected.mReadSet, mSelected.mWriteSet, mSelected.mErrorSet);
     620     21842204 :                 if (events.HasAny())
     621              :                 {
     622     21842143 :                     w.mCallback(events, w.mCallbackData);
     623              :                 }
     624              :             }
     625              :         }
     626              :     }
     627              : 
     628              :     // Call HandleEvents for active loop handlers
     629     21842105 :     auto loopIter = mLoopHandlers.begin();
     630     21842109 :     while (loopIter != mLoopHandlers.end())
     631              :     {
     632            4 :         auto & loop = *loopIter++; // advance before calling out, in case a list modification clobbers the `next` pointer
     633            4 :         if (LoopHandlerState(loop) == kLoopHandlerActive)
     634              :         {
     635            3 :             loop.HandleEvents();
     636              :         }
     637              :     }
     638              : 
     639              : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     640     21842105 :     mHandleSelectThread = PTHREAD_NULL;
     641              : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     642              : }
     643              : 
     644              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     645              : 
     646              : void LayerImplSelect::HandleLibEvTimer(EV_P_ struct ev_timer * t, int revents)
     647              : {
     648              :     TimerList::Node * timer = static_cast<TimerList::Node *>(t->data);
     649              :     VerifyOrDie(timer != nullptr);
     650              :     LayerImplSelect * layerP = dynamic_cast<LayerImplSelect *>(timer->mCallback.mSystemLayer);
     651              :     VerifyOrDie(layerP != nullptr);
     652              :     layerP->mTimerList.Remove(timer);
     653              :     layerP->mTimerPool.Invoke(timer);
     654              : }
     655              : 
     656              : void LayerImplSelect::HandleLibEvIoWatcher(EV_P_ struct ev_io * i, int revents)
     657              : {
     658              :     SocketWatch * watch = static_cast<SocketWatch *>(i->data);
     659              :     if (watch != nullptr && watch->mCallback != nullptr && watch->mLayerImplSelectP != nullptr)
     660              :     {
     661              :         SocketEvents events;
     662              :         if (revents & EV_READ)
     663              :         {
     664              :             events.Set(SocketEventFlags::kRead);
     665              :         }
     666              :         if (revents & EV_WRITE)
     667              :         {
     668              :             events.Set(SocketEventFlags::kWrite);
     669              :         }
     670              :         if (events.HasAny())
     671              :         {
     672              :             watch->mCallback(events, watch->mCallbackData);
     673              :         }
     674              :     }
     675              : }
     676              : 
     677              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     678              : 
     679         6869 : void LayerImplSelect::SocketWatch::Clear()
     680              : {
     681         6869 :     mFD = kInvalidFd;
     682         6869 :     mPendingIO.ClearAll();
     683         6869 :     mCallback     = nullptr;
     684         6869 :     mCallbackData = 0;
     685              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     686              :     mLayerImplSelectP = nullptr;
     687              : #endif
     688         6869 : }
     689              : 
     690              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     691              : void LayerImplSelect::SocketWatch::DisableAndClear()
     692              : {
     693              :     if (mLayerImplSelectP != nullptr && mLayerImplSelectP->mLibEvLoopP != nullptr)
     694              :     {
     695              :         ev_io_stop(mLayerImplSelectP->mLibEvLoopP, &mIoWatcher);
     696              :     }
     697              :     Clear();
     698              : }
     699              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     700              : 
     701              : } // namespace System
     702              : } // namespace chip
        

Generated by: LCOV version 2.0-1