Matter SDK Coverage Report
Current view: top level - include/platform/internal - GenericPlatformManagerImpl_POSIX.ipp (source / functions) Coverage Total Hit
Test: SHA:209dc18e4021e7d0dff8120ccc585909391dd862 Lines: 96.6 % 116 112
Test Date: 2026-06-16 07:34:53 Functions: 92.9 % 14 13

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020-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              :  *          Contains non-inline method definitions for the
      21              :  *          GenericPlatformManagerImpl_POSIX<> template.
      22              :  */
      23              : 
      24              : #ifndef GENERIC_PLATFORM_MANAGER_IMPL_POSIX_CPP
      25              : #define GENERIC_PLATFORM_MANAGER_IMPL_POSIX_CPP
      26              : 
      27              : #include <platform/PlatformManager.h>
      28              : #include <platform/internal/CHIPDeviceLayerInternal.h>
      29              : #include <platform/internal/GenericPlatformManagerImpl_POSIX.h>
      30              : 
      31              : // Include the non-inline definitions for the GenericPlatformManagerImpl<> template,
      32              : // from which the GenericPlatformManagerImpl_POSIX<> template inherits.
      33              : #include <platform/internal/GenericPlatformManagerImpl.ipp>
      34              : 
      35              : #include <system/SystemError.h>
      36              : #include <system/SystemLayer.h>
      37              : 
      38              : #if CHIP_HAVE_CONFIG_H
      39              : #include <crypto/CryptoBuildConfig.h>
      40              : #endif
      41              : #if CHIP_CRYPTO_PSA
      42              : #include <psa/crypto.h>
      43              : #endif
      44              : 
      45              : #include <assert.h>
      46              : #include <errno.h>
      47              : #include <fcntl.h>
      48              : #include <poll.h>
      49              : #include <sched.h>
      50              : #include <unistd.h>
      51              : 
      52              : namespace chip {
      53              : namespace DeviceLayer {
      54              : namespace Internal {
      55              : 
      56              : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
      57              : namespace {
      58          662 : System::LayerSelectLoop & SystemLayerSelectLoop()
      59              : {
      60          662 :     return static_cast<System::LayerSelectLoop &>(DeviceLayer::SystemLayer());
      61              : }
      62              : } // anonymous namespace
      63              : #endif
      64              : 
      65              : template <class ImplClass>
      66           63 : CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_InitChipStack()
      67              : {
      68              : #if CHIP_CRYPTO_PSA
      69              :     // Initialize the PSA crypto backend before the base class, which sets up
      70              :     // entropy/DRBG that already require PSA. Mirrors the Zephyr platform managers.
      71              :     VerifyOrReturnError(psa_crypto_init() == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
      72              : #endif
      73              : 
      74              :     // Call up to the base class _InitChipStack() to perform the bulk of the initialization.
      75           63 :     ReturnErrorOnFailure(GenericPlatformManagerImpl<ImplClass>::_InitChipStack());
      76              : 
      77              : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
      78              : 
      79           63 :     mShouldRunEventLoop.store(true, std::memory_order_relaxed);
      80              : 
      81           63 :     int ret = pthread_cond_init(&mEventQueueStoppedCond, nullptr);
      82           63 :     VerifyOrReturnError(ret == 0, CHIP_ERROR_POSIX(ret));
      83              : 
      84           63 :     ret = pthread_mutex_init(&mStateLock, nullptr);
      85           63 :     VerifyOrReturnError(ret == 0, CHIP_ERROR_POSIX(ret));
      86              : #endif
      87              : 
      88           63 :     return CHIP_NO_ERROR;
      89              : }
      90              : 
      91              : template <class ImplClass>
      92          180 : void GenericPlatformManagerImpl_POSIX<ImplClass>::_LockChipStack()
      93              : {
      94          180 :     int err = pthread_mutex_lock(&mChipStackLock);
      95          180 :     assert(err == 0);
      96              : 
      97              : #if CHIP_STACK_LOCK_TRACKING_ENABLED
      98          180 :     mChipStackIsLocked        = true;
      99          180 :     mChipStackLockOwnerThread = pthread_self();
     100              : #endif
     101          180 : }
     102              : 
     103              : template <class ImplClass>
     104            1 : bool GenericPlatformManagerImpl_POSIX<ImplClass>::_TryLockChipStack()
     105              : {
     106            1 :     bool locked = (pthread_mutex_trylock(&mChipStackLock) == 0);
     107              : #if CHIP_STACK_LOCK_TRACKING_ENABLED
     108            1 :     if (locked)
     109              :     {
     110            1 :         mChipStackIsLocked        = true;
     111            1 :         mChipStackLockOwnerThread = pthread_self();
     112              :     }
     113              : #endif
     114            1 :     return locked;
     115              : }
     116              : 
     117              : template <class ImplClass>
     118          181 : void GenericPlatformManagerImpl_POSIX<ImplClass>::_UnlockChipStack()
     119              : {
     120              : #if CHIP_STACK_LOCK_TRACKING_ENABLED
     121          181 :     if (!mChipStackIsLocked)
     122              :     {
     123            0 :         ChipLogError(DeviceLayer, "_UnlockChipStack while unlocked");
     124              : #if CHIP_STACK_LOCK_TRACKING_ERROR_FATAL
     125            0 :         chipDie();
     126              : #endif
     127              :     }
     128          181 :     mChipStackIsLocked        = false;
     129          181 :     mChipStackLockOwnerThread = pthread_t();
     130              : #endif
     131              : 
     132          181 :     int err = pthread_mutex_unlock(&mChipStackLock);
     133          181 :     assert(err == 0);
     134          181 : }
     135              : 
     136              : #if CHIP_STACK_LOCK_TRACKING_ENABLED
     137              : template <class ImplClass>
     138    167567249 : bool GenericPlatformManagerImpl_POSIX<ImplClass>::_IsChipStackLockedByCurrentThread() const
     139              : {
     140              :     // If no Matter thread is currently running we do not have to worry about
     141              :     // locking. Hence, this function always returns true in that case.
     142    167567249 :     if (mState.load(std::memory_order_relaxed) == State::kStopped)
     143    167566904 :         return true;
     144          345 :     return mChipStackIsLocked && (pthread_equal(pthread_self(), mChipStackLockOwnerThread));
     145              : }
     146              : #endif
     147              : 
     148              : template <class ImplClass>
     149            0 : CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_StartChipTimer(System::Clock::Timeout delay)
     150              : {
     151              :     // Let System::LayerSelectLoop.PrepareEvents() handle timers.
     152            0 :     return CHIP_NO_ERROR;
     153              : }
     154              : 
     155              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     156              : template <class ImplClass>
     157              : void GenericPlatformManagerImpl_POSIX<ImplClass>::_DispatchEventViaScheduleWork(System::Layer * aLayer, void * appState)
     158              : {
     159              :     auto * event = static_cast<const ChipDeviceEvent *>(appState);
     160              :     PlatformMgrImpl().DispatchEvent(event);
     161              :     delete event;
     162              : }
     163              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     164              : 
     165              : template <class ImplClass>
     166          211 : CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_PostEvent(const ChipDeviceEvent * event)
     167              : {
     168              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     169              :     // Note: PostEvent() is documented to allow being called "from any thread".
     170              :     //   In the libev mainloop case however, calling from another thread is NOT supported.
     171              :     //   Introducing this restriction is OK because the very goal of using libev is to avoid
     172              :     //   multiple threads by running matter and all application code in the same thread on the
     173              :     //   libev mainloop. So getting called from another thread here is very likely a
     174              :     //   application design error.
     175              :     VerifyOrDieWithMsg(_IsChipStackLockedByCurrentThread(), DeviceLayer, "PostEvent() not allowed from outside chip stack lock");
     176              : 
     177              :     // Schedule dispatching this event via System Layer's ScheduleWork
     178              :     ChipDeviceEvent * eventCopyP = new ChipDeviceEvent;
     179              :     VerifyOrDie(eventCopyP != nullptr);
     180              :     *eventCopyP = *event;
     181              :     SystemLayer().ScheduleWork(&_DispatchEventViaScheduleWork, eventCopyP);
     182              :     return CHIP_NO_ERROR;
     183              : #else
     184          211 :     mChipEventQueue.Push(*event);
     185              : 
     186          211 :     SystemLayerSelectLoop().Signal(); // Trigger wake select on CHIP thread
     187          211 :     return CHIP_NO_ERROR;
     188              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     189              : }
     190              : 
     191              : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
     192              : 
     193              : template <class ImplClass>
     194           94 : void GenericPlatformManagerImpl_POSIX<ImplClass>::ProcessDeviceEvents()
     195              : {
     196          243 :     while (!mChipEventQueue.Empty())
     197              :     {
     198          149 :         const ChipDeviceEvent event = mChipEventQueue.PopFront();
     199          149 :         Impl()->DispatchEvent(&event);
     200              :     }
     201           94 : }
     202              : 
     203              : template <class ImplClass>
     204           83 : void GenericPlatformManagerImpl_POSIX<ImplClass>::_RunEventLoop()
     205              : {
     206              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     207              : 
     208              :     VerifyOrDieWithMsg(false, DeviceLayer, "libev based app should never try to run a separate event loop");
     209              : 
     210              : #else
     211              : 
     212           83 :     pthread_mutex_lock(&mStateLock);
     213              : 
     214              :     //
     215              :     // If we haven't set mInternallyManagedChipTask by now, it means that the application did not call
     216              :     // StartEventLoopTask and consequently, are running the event loop from their own, externally managed
     217              :     // task.
     218              :     //
     219           83 :     if (!mInternallyManagedChipTask)
     220              :     {
     221           77 :         mChipTask = pthread_self();
     222           77 :         mState.store(State::kRunning, std::memory_order_relaxed);
     223           77 :         mShouldRunEventLoop.store(true, std::memory_order_relaxed);
     224              :     }
     225              : 
     226           83 :     pthread_mutex_unlock(&mStateLock);
     227              : 
     228           83 :     Impl()->LockChipStack();
     229              : 
     230           83 :     SystemLayerSelectLoop().EventLoopBegins();
     231              :     do
     232              :     {
     233           94 :         SystemLayerSelectLoop().PrepareEvents();
     234              : 
     235           94 :         Impl()->UnlockChipStack();
     236           94 :         SystemLayerSelectLoop().WaitForEvents();
     237           94 :         Impl()->LockChipStack();
     238              : 
     239           94 :         SystemLayerSelectLoop().HandleEvents();
     240              : 
     241           94 :         ProcessDeviceEvents();
     242           94 :     } while (mShouldRunEventLoop.load(std::memory_order_relaxed));
     243           83 :     SystemLayerSelectLoop().EventLoopEnds();
     244              : 
     245           83 :     Impl()->UnlockChipStack();
     246              : 
     247           83 :     pthread_mutex_lock(&mStateLock);
     248           83 :     mState.store(State::kStopping, std::memory_order_relaxed);
     249           83 :     pthread_mutex_unlock(&mStateLock);
     250              : 
     251              :     //
     252              :     // Wake up anyone blocked waiting for the event queue to stop in
     253              :     // StopEventLoopTask().
     254              :     //
     255           83 :     pthread_cond_signal(&mEventQueueStoppedCond);
     256              : 
     257              :     //
     258              :     // Mark event loop as truly stopped. After that line, we can not use any
     259              :     // non-simple type member variables, because they can be destroyed by the
     260              :     // Shutdown() method.
     261              :     //
     262           83 :     mState.store(State::kStopped, std::memory_order_relaxed);
     263              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     264           83 : }
     265              : 
     266              : template <class ImplClass>
     267            3 : void * GenericPlatformManagerImpl_POSIX<ImplClass>::EventLoopTaskMain(void * arg)
     268              : {
     269            3 :     ChipLogDetail(DeviceLayer, "CHIP task running");
     270            3 :     static_cast<GenericPlatformManagerImpl_POSIX<ImplClass> *>(arg)->Impl()->RunEventLoop();
     271            3 :     return nullptr;
     272              : }
     273              : 
     274              : #endif // !CHIP_SYSTEM_CONFIG_USE_LIBEV
     275              : 
     276              : template <class ImplClass>
     277            3 : CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_StartEventLoopTask()
     278              : {
     279              : 
     280              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     281              :     // Note: With libev, we dont need our own mainloop.
     282              :     //   Still, we set State::kRunning to activate lock checking, because
     283              :     //   calls to ScheduleWork and some System Layer methods may not
     284              :     //   occur from other threads (which usually don't exist in a
     285              :     //   libev app)
     286              :     mState.store(State::kRunning, std::memory_order_relaxed);
     287              :     return CHIP_NO_ERROR;
     288              : #else
     289              : 
     290              :     int err;
     291            3 :     err = pthread_attr_init(&mChipTaskAttr);
     292            3 :     VerifyOrReturnError(err == 0, CHIP_ERROR_POSIX(err));
     293            3 :     err = pthread_attr_getschedparam(&mChipTaskAttr, &mChipTaskSchedParam);
     294            3 :     VerifyOrReturnError(err == 0, CHIP_ERROR_POSIX(err));
     295              : 
     296              : #if CHIP_DEVICE_CONFIG_RUN_AS_ROOT
     297              :     // set SCHED_RR need root/admin on Android
     298            3 :     err = pthread_attr_setschedpolicy(&mChipTaskAttr, SCHED_RR);
     299            3 :     VerifyOrReturnError(err == 0, CHIP_ERROR_POSIX(err));
     300              : #endif
     301              : 
     302            3 :     mShouldRunEventLoop.store(true, std::memory_order_relaxed);
     303              : 
     304              :     //
     305              :     // We need to grab the lock here since we have to protect setting
     306              :     // mHasValidChipTask, which will be read right away upon creating the
     307              :     // thread below.
     308              :     //
     309            3 :     pthread_mutex_lock(&mStateLock);
     310              : 
     311            3 :     err = pthread_create(&mChipTask, &mChipTaskAttr, EventLoopTaskMain, this);
     312            3 :     if (err == 0)
     313              :     {
     314            3 :         mInternallyManagedChipTask = true;
     315            3 :         mState.store(State::kRunning, std::memory_order_relaxed);
     316              :     }
     317              : 
     318            3 :     pthread_mutex_unlock(&mStateLock);
     319              : 
     320            3 :     return CHIP_ERROR_POSIX(err);
     321              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     322              : }
     323              : 
     324              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     325              : // fallback implementation
     326              : void __attribute__((weak)) ExitExternalMainLoop()
     327              : {
     328              :     // FIXME: implement better exit
     329              :     VerifyOrDieWithMsg(false, DeviceLayer, "Missing custom ExitExternalMainLoop() implementation for clean shutdown -> just die");
     330              : }
     331              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     332              : 
     333              : template <class ImplClass>
     334           83 : CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_StopEventLoopTask()
     335              : {
     336              : 
     337              : #if CHIP_SYSTEM_CONFIG_USE_LIBEV
     338              :     // with libev, the mainloop is set up and managed externally
     339              :     mState.store(State::kStopping, std::memory_order_relaxed);
     340              :     ExitExternalMainLoop(); // this callback needs to be implemented.
     341              :     mState.store(State::kStopped, std::memory_order_relaxed);
     342              :     return CHIP_NO_ERROR;
     343              : #else
     344              : 
     345           83 :     int err = 0;
     346              : 
     347              :     //
     348              :     // Signal to the runloop to stop.
     349              :     //
     350           83 :     mShouldRunEventLoop.store(false, std::memory_order_relaxed);
     351              : 
     352           83 :     pthread_mutex_lock(&mStateLock);
     353              : 
     354              :     //
     355              :     // If we're calling this from a different thread than the one running chip, then
     356              :     // we need to wait till the event queue has completely stopped before proceeding.
     357              :     //
     358           83 :     auto isRunning = mState.load(std::memory_order_relaxed) == State::kRunning;
     359           83 :     if (isRunning && (pthread_equal(pthread_self(), mChipTask) == 0))
     360              :     {
     361            3 :         pthread_mutex_unlock(&mStateLock);
     362              : 
     363              :         //
     364              :         // We need to grab the lock to protect critical sections accessed by the WakeSelect() call within
     365              :         // System::Layer.
     366              :         //
     367            3 :         Impl()->LockChipStack();
     368            3 :         SystemLayerSelectLoop().Signal();
     369            3 :         Impl()->UnlockChipStack();
     370              : 
     371            3 :         pthread_mutex_lock(&mStateLock);
     372              : 
     373            6 :         while (mState.load(std::memory_order_relaxed) == State::kRunning)
     374              :         {
     375            3 :             err = pthread_cond_wait(&mEventQueueStoppedCond, &mStateLock);
     376            3 :             VerifyOrExit(err == 0, );
     377              :         }
     378              : 
     379            3 :         pthread_mutex_unlock(&mStateLock);
     380              : 
     381              :         //
     382              :         // Wait further for the thread to terminate if we had previously created it.
     383              :         //
     384            3 :         if (mInternallyManagedChipTask)
     385              :         {
     386            3 :             err = pthread_join(mChipTask, nullptr);
     387            3 :             VerifyOrExit(err == 0, );
     388              :         }
     389              :     }
     390              :     else
     391              :     {
     392           80 :         pthread_mutex_unlock(&mStateLock);
     393              :     }
     394              : 
     395           83 : exit:
     396           83 :     return CHIP_ERROR_POSIX(err);
     397              : #endif // CHIP_SYSTEM_CONFIG_USE_LIBEV
     398              : }
     399              : 
     400              : template <class ImplClass>
     401           63 : void GenericPlatformManagerImpl_POSIX<ImplClass>::_Shutdown()
     402              : {
     403              :     //
     404              :     // We cannot shutdown the stack while the event loop is still running. This can lead
     405              :     // to use after free errors - here we are destroying mutex and condition variable that
     406              :     // are still in use by the event loop!
     407              :     //
     408           63 :     VerifyOrDie(mState.load(std::memory_order_relaxed) == State::kStopped);
     409              : 
     410              : #if !CHIP_SYSTEM_CONFIG_USE_LIBEV
     411           63 :     pthread_mutex_destroy(&mStateLock);
     412           63 :     pthread_cond_destroy(&mEventQueueStoppedCond);
     413              : #endif
     414              : 
     415              :     //
     416              :     // Call up to the base class _Shutdown() to perform the actual stack de-initialization
     417              :     // and clean-up
     418              :     //
     419           63 :     GenericPlatformManagerImpl<ImplClass>::_Shutdown();
     420           63 : }
     421              : 
     422              : // Fully instantiate the generic implementation class in whatever compilation unit includes this file.
     423              : // NB: This must come after all templated class members are defined.
     424              : template class GenericPlatformManagerImpl_POSIX<PlatformManagerImpl>;
     425              : 
     426              : } // namespace Internal
     427              : } // namespace DeviceLayer
     428              : } // namespace chip
     429              : 
     430              : #endif // GENERIC_PLATFORM_MANAGER_IMPL_POSIX_CPP
        

Generated by: LCOV version 2.0-1