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

Generated by: LCOV version 2.0-1