Matter SDK Coverage Report
Current view: top level - system - SystemLayerImplSelect.cpp (source / functions) Coverage Total Hit
Test: SHA:5853f10e345717417494f970a7d13b422d94af51 Lines: 96.4 % 193 186
Test Date: 2025-06-30 07:09:23 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          106 : CHIP_ERROR LayerImplSelect::Init()
      56              : {
      57          106 :     VerifyOrReturnError(mLayerState.SetInitializing(), CHIP_ERROR_INCORRECT_STATE);
      58              : 
      59          106 :     RegisterPOSIXErrorFormatter();
      60              : 
      61         6890 :     for (auto & w : mSocketWatchPool)
      62              :     {
      63         6784 :         w.Clear();
      64              :     }
      65              : 
      66              : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
      67          106 :     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          106 :     ReturnErrorOnFailure(mWakeEvent.Open(*this));
      73              : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
      74              : 
      75          106 :     VerifyOrReturnError(mLayerState.SetInitialized(), CHIP_ERROR_INCORRECT_STATE);
      76          106 :     return CHIP_NO_ERROR;
      77              : }
      78              : 
      79          106 : void LayerImplSelect::Shutdown()
      80              : {
      81          106 :     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          106 :     mTimerList.Clear();
     100          106 :     mTimerPool.ReleaseAll();
     101              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     102              : 
     103              : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
     104          106 :     mWakeEvent.Close(*this);
     105              : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
     106              : 
     107          106 :     mLayerState.ResetFromShuttingDown(); // Return to uninitialized state to permit re-initialization.
     108              : }
     109              : 
     110     49533811 : 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     49533811 :     if (pthread_equal(mHandleSelectThread, pthread_self()))
     126              :     {
     127        51252 :         return;
     128              :     }
     129              : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     130              : 
     131              :     // Send notification to wake up the select call.
     132     49482559 :     CHIP_ERROR status = mWakeEvent.Notify();
     133     49482559 :     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     24900560 : CHIP_ERROR LayerImplSelect::StartTimer(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState)
     142              : {
     143     24900560 :     assertChipStackLockedByCurrentThread();
     144              : 
     145     24900560 :     VerifyOrReturnError(mLayerState.IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     146              : 
     147     24900559 :     CHIP_SYSTEM_FAULT_INJECT(FaultInjection::kFault_TimeoutImmediate, delay = System::Clock::kZero);
     148              : 
     149     24900559 :     CancelTimer(onComplete, appState);
     150              : 
     151     24900559 :     TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp() + delay, onComplete, appState);
     152     24900559 :     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     24900559 :     if (mTimerList.Add(timer) == timer)
     171              :     {
     172              :         // The new timer is the earliest, so the time until the next event has probably changed.
     173     24626025 :         Signal();
     174              :     }
     175              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     176              : 
     177     24900559 :     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              :         // Just call StartTimer; it will invoke CancelTimer(), then start a new timer.  That handles
     190              :         // all the various "timer was about to fire" edge cases correctly too.
     191           11 :         return StartTimer(delay, onComplete, appState);
     192              :     }
     193              : 
     194            3 :     return CHIP_NO_ERROR;
     195              : }
     196              : 
     197           22 : bool LayerImplSelect::IsTimerActive(TimerCompleteCallback onComplete, void * appState)
     198              : {
     199           22 :     bool timerIsActive = (mTimerList.GetRemainingTime(onComplete, appState) > Clock::kZero);
     200              : 
     201           22 :     if (!timerIsActive)
     202              :     {
     203              :         // check if the timer is in the mExpiredTimers list about to be fired.
     204            8 :         for (TimerList::Node * timer = mExpiredTimers.Earliest(); timer != nullptr; timer = timer->mNextTimer)
     205              :         {
     206            0 :             if (timer->GetCallback().GetOnComplete() == onComplete && timer->GetCallback().GetAppState() == appState)
     207              :             {
     208            0 :                 return true;
     209              :             }
     210              :         }
     211              :     }
     212              : 
     213           22 :     return timerIsActive;
     214              : }
     215              : 
     216            4 : Clock::Timeout LayerImplSelect::GetRemainingTime(TimerCompleteCallback onComplete, void * appState)
     217              : {
     218            4 :     return mTimerList.GetRemainingTime(onComplete, appState);
     219              : }
     220              : 
     221     24952490 : void LayerImplSelect::CancelTimer(TimerCompleteCallback onComplete, void * appState)
     222              : {
     223     24952490 :     assertChipStackLockedByCurrentThread();
     224              : 
     225     24952490 :     VerifyOrReturn(mLayerState.IsInitialized());
     226              : 
     227     24952490 :     TimerList::Node * timer = mTimerList.Remove(onComplete, appState);
     228     24952490 :     if (timer == nullptr)
     229              :     {
     230              :         // The timer was not in our "will fire in the future" list, but it might
     231              :         // be in the "we're about to fire these" chunk we already grabbed from
     232              :         // that list.  Check for it there too, and if found there we still want
     233              :         // to cancel it.
     234        52230 :         timer = mExpiredTimers.Remove(onComplete, appState);
     235              :     }
     236     24952490 :     VerifyOrReturn(timer != nullptr);
     237              : 
     238              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     239              :     VerifyOrDie(mLibEvLoopP != nullptr);
     240              :     ev_timer_stop(mLibEvLoopP, &timer->mLibEvTimer);
     241              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     242              : 
     243     24900277 :     mTimerPool.Release(timer);
     244              : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
     245              :     // LIBEV builds does not include an I/O wakeup thread, so must not call Signal().
     246     24900277 :     Signal();
     247              : #endif
     248              : }
     249              : 
     250        16696 : CHIP_ERROR LayerImplSelect::ScheduleWork(TimerCompleteCallback onComplete, void * appState)
     251              : {
     252        16696 :     assertChipStackLockedByCurrentThread();
     253              : 
     254        16696 :     VerifyOrReturnError(mLayerState.IsInitialized(), CHIP_ERROR_INCORRECT_STATE);
     255              : 
     256              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     257              :     // schedule as timer with no delay, but do NOT cancel previous timers with same onComplete/appState!
     258              :     TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp(), onComplete, appState);
     259              :     VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY);
     260              :     VerifyOrDie(mLibEvLoopP != nullptr);
     261              :     ev_timer_init(&timer->mLibEvTimer, &LayerImplSelect::HandleLibEvTimer, 1, 0);
     262              :     timer->mLibEvTimer.data = timer;
     263              :     auto t                  = Clock::Milliseconds64(0).count();
     264              :     ev_timer_set(&timer->mLibEvTimer, static_cast<double>(t) / 1E3, 0.);
     265              :     (void) mTimerList.Add(timer);
     266              :     ev_timer_start(mLibEvLoopP, &timer->mLibEvTimer);
     267              : #else
     268              :     // Ideally we would not use a timer here at all, but if we try to just
     269              :     // ScheduleLambda the lambda needs to capture the following:
     270              :     // 1) onComplete
     271              :     // 2) appState
     272              :     // 3) The `this` pointer, because onComplete needs to be passed a pointer to
     273              :     //    the System::Layer.
     274              :     //
     275              :     // On a 64-bit system that's 24 bytes, but lambdas passed to ScheduleLambda
     276              :     // are capped at CHIP_CONFIG_LAMBDA_EVENT_SIZE which is 16 bytes.
     277              :     //
     278              :     // So for now use a timer as a poor-man's closure that captures `this` and
     279              :     // onComplete and appState in a single pointer, so we fit inside the size
     280              :     // limit.
     281              :     //
     282              :     // TODO: We could do something here where we compile-time condition on the
     283              :     // sizes of things and use a direct ScheduleLambda if it would fit and this
     284              :     // setup otherwise.
     285              :     //
     286              :     // TODO: But also, unit tests seem to do SystemLayer::ScheduleWork without
     287              :     // actually running a useful event loop (in the PlatformManager sense),
     288              :     // which breaks if we use ScheduleLambda here, since that does rely on the
     289              :     // PlatformManager event loop. So for now, keep scheduling an expires-ASAP
     290              :     // timer, but just make sure we don't cancel existing timers with the same
     291              :     // callback and appState, so ScheduleWork invocations don't stomp on each
     292              :     // other.
     293        16696 :     TimerList::Node * timer = mTimerPool.Create(*this, SystemClock().GetMonotonicTimestamp(), onComplete, appState);
     294        16696 :     VerifyOrReturnError(timer != nullptr, CHIP_ERROR_NO_MEMORY);
     295              : 
     296        16696 :     if (mTimerList.Add(timer) == timer)
     297              :     {
     298              :         // The new timer is the earliest, so the time until the next event has probably changed.
     299         7114 :         Signal();
     300              :     }
     301              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     302              : 
     303        16696 :     return CHIP_NO_ERROR;
     304              : }
     305              : 
     306          215 : CHIP_ERROR LayerImplSelect::StartWatchingSocket(int fd, SocketWatchToken * tokenOut)
     307              : {
     308              :     // Find a free slot.
     309          215 :     SocketWatch * watch = nullptr;
     310        13975 :     for (auto & w : mSocketWatchPool)
     311              :     {
     312        13760 :         if (w.mFD == fd)
     313              :         {
     314              :             // Already registered, return the existing token
     315            0 :             *tokenOut = reinterpret_cast<SocketWatchToken>(&w);
     316            0 :             return CHIP_NO_ERROR;
     317              :         }
     318        13760 :         if ((w.mFD == kInvalidFd) && (watch == nullptr))
     319              :         {
     320          215 :             watch = &w;
     321              :         }
     322              :     }
     323          215 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_ENDPOINT_POOL_FULL);
     324              : 
     325          215 :     watch->mFD = fd;
     326              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     327              :     ev_io_init(&watch->mIoWatcher, &LayerImplSelect::HandleLibEvIoWatcher, 0, 0);
     328              :     watch->mIoWatcher.data   = watch;
     329              :     watch->mLayerImplSelectP = this;
     330              : #endif
     331              : 
     332          215 :     *tokenOut = reinterpret_cast<SocketWatchToken>(watch);
     333          215 :     return CHIP_NO_ERROR;
     334              : }
     335              : 
     336          214 : CHIP_ERROR LayerImplSelect::SetCallback(SocketWatchToken token, SocketWatchCallback callback, intptr_t data)
     337              : {
     338          214 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
     339          214 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     340              : 
     341          214 :     watch->mCallback     = callback;
     342          214 :     watch->mCallbackData = data;
     343          214 :     return CHIP_NO_ERROR;
     344              : }
     345              : 
     346          214 : CHIP_ERROR LayerImplSelect::RequestCallbackOnPendingRead(SocketWatchToken token)
     347              : {
     348          214 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
     349          214 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     350              : 
     351          214 :     watch->mPendingIO.Set(SocketEventFlags::kRead);
     352              : 
     353              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     354              :     VerifyOrDie(mLibEvLoopP != nullptr);
     355              :     int evs = (watch->mPendingIO.Has(SocketEventFlags::kRead) ? EV_READ : 0) |
     356              :         (watch->mPendingIO.Has(SocketEventFlags::kWrite) ? EV_WRITE : 0);
     357              :     if (!ev_is_active(&watch->mIoWatcher))
     358              :     {
     359              :         // First time actually using that watch
     360              :         ev_io_set(&watch->mIoWatcher, watch->mFD, evs);
     361              :         ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
     362              :     }
     363              :     else
     364              :     {
     365              :         // already active, just change flags
     366              :         // Note: changing flags only reliably works when the watcher is stopped
     367              :         ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
     368              :         ev_io_modify(&watch->mIoWatcher, evs);
     369              :         ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
     370              :     }
     371              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     372              : 
     373          214 :     return CHIP_NO_ERROR;
     374              : }
     375              : 
     376           27 : CHIP_ERROR LayerImplSelect::RequestCallbackOnPendingWrite(SocketWatchToken token)
     377              : {
     378           27 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
     379           27 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     380              : 
     381           27 :     watch->mPendingIO.Set(SocketEventFlags::kWrite);
     382              : 
     383              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     384              :     VerifyOrDie(mLibEvLoopP != nullptr);
     385              :     int evs = (watch->mPendingIO.Has(SocketEventFlags::kRead) ? EV_READ : 0) |
     386              :         (watch->mPendingIO.Has(SocketEventFlags::kWrite) ? EV_WRITE : 0);
     387              :     if (!ev_is_active(&watch->mIoWatcher))
     388              :     {
     389              :         // First time actually using that watch
     390              :         ev_io_set(&watch->mIoWatcher, watch->mFD, evs);
     391              :         ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
     392              :     }
     393              :     else
     394              :     {
     395              :         // already active, just change flags
     396              :         // Note: changing flags only reliably works when the watcher is stopped
     397              :         ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
     398              :         ev_io_modify(&watch->mIoWatcher, evs);
     399              :         ev_io_start(mLibEvLoopP, &watch->mIoWatcher);
     400              :     }
     401              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     402              : 
     403           27 :     return CHIP_NO_ERROR;
     404              : }
     405              : 
     406            9 : CHIP_ERROR LayerImplSelect::ClearCallbackOnPendingRead(SocketWatchToken token)
     407              : {
     408            9 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
     409            9 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     410              : 
     411            9 :     watch->mPendingIO.Clear(SocketEventFlags::kRead);
     412              : 
     413              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     414              :     if (ev_is_active(&watch->mIoWatcher) && watch->mPendingIO.Raw() == 0)
     415              :     {
     416              :         // all flags cleared now, stop watching
     417              :         ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
     418              :     }
     419              : #endif
     420              : 
     421            9 :     return CHIP_NO_ERROR;
     422              : }
     423              : 
     424            5 : CHIP_ERROR LayerImplSelect::ClearCallbackOnPendingWrite(SocketWatchToken token)
     425              : {
     426            5 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(token);
     427            5 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     428              : 
     429            5 :     watch->mPendingIO.Clear(SocketEventFlags::kWrite);
     430              : 
     431              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     432              :     if (ev_is_active(&watch->mIoWatcher) && watch->mPendingIO.Raw() == 0)
     433              :     {
     434              :         // all flags cleared now, stop watching
     435              :         ev_io_stop(mLibEvLoopP, &watch->mIoWatcher);
     436              :     }
     437              : #endif
     438              : 
     439            5 :     return CHIP_NO_ERROR;
     440              : }
     441              : 
     442          215 : CHIP_ERROR LayerImplSelect::StopWatchingSocket(SocketWatchToken * tokenInOut)
     443              : {
     444          215 :     SocketWatch * watch = reinterpret_cast<SocketWatch *>(*tokenInOut);
     445          215 :     *tokenInOut         = InvalidSocketWatchToken();
     446              : 
     447          215 :     VerifyOrReturnError(watch != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     448          215 :     VerifyOrReturnError(watch->mFD >= 0, CHIP_ERROR_INCORRECT_STATE);
     449              : 
     450              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     451              :     watch->DisableAndClear();
     452              : #else
     453          215 :     watch->Clear();
     454              : 
     455              :     // Wake the thread calling select so that it stops selecting on the socket.
     456          215 :     Signal();
     457              : #endif
     458              : 
     459          215 :     return CHIP_NO_ERROR;
     460              : }
     461              : 
     462              : /**
     463              :  *  Set the read, write or exception bit flags for the specified socket based on its status in
     464              :  *  the corresponding file descriptor sets.
     465              :  *
     466              :  *  @param[in]    socket    The file descriptor for which the bit flags are being set.
     467              :  *
     468              :  *  @param[in]    readfds   A pointer to the set of readable file descriptors.
     469              :  *
     470              :  *  @param[in]    writefds  A pointer to the set of writable file descriptors.
     471              :  *
     472              :  *  @param[in]    exceptfds  A pointer to the set of file descriptors with errors.
     473              :  */
     474     24853317 : SocketEvents LayerImplSelect::SocketEventsFromFDs(int socket, const fd_set & readfds, const fd_set & writefds,
     475              :                                                   const fd_set & exceptfds)
     476              : {
     477     24853317 :     SocketEvents res;
     478              : 
     479     24853317 :     if (socket >= 0)
     480              :     {
     481              :         // POSIX does not define the fd_set parameter of FD_ISSET() as const, even though it isn't modified.
     482     24853317 :         if (FD_ISSET(socket, const_cast<fd_set *>(&readfds)))
     483     24853245 :             res.Set(SocketEventFlags::kRead);
     484     24853317 :         if (FD_ISSET(socket, const_cast<fd_set *>(&writefds)))
     485           11 :             res.Set(SocketEventFlags::kWrite);
     486     24853317 :         if (FD_ISSET(socket, const_cast<fd_set *>(&exceptfds)))
     487            0 :             res.Set(SocketEventFlags::kExcept);
     488              :     }
     489              : 
     490     24853317 :     return res;
     491              : }
     492              : 
     493              : enum : intptr_t
     494              : {
     495              :     kLoopHandlerInactive = 0, // default value for EventLoopHandler::mState
     496              :     kLoopHandlerPending,
     497              :     kLoopHandlerActive,
     498              : };
     499              : 
     500            2 : void LayerImplSelect::AddLoopHandler(EventLoopHandler & handler)
     501              : {
     502              :     // Add the handler as pending because this method can be called at any point
     503              :     // in a PrepareEvents() / WaitForEvents() / HandleEvents() sequence.
     504              :     // It will be marked active when we call PrepareEvents() on it for the first time.
     505            2 :     auto & state = LoopHandlerState(handler);
     506            2 :     VerifyOrDie(state == kLoopHandlerInactive);
     507            2 :     state = kLoopHandlerPending;
     508            2 :     mLoopHandlers.PushBack(&handler);
     509            2 : }
     510              : 
     511            2 : void LayerImplSelect::RemoveLoopHandler(EventLoopHandler & handler)
     512              : {
     513            2 :     mLoopHandlers.Remove(&handler);
     514            2 :     LoopHandlerState(handler) = kLoopHandlerInactive;
     515            2 : }
     516              : 
     517     24853218 : void LayerImplSelect::PrepareEvents()
     518              : {
     519     24853218 :     assertChipStackLockedByCurrentThread();
     520              : 
     521     24853218 :     const Clock::Timestamp currentTime = SystemClock().GetMonotonicTimestamp();
     522     24853218 :     Clock::Timestamp awakenTime        = currentTime + kDefaultMinSleepPeriod;
     523              : 
     524     24853218 :     TimerList::Node * timer = mTimerList.Earliest();
     525     24853218 :     if (timer)
     526              :     {
     527     24853201 :         awakenTime = std::min(awakenTime, timer->AwakenTime());
     528              :     }
     529              : 
     530              :     // Activate added EventLoopHandlers and call PrepareEvents on active handlers.
     531     24853218 :     auto loopIter = mLoopHandlers.begin();
     532     24853222 :     while (loopIter != mLoopHandlers.end())
     533              :     {
     534            4 :         auto & loop = *loopIter++; // advance before calling out, in case a list modification clobbers the `next` pointer
     535            4 :         switch (auto & state = LoopHandlerState(loop))
     536              :         {
     537            2 :         case kLoopHandlerPending:
     538            2 :             state = kLoopHandlerActive;
     539              :             [[fallthrough]];
     540            4 :         case kLoopHandlerActive:
     541            4 :             awakenTime = std::min(awakenTime, loop.PrepareEvents(currentTime));
     542            4 :             break;
     543              :         }
     544              :     }
     545              : 
     546     24853218 :     const Clock::Timestamp sleepTime = (awakenTime > currentTime) ? (awakenTime - currentTime) : Clock::kZero;
     547     24853218 :     Clock::ToTimeval(sleepTime, mNextTimeout);
     548              : 
     549     24853218 :     mMaxFd = -1;
     550              : 
     551              :     // NOLINTBEGIN(clang-analyzer-security.insecureAPI.bzero)
     552              :     //
     553              :     // NOTE: darwin uses bzero to clear out FD sets. This is not a security concern.
     554    422504706 :     FD_ZERO(&mSelected.mReadSet);
     555    422504706 :     FD_ZERO(&mSelected.mWriteSet);
     556    422504706 :     FD_ZERO(&mSelected.mErrorSet);
     557              :     // NOLINTEND(clang-analyzer-security.insecureAPI.bzero)
     558              : 
     559   1615459170 :     for (auto & w : mSocketWatchPool)
     560              :     {
     561   1590605952 :         if (w.mFD != kInvalidFd)
     562              :         {
     563     24853318 :             if (mMaxFd < w.mFD)
     564              :             {
     565     24853318 :                 mMaxFd = w.mFD;
     566              :             }
     567     24853318 :             if (w.mPendingIO.Has(SocketEventFlags::kRead))
     568              :             {
     569     24853307 :                 FD_SET(w.mFD, &mSelected.mReadSet);
     570              :             }
     571     24853318 :             if (w.mPendingIO.Has(SocketEventFlags::kWrite))
     572              :             {
     573           11 :                 FD_SET(w.mFD, &mSelected.mWriteSet);
     574              :             }
     575              :         }
     576              :     }
     577     24853218 : }
     578              : 
     579     24853218 : void LayerImplSelect::WaitForEvents()
     580              : {
     581     24853218 :     mSelectResult = select(mMaxFd + 1, &mSelected.mReadSet, &mSelected.mWriteSet, &mSelected.mErrorSet, &mNextTimeout);
     582     24853218 : }
     583              : 
     584     24853218 : void LayerImplSelect::HandleEvents()
     585              : {
     586     24853218 :     assertChipStackLockedByCurrentThread();
     587              : 
     588     24853218 :     if (!IsSelectResultValid())
     589              :     {
     590            0 :         ChipLogError(DeviceLayer, "Select failed: %" CHIP_ERROR_FORMAT, CHIP_ERROR_POSIX(errno).Format());
     591            0 :         return;
     592              :     }
     593              : 
     594              : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     595     24853218 :     mHandleSelectThread = pthread_self();
     596              : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     597              : 
     598              :     // Obtain the list of currently expired timers. Any new timers added by timer callback are NOT handled on this pass,
     599              :     // since that could result in infinite handling of new timers blocking any other progress.
     600     24853218 :     VerifyOrDieWithMsg(mExpiredTimers.Empty(), DeviceLayer, "Re-entry into HandleEvents from a timer callback?");
     601     24853218 :     mExpiredTimers          = mTimerList.ExtractEarlier(Clock::Timeout(1) + SystemClock().GetMonotonicTimestamp());
     602     24853218 :     TimerList::Node * timer = nullptr;
     603     24870151 :     while ((timer = mExpiredTimers.PopEarliest()) != nullptr)
     604              :     {
     605        16933 :         mTimerPool.Invoke(timer);
     606              :     }
     607              : 
     608              :     // Process socket events, if any
     609     24853218 :     if (mSelectResult > 0)
     610              :     {
     611   1615458390 :         for (auto & w : mSocketWatchPool)
     612              :         {
     613   1590605184 :             if (w.mFD != kInvalidFd && w.mCallback != nullptr)
     614              :             {
     615     24853317 :                 SocketEvents events = SocketEventsFromFDs(w.mFD, mSelected.mReadSet, mSelected.mWriteSet, mSelected.mErrorSet);
     616     24853317 :                 if (events.HasAny())
     617              :                 {
     618     24853256 :                     w.mCallback(events, w.mCallbackData);
     619              :                 }
     620              :             }
     621              :         }
     622              :     }
     623              : 
     624              :     // Call HandleEvents for active loop handlers
     625     24853218 :     auto loopIter = mLoopHandlers.begin();
     626     24853222 :     while (loopIter != mLoopHandlers.end())
     627              :     {
     628            4 :         auto & loop = *loopIter++; // advance before calling out, in case a list modification clobbers the `next` pointer
     629            4 :         if (LoopHandlerState(loop) == kLoopHandlerActive)
     630              :         {
     631            3 :             loop.HandleEvents();
     632              :         }
     633              :     }
     634              : 
     635              : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     636     24853218 :     mHandleSelectThread = PTHREAD_NULL;
     637              : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     638              : }
     639              : 
     640              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     641              : 
     642              : void LayerImplSelect::HandleLibEvTimer(EV_P_ struct ev_timer * t, int revents)
     643              : {
     644              :     TimerList::Node * timer = static_cast<TimerList::Node *>(t->data);
     645              :     VerifyOrDie(timer != nullptr);
     646              :     LayerImplSelect * layerP = dynamic_cast<LayerImplSelect *>(timer->mCallback.mSystemLayer);
     647              :     VerifyOrDie(layerP != nullptr);
     648              :     layerP->mTimerList.Remove(timer);
     649              :     layerP->mTimerPool.Invoke(timer);
     650              : }
     651              : 
     652              : void LayerImplSelect::HandleLibEvIoWatcher(EV_P_ struct ev_io * i, int revents)
     653              : {
     654              :     SocketWatch * watch = static_cast<SocketWatch *>(i->data);
     655              :     if (watch != nullptr && watch->mCallback != nullptr && watch->mLayerImplSelectP != nullptr)
     656              :     {
     657              :         SocketEvents events;
     658              :         if (revents & EV_READ)
     659              :         {
     660              :             events.Set(SocketEventFlags::kRead);
     661              :         }
     662              :         if (revents & EV_WRITE)
     663              :         {
     664              :             events.Set(SocketEventFlags::kWrite);
     665              :         }
     666              :         if (events.HasAny())
     667              :         {
     668              :             watch->mCallback(events, watch->mCallbackData);
     669              :         }
     670              :     }
     671              : }
     672              : 
     673              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     674              : 
     675         6999 : void LayerImplSelect::SocketWatch::Clear()
     676              : {
     677         6999 :     mFD = kInvalidFd;
     678         6999 :     mPendingIO.ClearAll();
     679         6999 :     mCallback     = nullptr;
     680         6999 :     mCallbackData = 0;
     681              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     682              :     mLayerImplSelectP = nullptr;
     683              : #endif
     684         6999 : }
     685              : 
     686              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     687              : void LayerImplSelect::SocketWatch::DisableAndClear()
     688              : {
     689              :     if (mLayerImplSelectP != nullptr && mLayerImplSelectP->mLibEvLoopP != nullptr)
     690              :     {
     691              :         ev_io_stop(mLayerImplSelectP->mLibEvLoopP, &mIoWatcher);
     692              :     }
     693              :     Clear();
     694              : }
     695              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     696              : 
     697              : } // namespace System
     698              : } // namespace chip
        

Generated by: LCOV version 2.0-1