LCOV - code coverage report
Current view: top level - lib/core - CHIPCallback.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 10 48 20.8 %
Date: 2024-02-15 08:20:41 Functions: 6 27 22.2 %

          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        4026 :     Cancelable()
      70        4026 :     {
      71        4026 :         mNext = mPrev = this;
      72        4026 :         mCancel       = nullptr;
      73        4026 :     }
      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        3960 :     Cancelable * Cancel()
      81             :     {
      82        3960 :         if (mCancel != nullptr)
      83             :         {
      84           0 :             CancelFn cancel = mCancel;
      85           0 :             mCancel         = nullptr;
      86           0 :             cancel(this);
      87             :         }
      88        3960 :         return this;
      89             :     }
      90        3960 :     ~Cancelable() { Cancel(); }
      91             : 
      92             :     Cancelable(const Cancelable &) = delete;
      93             : };
      94             : 
      95             : typedef void (*CallFn)(void *);
      96             : 
      97             : /**
      98             :  *  @class Callback
      99             :  *
     100             :  *    Base struct used for registration of items of interest, includes
     101             :  *     memory for list management and storing information about the registration's
     102             :  *     meaning.  Callback also defines cancellation.
     103             :  *    Callbacks can be registered with exactly one callee at a time. While
     104             :  *     registered (as indicated by a non-null mCancel function), all fields of
     105             :  *     the Callback save usercontext are "owned" by the callee, and should not
     106             :  *     be touched unless Cancel() has first been called.
     107             :  *    When a callee accepts a Callback for registration, step one is always Cancel(),
     108             :  *     in order to take ownership of Cancelable members next, prev, info_ptr, and info_scalar.
     109             :  *    This template class also defines a default notification function prototype.
     110             :  *
     111             :  *   One-shot semantics can be accomplished by calling Cancel() before calling mCall.
     112             :  *     Persistent registration semantics would skip that.
     113             :  *
     114             :  *   There is no provision for queueing data passed as arguments to a Callback's mCall
     115             :  *     function.  If such a thing is required, the normal pattern is to take an output
     116             :  *     parameter at Callback registration time.
     117             :  *
     118             :  */
     119             : template <class T = CallFn>
     120             : class Callback : private Cancelable
     121             : {
     122             : public:
     123             :     /**
     124             :      * pointer to owner context, normally passed to the run function
     125             :      */
     126             :     void * mContext;
     127             : 
     128             :     /**
     129             :      * where to call when the event of interest has occurred
     130             :      */
     131             :     T mCall;
     132             : 
     133             :     /**
     134             :      * Indication that the Callback is registered with a notifier
     135             :      */
     136             :     bool IsRegistered() { return (mCancel != nullptr); }
     137             : 
     138             :     /**
     139             :      * Cancel, i.e. de-register interest in the event,
     140             :      * This is the only way to get access to the Cancelable, to enqueue,
     141             :      *  store any per-registration state.
     142             :      * There are 3 primary use cases for this API:
     143             :      *   1. For the owner of the Callback, Cancel() means "where-ever this Callback
     144             :      *       was put in a list or registered for an event, gimme back, remove interest".
     145             :      *   2. To a new registrar, during a registration call, it means "hey cleanup any
     146             :      *       current registrations, let me use the internal fields of Cancelable
     147             :      *       to keep track of what the owner is interested in.
     148             :      *   3. To any current registrar (i.e. when mCancel is non-null), Cancel() means:
     149             :      *       "remove this Callback from any internal lists and free any resources
     150             :      *        you've allocated to track the interest".
     151             :      *
     152             :      *  For example: a sockets library with an API like Socket::Readable(Callback<> *cb)
     153             :      *    using an underlying persistent registration API with the OS (like epoll())
     154             :      *    might store the file descriptor and interest mask in the scalar, put the
     155             :      *    Callback in a list.  Cancel() would dequeue the callback and remove
     156             :      *    the socket from the interest set
     157             :      *
     158             :      */
     159           0 :     Cancelable * Cancel() { return Cancelable::Cancel(); }
     160             : 
     161             :     /**
     162             :      * public constructor
     163             :      */
     164        2013 :     Callback(T call, void * context) : mContext(context), mCall(call) { Cancelable(); }
     165             : 
     166             :     /**
     167             :      * TODO: type-safety? It'd be nice if Cancelables that aren't Callbacks returned null
     168             :      *    here.  https://github.com/project-chip/connectedhomeip/issues/1350
     169             :      */
     170           0 :     static Callback * FromCancelable(Cancelable * ca) { return static_cast<Callback *>(ca); }
     171             : };
     172             : 
     173             : /**
     174             :  * @brief core of a simple doubly-linked list Callback keeper-tracker-of
     175             :  *
     176             :  */
     177             : class CallbackDeque : public Cancelable
     178             : {
     179             : public:
     180             :     /**
     181             :      * @brief appends with overridden cancel function, in case the
     182             :      *   list change requires some other state update.
     183             :      */
     184           0 :     void Enqueue(Cancelable * ca, void (*cancel)(Cancelable *))
     185             :     {
     186             :         // add to a doubly-linked list, set cancel function
     187           0 :         InsertBefore(ca, this, cancel);
     188           0 :     }
     189             :     /**
     190             :      * @brief appends
     191             :      */
     192           0 :     void Enqueue(Cancelable * ca) { Enqueue(ca, Dequeue); }
     193             : 
     194             :     /**
     195             :      * @brief dequeue, but don't cancel, all cas that match the by()
     196             :      */
     197             :     void DequeueBy(bool (*by)(uint64_t, const Cancelable *), uint64_t p, Cancelable & dequeued)
     198             :     {
     199             :         for (Cancelable * ca = mNext; ca != this;)
     200             :         {
     201             :             Cancelable * next = ca->mNext;
     202             :             if (by(p, ca))
     203             :             {
     204             :                 _Dequeue(ca);
     205             :                 _InsertBefore(ca, &dequeued);
     206             :             }
     207             :             ca = next;
     208             :         }
     209             :     }
     210             : 
     211             :     /**
     212             :      * @brief insert the node in a queue in order, sorted by "sortby(a, b)"
     213             :      *   sortby(a, b) should return 1 if a > b, -1 if a < b and 0 if a == b
     214             :      */
     215             :     void InsertBy(Cancelable * ca, int (*sortby)(void *, const Cancelable *, const Cancelable *), void * p,
     216             :                   void (*cancel)(Cancelable *))
     217             :     {
     218             :         Cancelable * where; // node before which we need to insert
     219             :         for (where = mNext; where != this; where = where->mNext)
     220             :         {
     221             :             if (sortby(p, ca, where) <= 0)
     222             :             {
     223             :                 break;
     224             :             }
     225             :         }
     226             :         InsertBefore(ca, where, cancel);
     227             :     }
     228             : 
     229             :     void InsertBy(Cancelable * ca, int (*sortby)(void *, const Cancelable *, const Cancelable *), void * p)
     230             :     {
     231             :         InsertBy(ca, sortby, p, Dequeue);
     232             :     }
     233             : 
     234             :     /**
     235             :      * @brief insert the node in a the list at a specific point
     236             :      */
     237           0 :     void InsertBefore(Cancelable * ca, Cancelable * where, void (*cancel)(Cancelable *))
     238             :     {
     239           0 :         ca->Cancel(); // make doubly-sure we're not corrupting another list somewhere
     240           0 :         ca->mCancel = cancel;
     241           0 :         _InsertBefore(ca, where);
     242           0 :     }
     243             :     void InsertBefore(Cancelable * ca, Cancelable * where) { InsertBefore(ca, where, Dequeue); }
     244             : 
     245             :     /**
     246             :      * @brief returns first item unless list is empty, otherwise returns NULL
     247             :      */
     248           0 :     Cancelable * First() { return (mNext != this) ? mNext : nullptr; }
     249             : 
     250             :     /**
     251             :      * @brief Dequeue all, return in a stub. does not cancel the cas, as the list
     252             :      *   members are still in use
     253             :      */
     254           0 :     void DequeueAll(Cancelable & ready)
     255             :     {
     256           0 :         if (mNext != this)
     257             :         {
     258           0 :             ready.mNext        = mNext;
     259           0 :             ready.mPrev        = mPrev;
     260           0 :             ready.mPrev->mNext = &ready;
     261           0 :             ready.mNext->mPrev = &ready;
     262             : 
     263           0 :             mNext = mPrev = this;
     264             :         }
     265           0 :     }
     266             : 
     267             :     /**
     268             :      * @brief dequeue but don't cancel, useful if
     269             :      *     immediately putting on another list
     270             :      */
     271           0 :     static void Dequeue(Cancelable * ca)
     272             :     {
     273           0 :         _Dequeue(ca);
     274           0 :         ca->mCancel = nullptr;
     275           0 :     }
     276             : 
     277             :     /**
     278             :      * @brief empty?
     279             :      */
     280             :     bool IsEmpty() { return mNext == this; }
     281             : 
     282             : private:
     283           0 :     static void _Dequeue(Cancelable * ca)
     284             :     {
     285           0 :         ca->mNext->mPrev = ca->mPrev;
     286           0 :         ca->mPrev->mNext = ca->mNext;
     287           0 :         ca->mNext = ca->mPrev = ca;
     288           0 :     }
     289           0 :     void _InsertBefore(Cancelable * ca, Cancelable * where)
     290             :     {
     291           0 :         ca->mPrev           = where->mPrev;
     292           0 :         where->mPrev->mNext = ca;
     293           0 :         where->mPrev        = ca;
     294           0 :         ca->mNext           = where;
     295           0 :     }
     296             : };
     297             : 
     298             : } // namespace Callback
     299             : } // namespace chip

Generated by: LCOV version 1.14