Matter SDK Coverage Report
Current view: top level - data-model-providers/codegen - ServerClusterInterfaceRegistry.cpp (source / functions) Coverage Total Hit
Test: SHA:1560a87972ec2c7a76cec101927a563a6862bc2a Lines: 98.9 % 88 87
Test Date: 2025-03-30 07:08:27 Functions: 100.0 % 8 8

            Line data    Source code
       1              : /*
       2              :  *    Copyright (c) 2025 Project CHIP Authors
       3              :  *    All rights reserved.
       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              : #include <data-model-providers/codegen/ServerClusterInterfaceRegistry.h>
      18              : 
      19              : #include <app/ConcreteClusterPath.h>
      20              : #include <app/server-cluster/ServerClusterInterface.h>
      21              : #include <lib/core/CHIPError.h>
      22              : #include <lib/core/DataModelTypes.h>
      23              : #include <lib/support/CHIPMem.h>
      24              : #include <lib/support/CodeUtils.h>
      25              : #include <optional>
      26              : 
      27              : namespace chip {
      28              : namespace app {
      29              : 
      30          169 : ServerClusterInterfaceRegistry::~ServerClusterInterfaceRegistry()
      31              : {
      32          373 :     while (mRegistrations != nullptr)
      33              :     {
      34          204 :         ServerClusterRegistration * next = mRegistrations->next;
      35          204 :         if (mContext.has_value())
      36              :         {
      37            2 :             mRegistrations->serverClusterInterface->Shutdown();
      38              :         }
      39          204 :         mRegistrations->next = nullptr;
      40          204 :         mRegistrations       = next;
      41              :     }
      42          169 : }
      43              : 
      44         1015 : CHIP_ERROR ServerClusterInterfaceRegistry::Register(ServerClusterRegistration & entry)
      45              : {
      46              :     // we have no strong way to check if entry is already registered somewhere else, so we use "next" as some
      47              :     // form of double-check
      48         1015 :     VerifyOrReturnError(entry.next == nullptr, CHIP_ERROR_INVALID_ARGUMENT);
      49         1014 :     VerifyOrReturnError(entry.serverClusterInterface != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
      50              : 
      51         1014 :     ConcreteClusterPath path = entry.serverClusterInterface->GetPath();
      52              : 
      53         1014 :     VerifyOrReturnError(path.HasValidIds(), CHIP_ERROR_INVALID_ARGUMENT);
      54              : 
      55              :     // Double-checking for duplicates makes the checks O(n^2) on the total number of registered
      56              :     // items. We preserve this however we may want to make this optional at some point in time.
      57         1012 :     VerifyOrReturnError(Get(path) == nullptr, CHIP_ERROR_DUPLICATE_KEY_ID);
      58              : 
      59         1011 :     if (mContext.has_value())
      60              :     {
      61            4 :         ReturnErrorOnFailure(entry.serverClusterInterface->Startup(*mContext));
      62              :     }
      63              : 
      64         1011 :     entry.next     = mRegistrations;
      65         1011 :     mRegistrations = &entry;
      66              : 
      67         1011 :     return CHIP_NO_ERROR;
      68              : }
      69              : 
      70          805 : ServerClusterInterface * ServerClusterInterfaceRegistry::Unregister(const ConcreteClusterPath & path)
      71              : {
      72          805 :     ServerClusterRegistration * prev    = nullptr;
      73          805 :     ServerClusterRegistration * current = mRegistrations;
      74              : 
      75        60062 :     while (current != nullptr)
      76              :     {
      77        59661 :         if (current->serverClusterInterface->GetPath() == path)
      78              :         {
      79              :             // take the item out of the current list and return it.
      80          404 :             ServerClusterRegistration * next = current->next;
      81              : 
      82          404 :             if (prev == nullptr)
      83              :             {
      84           12 :                 mRegistrations = next;
      85              :             }
      86              :             else
      87              :             {
      88          392 :                 prev->next = next;
      89              :             }
      90              : 
      91          404 :             if (mCachedInterface == current->serverClusterInterface)
      92              :             {
      93          401 :                 mCachedInterface = nullptr;
      94              :             }
      95              : 
      96          404 :             current->next = nullptr; // Make sure current does not look like part of a list.
      97          404 :             if (mContext.has_value())
      98              :             {
      99            3 :                 current->serverClusterInterface->Shutdown();
     100              :             }
     101              : 
     102          404 :             return current->serverClusterInterface;
     103              :         }
     104              : 
     105        59257 :         prev    = current;
     106        59257 :         current = current->next;
     107              :     }
     108              : 
     109              :     // Not found.
     110          401 :     return nullptr;
     111              : }
     112              : 
     113        16901 : ServerClusterInterfaceRegistry::ClustersList ServerClusterInterfaceRegistry::ClustersOnEndpoint(EndpointId endpointId)
     114              : {
     115        16901 :     return { mRegistrations, endpointId };
     116              : }
     117              : 
     118           22 : void ServerClusterInterfaceRegistry::UnregisterAllFromEndpoint(EndpointId endpointId)
     119              : {
     120           22 :     ServerClusterRegistration * prev    = nullptr;
     121           22 :     ServerClusterRegistration * current = mRegistrations;
     122         2172 :     while (current != nullptr)
     123              :     {
     124         2150 :         if (current->serverClusterInterface->GetPath().mEndpointId == endpointId)
     125              :         {
     126          403 :             if (mCachedInterface == current->serverClusterInterface)
     127              :             {
     128            4 :                 mCachedInterface = nullptr;
     129              :             }
     130          403 :             if (prev == nullptr)
     131              :             {
     132           35 :                 mRegistrations = current->next;
     133              :             }
     134              :             else
     135              :             {
     136          368 :                 prev->next = current->next;
     137              :             }
     138          403 :             ServerClusterRegistration * actual_next = current->next;
     139              : 
     140          403 :             current->next = nullptr; // Make sure current does not look like part of a list.
     141          403 :             if (mContext.has_value())
     142              :             {
     143            0 :                 current->serverClusterInterface->Shutdown();
     144              :             }
     145              : 
     146          403 :             current = actual_next;
     147              :         }
     148              :         else
     149              :         {
     150         1747 :             prev    = current;
     151         1747 :             current = current->next;
     152              :         }
     153              :     }
     154           22 : }
     155              : 
     156        37236 : ServerClusterInterface * ServerClusterInterfaceRegistry::Get(const ConcreteClusterPath & path)
     157              : {
     158              :     // Check the cache to speed things up
     159        37236 :     if ((mCachedInterface != nullptr) && (mCachedInterface->GetPath() == path))
     160              :     {
     161            6 :         return mCachedInterface;
     162              :     }
     163              : 
     164              :     // The cluster searched for is not cached, do a linear search for it
     165        37230 :     ServerClusterRegistration * current = mRegistrations;
     166              : 
     167      1715626 :     while (current != nullptr)
     168              :     {
     169      1679603 :         if (current->serverClusterInterface->GetPath() == path)
     170              :         {
     171         1207 :             mCachedInterface = current->serverClusterInterface;
     172         1207 :             return mCachedInterface;
     173              :         }
     174              : 
     175      1678396 :         current = current->next;
     176              :     }
     177              : 
     178              :     // not found
     179        36023 :     return nullptr;
     180              : }
     181              : 
     182          398 : CHIP_ERROR ServerClusterInterfaceRegistry::SetContext(ServerClusterContext && context)
     183              : {
     184          398 :     if (mContext.has_value())
     185              :     {
     186              :         // if there is no difference, do not re-initialize.
     187          227 :         VerifyOrReturnError(*mContext != context, CHIP_NO_ERROR);
     188            3 :         ClearContext();
     189              :     }
     190              : 
     191          174 :     mContext.emplace(std::move(context));
     192          174 :     bool had_failure = false;
     193              : 
     194          181 :     for (ServerClusterRegistration * registration = mRegistrations; registration != nullptr; registration = registration->next)
     195              :     {
     196            7 :         CHIP_ERROR err = registration->serverClusterInterface->Startup(*mContext);
     197            7 :         if (err != CHIP_NO_ERROR)
     198              :         {
     199              : #if CHIP_ERROR_LOGGING
     200            1 :             const ConcreteClusterPath path = registration->serverClusterInterface->GetPath();
     201            1 :             ChipLogError(DataManagement, "Cluster %u/" ChipLogFormatMEI " startup failed: %" CHIP_ERROR_FORMAT, path.mEndpointId,
     202              :                          ChipLogValueMEI(path.mClusterId), err.Format());
     203              : #endif
     204            1 :             had_failure = true;
     205              :             // NOTE: this makes the object be in an awkward state:
     206              :             //       - cluster is not initialized
     207              :             //       - mContext is valid
     208              :             //       As a result, ::Shutdown on this cluster WILL be called even if startup failed.
     209              :         }
     210              :     }
     211              : 
     212          174 :     if (had_failure)
     213              :     {
     214            1 :         return CHIP_ERROR_HAD_FAILURES;
     215              :     }
     216              : 
     217          173 :     return CHIP_NO_ERROR;
     218              : }
     219              : 
     220          162 : void ServerClusterInterfaceRegistry::ClearContext()
     221              : {
     222          162 :     if (!mContext.has_value())
     223              :     {
     224            4 :         return;
     225              :     }
     226          164 :     for (ServerClusterRegistration * registration = mRegistrations; registration != nullptr; registration = registration->next)
     227              :     {
     228            6 :         registration->serverClusterInterface->Shutdown();
     229              :     }
     230              : 
     231          158 :     mContext.reset();
     232              : }
     233              : 
     234              : } // namespace app
     235              : } // namespace chip
        

Generated by: LCOV version 2.0-1