3 * Copyright (c) 2020 Project CHIP Authors
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * This file contains definitions for Callback objects for registering with
21 * Clusters and the Device
36 * Private members of a Callback for use by subsystems that accept
37 * Callbacks for event registration/notification.
42 typedef void (*CancelFn)(Cancelable *);
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.
57 * @brief when non-null, indicates the Callback is registered with
58 * a subsystem and that Cancelable members belong to
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
76 if (mCancel != nullptr)
78 CancelFn cancel = mCancel;
84 ~Cancelable() { Cancel(); }
86 Cancelable(const Cancelable &) = delete;
89 typedef void (*CallFn)(void *);
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.
105 * One-shot semantics can be accomplished by calling Cancel() before calling mCall.
106 * Persistent registration semantics would skip that.
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.
113 template <class T = CallFn>
114 class Callback : private Cancelable
118 * pointer to owner context, normally passed to the run function
123 * where to call when the event of interest has occured
128 * Indication that the Callback is registered with a notifier
130 bool IsRegistered() { return (mCancel != nullptr); }
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".
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
153 Cancelable * Cancel() { return Cancelable::Cancel(); }
158 Callback(T call, void * context) : mContext(context), mCall(call) { Cancelable(); }
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
164 static Callback * FromCancelable(Cancelable * ca) { return static_cast<Callback *>(ca); }
168 * @brief core of a simple doubly-linked list Callback keeper-tracker-of
171 class CallbackDeque : public Cancelable
175 * @brief appends with overridden cancel function, in case the
176 * list change requires some other state update.
178 void Enqueue(Cancelable * ca, void (*cancel)(Cancelable *))
180 // add to a doubly-linked list, set cancel function
181 InsertBefore(ca, this, cancel);
186 void Enqueue(Cancelable * ca) { Enqueue(ca, Dequeue); }
189 * @brief dequeue, but don't cancel, all cas that match the by()
191 void DequeueBy(bool (*by)(uint64_t, const Cancelable *), uint64_t p, Cancelable & dequeued)
193 for (Cancelable * ca = mNext; ca != this;)
195 Cancelable * next = ca->mNext;
199 _InsertBefore(ca, &dequeued);
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
209 void InsertBy(Cancelable * ca, int (*sortby)(void *, const Cancelable *, const Cancelable *), void * p,
210 void (*cancel)(Cancelable *))
212 Cancelable * where; // node before which we need to insert
213 for (where = mNext; where != this; where = where->mNext)
215 if (sortby(p, ca, where) <= 0)
220 InsertBefore(ca, where, cancel);
223 void InsertBy(Cancelable * ca, int (*sortby)(void *, const Cancelable *, const Cancelable *), void * p)
225 InsertBy(ca, sortby, p, Dequeue);
229 * @brief insert the node in a the list at a specific point
231 void InsertBefore(Cancelable * ca, Cancelable * where, void (*cancel)(Cancelable *))
233 ca->Cancel(); // make doubly-sure we're not corrupting another list somewhere
234 ca->mCancel = cancel;
235 _InsertBefore(ca, where);
237 void InsertBefore(Cancelable * ca, Cancelable * where) { InsertBefore(ca, where, Dequeue); }
240 * @brief returns first item unless list is empty, otherwise returns NULL
242 Cancelable * First() { return (mNext != this) ? mNext : nullptr; }
245 * @brief Dequeue all, return in a stub. does not cancel the cas, as the list
246 * members are still in use
248 void DequeueAll(Cancelable & ready)
254 ready.mPrev->mNext = &ready;
255 ready.mNext->mPrev = &ready;
257 mNext = mPrev = this;
262 * @brief dequeue but don't cancel, useful if
263 * immediately putting on another list
265 static void Dequeue(Cancelable * ca)
268 ca->mCancel = nullptr;
274 bool IsEmpty() { return mNext == this; }
277 static void _Dequeue(Cancelable * ca)
279 ca->mNext->mPrev = ca->mPrev;
280 ca->mPrev->mNext = ca->mNext;
281 ca->mNext = ca->mPrev = ca;
283 void _InsertBefore(Cancelable * ca, Cancelable * where)
285 ca->mPrev = where->mPrev;
286 where->mPrev->mNext = ca;
292 } // namespace Callback