Matter SDK Coverage Report
Current view: top level - lib/core - CHIPCallback.h (source / functions) Coverage Total Hit
Test: SHA:6c8f029dd2432dc900f1c9245c324e69bd79e40a Lines: 98.0 % 49 48
Test Date: 2026-08-08 07:40:09 Functions: 73.7 % 38 28

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020 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 contains definitions for Callback objects for registering with
      21              :  *     Clusters and the Device
      22              :  */
      23              : 
      24              : #pragma once
      25              : 
      26              : #include <stddef.h>
      27              : #include <stdint.h>
      28              : 
      29              : #include <lib/core/CHIPConfig.h>
      30              : 
      31              : namespace chip {
      32              : 
      33              : namespace Callback {
      34              : 
      35              : /**
      36              :  *  @class Cancelable
      37              :  *
      38              :  *    Private members of a Callback for use by subsystems that accept
      39              :  *     Callbacks for event registration/notification.
      40              :  *
      41              :  */
      42              : class Cancelable
      43              : {
      44              :     typedef void (*CancelFn)(Cancelable *);
      45              : 
      46              : public:
      47              :     /**
      48              :      *  @brief for use by Callback callees, i.e. those that accept callbacks for
      49              :      *   event registration.  The names suggest how to use these members, but
      50              :      *   implementations can choose.
      51              :      */
      52              :     Cancelable * mNext;
      53              :     Cancelable * mPrev;
      54              : 
      55              :     // CHIP_CONFIG_CANCELABLE_HAS_INFO_STRING_FIELD allows consumers that were
      56              :     // using this field to opt into having it (and the resulting memory bloat)
      57              :     // while allowing everyone else to save the memory.
      58              : #if CHIP_CONFIG_CANCELABLE_HAS_INFO_STRING_FIELD
      59              :     alignas(uint64_t) char mInfo[24];
      60              : #endif // CHIP_CONFIG_CANCELABLE_HAS_INFO_STRING_FIELD
      61              : 
      62              :     /**
      63              :      * @brief when non-null, indicates the Callback is registered with
      64              :      *   a subsystem and that Cancelable members belong to
      65              :      *   that subsystem
      66              :      */
      67              :     CancelFn mCancel;
      68              : 
      69         5693 :     Cancelable()
      70         5693 :     {
      71         5693 :         mNext = mPrev = this;
      72         5693 :         mCancel       = nullptr;
      73         5693 :     }
      74              : 
      75              :     /**
      76              :      * @brief run whatever function the callee/registrar has specified in order
      77              :      *  to clean up any resource allocation associated with the registration,
      78              :      *  and surrender ownership of the Cancelable's fields
      79              :      */
      80         5759 :     Cancelable * Cancel()
      81              :     {
      82         5759 :         if (mCancel != nullptr)
      83              :         {
      84           23 :             CancelFn cancel = mCancel;
      85           23 :             mCancel         = nullptr;
      86           23 :             cancel(this);
      87              :         }
      88         5759 :         return this;
      89              :     }
      90         5693 :     ~Cancelable() { Cancel(); }
      91              : 
      92              :     Cancelable(const Cancelable &) = delete;
      93              :     // A Cancelable links itself into intrusive cancelable lists via mNext/mPrev, so it must not be
      94              :     // copy-assigned either: a shallow assignment would copy those list links and corrupt the lists
      95              :     // (and silently shallow-copy any Callback subclass). Complete the rule-of-three; copy construction
      96              :     // is already deleted above.
      97              :     Cancelable & operator=(const Cancelable &) = delete;
      98              : };
      99              : 
     100              : typedef void (*CallFn)(void *);
     101              : 
     102              : /**
     103              :  *  @class Callback
     104              :  *
     105              :  *    Base struct used for registration of items of interest, includes
     106              :  *     memory for list management and storing information about the registration's
     107              :  *     meaning.  Callback also defines cancellation.
     108              :  *    Callbacks can be registered with exactly one callee at a time. While
     109              :  *     registered (as indicated by a non-null mCancel function), all fields of
     110              :  *     the Callback save usercontext are "owned" by the callee, and should not
     111              :  *     be touched unless Cancel() has first been called.
     112              :  *    When a callee accepts a Callback for registration, step one is always Cancel(),
     113              :  *     in order to take ownership of Cancelable members next, prev, info_ptr, and info_scalar.
     114              :  *    This template class also defines a default notification function prototype.
     115              :  *
     116              :  *   One-shot semantics can be accomplished by calling Cancel() before calling mCall.
     117              :  *     Persistent registration semantics would skip that.
     118              :  *
     119              :  *   There is no provision for queueing data passed as arguments to a Callback's mCall
     120              :  *     function.  If such a thing is required, the normal pattern is to take an output
     121              :  *     parameter at Callback registration time.
     122              :  *
     123              :  */
     124              : template <class T = CallFn>
     125              : class Callback : private Cancelable
     126              : {
     127              : public:
     128              :     /**
     129              :      * pointer to owner context, normally passed to the run function
     130              :      */
     131              :     void * mContext;
     132              : 
     133              :     /**
     134              :      * where to call when the event of interest has occurred
     135              :      */
     136              :     T mCall;
     137              : 
     138              :     /**
     139              :      * Indication that the Callback is registered with a notifier
     140              :      */
     141           18 :     bool IsRegistered() { return (mCancel != nullptr); }
     142              : 
     143              :     /**
     144              :      * Cancel, i.e. de-register interest in the event,
     145              :      * This is the only way to get access to the Cancelable, to enqueue,
     146              :      *  store any per-registration state.
     147              :      * There are 3 primary use cases for this API:
     148              :      *   1. For the owner of the Callback, Cancel() means "where-ever this Callback
     149              :      *       was put in a list or registered for an event, gimme back, remove interest".
     150              :      *   2. To a new registrar, during a registration call, it means "hey cleanup any
     151              :      *       current registrations, let me use the internal fields of Cancelable
     152              :      *       to keep track of what the owner is interested in.
     153              :      *   3. To any current registrar (i.e. when mCancel is non-null), Cancel() means:
     154              :      *       "remove this Callback from any internal lists and free any resources
     155              :      *        you've allocated to track the interest".
     156              :      *
     157              :      *  For example: a sockets library with an API like Socket::Readable(Callback<> *cb)
     158              :      *    using an underlying persistent registration API with the OS (like epoll())
     159              :      *    might store the file descriptor and interest mask in the scalar, put the
     160              :      *    Callback in a list.  Cancel() would dequeue the callback and remove
     161              :      *    the socket from the interest set
     162              :      *
     163              :      */
     164           47 :     Cancelable * Cancel() { return Cancelable::Cancel(); }
     165              : 
     166              :     /**
     167              :      * public constructor
     168              :      */
     169         2837 :     Callback(T call, void * context) : mContext(context), mCall(call) { Cancelable(); }
     170              : 
     171              :     /**
     172              :      * TODO: type-safety? It'd be nice if Cancelables that aren't Callbacks returned null
     173              :      *    here.  https://github.com/project-chip/connectedhomeip/issues/1350
     174              :      */
     175           17 :     static Callback * FromCancelable(Cancelable * ca) { return static_cast<Callback *>(ca); }
     176              : };
     177              : 
     178              : /**
     179              :  * @brief core of a simple doubly-linked list Callback keeper-tracker-of
     180              :  *
     181              :  */
     182              : class CallbackDeque : public Cancelable
     183              : {
     184              : public:
     185              :     /**
     186              :      * @brief appends with overridden cancel function, in case the
     187              :      *   list change requires some other state update.
     188              :      */
     189           15 :     void Enqueue(Cancelable * ca, void (*cancel)(Cancelable *))
     190              :     {
     191              :         // add to a doubly-linked list, set cancel function
     192           15 :         InsertBefore(ca, this, cancel);
     193           15 :     }
     194              :     /**
     195              :      * @brief appends
     196              :      */
     197           12 :     void Enqueue(Cancelable * ca) { Enqueue(ca, Dequeue); }
     198              : 
     199              :     /**
     200              :      * @brief dequeue, but don't cancel, all cas that match the by()
     201              :      */
     202              :     void DequeueBy(bool (*by)(uint64_t, const Cancelable *), uint64_t p, Cancelable & dequeued)
     203              :     {
     204              :         for (Cancelable * ca = mNext; ca != this;)
     205              :         {
     206              :             Cancelable * next = ca->mNext;
     207              :             if (by(p, ca))
     208              :             {
     209              :                 _Dequeue(ca);
     210              :                 _InsertBefore(ca, &dequeued);
     211              :             }
     212              :             ca = next;
     213              :         }
     214              :     }
     215              : 
     216              :     /**
     217              :      * @brief insert the node in a queue in order, sorted by "sortby(a, b)"
     218              :      *   sortby(a, b) should return 1 if a > b, -1 if a < b and 0 if a == b
     219              :      */
     220              :     void InsertBy(Cancelable * ca, int (*sortby)(void *, const Cancelable *, const Cancelable *), void * p,
     221              :                   void (*cancel)(Cancelable *))
     222              :     {
     223              :         Cancelable * where; // node before which we need to insert
     224              :         for (where = mNext; where != this; where = where->mNext)
     225              :         {
     226              :             if (sortby(p, ca, where) <= 0)
     227              :             {
     228              :                 break;
     229              :             }
     230              :         }
     231              :         InsertBefore(ca, where, cancel);
     232              :     }
     233              : 
     234              :     void InsertBy(Cancelable * ca, int (*sortby)(void *, const Cancelable *, const Cancelable *), void * p)
     235              :     {
     236              :         InsertBy(ca, sortby, p, Dequeue);
     237              :     }
     238              : 
     239              :     /**
     240              :      * @brief insert the node in a the list at a specific point
     241              :      */
     242           15 :     void InsertBefore(Cancelable * ca, Cancelable * where, void (*cancel)(Cancelable *))
     243              :     {
     244           15 :         ca->Cancel(); // make doubly-sure we're not corrupting another list somewhere
     245           15 :         ca->mCancel = cancel;
     246           15 :         _InsertBefore(ca, where);
     247           15 :     }
     248              :     void InsertBefore(Cancelable * ca, Cancelable * where) { InsertBefore(ca, where, Dequeue); }
     249              : 
     250              :     /**
     251              :      * @brief returns first item unless list is empty, otherwise returns NULL
     252              :      */
     253            0 :     Cancelable * First() { return (mNext != this) ? mNext : nullptr; }
     254              : 
     255              :     /**
     256              :      * @brief Dequeue all, return in a stub. does not cancel the cas, as the list
     257              :      *   members are still in use
     258              :      */
     259           10 :     void DequeueAll(Cancelable & ready)
     260              :     {
     261           10 :         if (mNext != this)
     262              :         {
     263            7 :             ready.mNext        = mNext;
     264            7 :             ready.mPrev        = mPrev;
     265            7 :             ready.mPrev->mNext = &ready;
     266            7 :             ready.mNext->mPrev = &ready;
     267              : 
     268            7 :             mNext = mPrev = this;
     269              :         }
     270           10 :     }
     271              : 
     272              :     /**
     273              :      * @brief dequeue but don't cancel, useful if
     274              :      *     immediately putting on another list
     275              :      */
     276           15 :     static void Dequeue(Cancelable * ca)
     277              :     {
     278           15 :         _Dequeue(ca);
     279           15 :         ca->mCancel = nullptr;
     280           15 :     }
     281              : 
     282              :     /**
     283              :      * @brief empty?
     284              :      */
     285              :     bool IsEmpty() { return mNext == this; }
     286              : 
     287              : private:
     288           15 :     static void _Dequeue(Cancelable * ca)
     289              :     {
     290           15 :         ca->mNext->mPrev = ca->mPrev;
     291           15 :         ca->mPrev->mNext = ca->mNext;
     292           15 :         ca->mNext = ca->mPrev = ca;
     293           15 :     }
     294           15 :     void _InsertBefore(Cancelable * ca, Cancelable * where)
     295              :     {
     296           15 :         ca->mPrev           = where->mPrev;
     297           15 :         where->mPrev->mNext = ca;
     298           15 :         where->mPrev        = ca;
     299           15 :         ca->mNext           = where;
     300           15 :     }
     301              : };
     302              : 
     303              : } // namespace Callback
     304              : } // namespace chip
        

Generated by: LCOV version 2.0-1