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