Matter SDK Coverage Report
Current view: top level - system - SystemLayerImplSelect.cpp (source / functions) Coverage Total Hit
Test: SHA:2a48c1efeab1c0f76f3adb3a0940b0f7de706453 Lines: 96.4 % 220 212
Test Date: 2026-01-31 08:14:20 Functions: 100.0 % 26 26

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

Generated by: LCOV version 2.0-1