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

Generated by: LCOV version 2.0-1