Matter SDK Coverage Report
Current view: top level - system - SystemLayerImplSelect.h (source / functions) Coverage Total Hit
Test: SHA:2a48c1efeab1c0f76f3adb3a0940b0f7de706453 Lines: 100.0 % 8 8
Test Date: 2026-01-31 08:14:20 Functions: 80.0 % 10 8

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021 Project CHIP Authors
       4              :  *
       5              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6              :  *    you may not use this file except in compliance with the License.
       7              :  *    You may obtain a copy of the License at
       8              :  *
       9              :  *        http://www.apache.org/licenses/LICENSE-2.0
      10              :  *
      11              :  *    Unless required by applicable law or agreed to in writing, software
      12              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14              :  *    See the License for the specific language governing permissions and
      15              :  *    limitations under the License.
      16              :  */
      17              : 
      18              : /**
      19              :  *    @file
      20              :  *      This file declares an implementation of System::Layer using select().
      21              :  */
      22              : 
      23              : #pragma once
      24              : 
      25              : #include "system/SystemConfig.h"
      26              : 
      27              : #if CHIP_SYSTEM_CONFIG_USE_POSIX_SOCKETS
      28              : #include <sys/select.h>
      29              : #endif
      30              : 
      31              : #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKETS
      32              : #include <inet/ZephyrSocket.h> // nogncheck
      33              : #endif
      34              : 
      35              : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
      36              : #include <atomic>
      37              : #include <pthread.h>
      38              : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
      39              : 
      40              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
      41              : #include <ev.h>
      42              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
      43              : 
      44              : #include <lib/support/IntrusiveList.h>
      45              : #include <lib/support/ObjectLifeCycle.h>
      46              : #include <system/SystemLayer.h>
      47              : #include <system/SystemTimer.h>
      48              : #include <system/WakeEvent.h>
      49              : 
      50              : namespace chip {
      51              : namespace System {
      52              : 
      53              : class LayerImplSelect : public LayerSelectLoop
      54              : {
      55              : public:
      56         7280 :     LayerImplSelect() = default;
      57          112 :     ~LayerImplSelect() override { VerifyOrDie(mLayerState.Destroy()); }
      58              : 
      59              :     // Layer overrides.
      60              :     CriticalFailure Init() override;
      61              :     void Shutdown() override;
      62          233 :     bool IsInitialized() const override { return mLayerState.IsInitialized(); }
      63              :     CriticalFailure StartTimer(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) override;
      64              :     CHIP_ERROR ExtendTimerTo(Clock::Timeout delay, TimerCompleteCallback onComplete, void * appState) override;
      65              :     bool IsTimerActive(TimerCompleteCallback onComplete, void * appState) override;
      66              :     Clock::Timeout GetRemainingTime(TimerCompleteCallback onComplete, void * appState) override;
      67              :     void CancelTimer(TimerCompleteCallback onComplete, void * appState) override;
      68              :     CriticalFailure ScheduleWork(TimerCompleteCallback onComplete, void * appState) override;
      69              : 
      70              : #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
      71              :     // LayerSocket overrides.
      72              :     CHIP_ERROR StartWatchingSocket(int fd, SocketWatchToken * tokenOut) override;
      73              :     CHIP_ERROR SetCallback(SocketWatchToken token, SocketWatchCallback callback, intptr_t data) override;
      74              :     CHIP_ERROR RequestCallbackOnPendingRead(SocketWatchToken token) override;
      75              :     CHIP_ERROR RequestCallbackOnPendingWrite(SocketWatchToken token) override;
      76              :     CHIP_ERROR ClearCallbackOnPendingRead(SocketWatchToken token) override;
      77              :     CHIP_ERROR ClearCallbackOnPendingWrite(SocketWatchToken token) override;
      78              :     CHIP_ERROR StopWatchingSocket(SocketWatchToken * tokenInOut) override;
      79          156 :     SocketWatchToken InvalidSocketWatchToken() override { return reinterpret_cast<SocketWatchToken>(nullptr); }
      80              : #endif
      81              : 
      82              :     // LayerSelectLoop overrides.
      83              :     void Signal() override;
      84           78 :     void EventLoopBegins() override {}
      85              :     void PrepareEvents() override;
      86              :     void WaitForEvents() override;
      87              :     void HandleEvents() override;
      88           78 :     void EventLoopEnds() override {}
      89              : 
      90              :     void AddLoopHandler(EventLoopHandler & handler) override;
      91              :     void RemoveLoopHandler(EventLoopHandler & handler) override;
      92              : 
      93              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
      94              :     virtual void SetLibEvLoop(struct ev_loop * aLibEvLoopP) override { mLibEvLoopP = aLibEvLoopP; };
      95              :     virtual struct ev_loop * GetLibEvLoop() override { return mLibEvLoopP; };
      96              :     static void HandleLibEvTimer(EV_P_ struct ev_timer * t, int revents);
      97              :     static void HandleLibEvIoWatcher(EV_P_ struct ev_io * i, int revents);
      98              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
      99              : 
     100              :     // Expose the result of WaitForEvents() for non-blocking socket implementations.
     101     23475032 :     bool IsSelectResultValid() const { return mSelectResult >= 0; }
     102              : 
     103              :     /**
     104              :      * @brief Abstract interface for an event source compatible with a select()-based event loop.
     105              :      *
     106              :      * This interface defines the contract for objects that wish to register file descriptors
     107              :      * and timeouts for monitoring. It is designed to be managed by a selection layer (e.g., LayerImplSelect).
     108              :      */
     109              :     struct EventSource : public IntrusiveListNodeBase<IntrusiveMode::Strict>
     110              :     {
     111              :         /**
     112              :          * @brief Virtual destructor to ensure proper cleanup of derived classes.
     113              :          */
     114            7 :         virtual ~EventSource() = default;
     115              : 
     116              :         /**
     117              :          * @brief Prepares the file descriptor sets and timeout before the select() call.
     118              :          *
     119              :          * This method is called by the event loop to gather all file descriptors and the
     120              :          * minimum required timeout from all registered sources.
     121              :          *
     122              :          * @param[in,out] maxfd      The highest-numbered file descriptor. Must be updated if
     123              :          *                          this source adds a descriptor larger than the current value.
     124              :          * @param[in,out] readfds   Set of file descriptors to be watched for read readiness.
     125              :          * @param[in,out] writefds  Set of file descriptors to be watched for write readiness.
     126              :          * @param[in,out] exceptfds Set of file descriptors to be watched for error conditions.
     127              :          * @param[in,out] timeout   The maximum time to wait for an event.
     128              :          *
     129              :          * @warning **Timeout Modification Logic:**
     130              :          * To ensure all sources are handled correctly, you must follow these rules:
     131              :          * - **DO NOT** modify @p timeout if this source's desired timeout is **larger** than the current value.
     132              :          * - **ONLY** modify @p timeout if this source's desired timeout is **smaller** than the current value.
     133              :          *
     134              :          * This ensures the event loop wakes up in time for the earliest pending event among all sources.
     135              :          */
     136              :         virtual void PrepareEvents(int & maxfd, fd_set & readfds, fd_set & writefds, fd_set & exceptfds,
     137              :                                    struct timeval & timeout) = 0;
     138              : 
     139              :         /**
     140              :          * @brief Processes the results after the select() call returns.
     141              :          *
     142              :          * The event loop calls this method to allow the source to check if its descriptors
     143              :          * are set in the resulting masks and perform the associated I/O or logic.
     144              :          *
     145              :          * @param[in] readfds   The set of descriptors ready for reading.
     146              :          * @param[in] writefds  The set of descriptors ready for writing.
     147              :          * @param[in] exceptfds The set of descriptors with pending error conditions.
     148              :          */
     149              :         virtual void ProcessEvents(const fd_set & readfds, const fd_set & writefds, const fd_set & exceptfds) = 0;
     150              :     };
     151              : 
     152              :     /**
     153              :      * @brief Register an EventSource with this LayerImplSelect instance.
     154              :      *
     155              :      * Adds the given EventSource to the internal list of sources that will be
     156              :      * consulted when preparing and handling events in the select()-based loop.
     157              :      *
     158              :      * Thread-safety: This method is not thread-safe and MUST be called with
     159              :      * the ChipStack lock held.
     160              :      *
     161              :      * Ownership: LayerImplSelect does not take ownership of @p source.
     162              :      * The caller is responsible for ensuring that the EventSource object
     163              :      * remains valid for as long as it is registered.
     164              :      *
     165              :      * Lifecycle: The EventSource MUST either outlive its registration (i.e.,
     166              :      * remain alive until after it is removed) or be explicitly removed using
     167              :      * EventSourceRemove() before it is destroyed.
     168              :      */
     169              :     void EventSourceAdd(EventSource * source);
     170              : 
     171              :     /**
     172              :      * @brief Unregister a previously added EventSource.
     173              :      *
     174              :      * Removes the given EventSource from the internal list of sources that are
     175              :      * monitored by the select()-based loop.
     176              :      *
     177              :      * Thread-safety: This method is not thread-safe and MUST be called with
     178              :      * the ChipStack lock held.
     179              :      *
     180              :      * Ownership: This method does not delete or otherwise destroy @p source;
     181              :      * ownership remains with the caller.
     182              :      *
     183              :      * Lifecycle: EventSourceRemove() MUST be called before destroying an
     184              :      * EventSource that has been registered with EventSourceAdd(). It is safe
     185              :      * to call EventSourceRemove() multiple times with the same pointer; calls
     186              :      * after the source has been removed have no effect.
     187              :      */
     188              :     void EventSourceRemove(EventSource * source);
     189              : 
     190              :     /**
     191              :      * @brief Clear all registered EventSource instances.
     192              :      *
     193              :      * Removes all EventSource objects from the internal list maintained by
     194              :      * LayerImplSelect.
     195              :      *
     196              :      * Thread-safety: This method is not thread-safe and MUST be called with
     197              :      * the ChipStack lock held.
     198              :      *
     199              :      * Ownership: This method does not delete or destroy any EventSource
     200              :      * instances; it only clears their registration with the loop.
     201              :      *
     202              :      * Lifecycle: After this call returns, all previously registered
     203              :      * EventSource instances are no longer tracked by the event loop. The
     204              :      * objects themselves remain the responsibility of the caller.
     205              :      */
     206              :     void EventSourceClear();
     207              : 
     208              : protected:
     209              :     IntrusiveList<EventSource> mSources;
     210              : #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
     211              :     static SocketEvents SocketEventsFromFDs(int socket, const fd_set & readfds, const fd_set & writefds, const fd_set & exceptfds);
     212              : 
     213              :     static constexpr int kSocketWatchMax = (INET_CONFIG_ENABLE_TCP_ENDPOINT ? INET_CONFIG_NUM_TCP_ENDPOINTS : 0) +
     214              :         (INET_CONFIG_ENABLE_UDP_ENDPOINT ? INET_CONFIG_NUM_UDP_ENDPOINTS : 0);
     215              : 
     216              :     struct SocketWatch
     217              :     {
     218              :         void Clear();
     219              :         int mFD;
     220              :         SocketEvents mPendingIO;
     221              :         SocketWatchCallback mCallback;
     222              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     223              :         struct ev_io mIoWatcher;
     224              :         LayerImplSelect * mLayerImplSelectP;
     225              :         void DisableAndClear();
     226              : #endif
     227              : 
     228              :         intptr_t mCallbackData;
     229              :     };
     230              :     SocketWatch mSocketWatchPool[kSocketWatchMax];
     231              : #endif
     232              : 
     233              :     TimerPool<TimerList::Node> mTimerPool;
     234              :     TimerList mTimerList;
     235              :     // List of expired timers being processed right now.  Stored in a member so
     236              :     // we can cancel them.
     237              :     TimerList mExpiredTimers;
     238              :     timeval mNextTimeout;
     239              : 
     240              :     IntrusiveList<EventLoopHandler> mLoopHandlers;
     241              : 
     242              :     // Members for select loop
     243              :     struct SelectSets
     244              :     {
     245              :         fd_set mReadSet;
     246              :         fd_set mWriteSet;
     247              :         fd_set mErrorSet;
     248              :     };
     249              :     SelectSets mSelected;
     250              :     int mMaxFd;
     251              : 
     252              :     // Return value from select(), carried between WaitForEvents() and HandleEvents().
     253              :     int mSelectResult;
     254              : 
     255              :     ObjectLifeCycle mLayerState;
     256              : 
     257              : #if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     258              :     std::atomic<pthread_t> mHandleSelectThread;
     259              : #endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
     260              : 
     261              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     262              :     struct ev_loop * mLibEvLoopP;
     263              : #else
     264              :     WakeEvent mWakeEvent;
     265              : #endif
     266              : };
     267              : 
     268              : using LayerImpl = LayerImplSelect;
     269              : 
     270              : } // namespace System
     271              : } // namespace chip
        

Generated by: LCOV version 2.0-1