Mbed OS Reference
Loading...
Searching...
No Matches
UserAllocatedEvent.h
1/*
2 * Copyright (c) 2019 ARM Limited
3 * SPDX-License-Identifier: Apache-2.0
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#ifndef USER_ALLOCATED_EVENT_H
18#define USER_ALLOCATED_EVENT_H
19
20#include "events/EventQueue.h"
21#include "platform/mbed_assert.h"
22#include "platform/mbed_atomic.h"
23
24namespace events {
25/**
26 * \addtogroup events_Event
27 * @{
28 */
29template <typename F, typename A>
30class UserAllocatedEvent;
31
32/** UserAllocatedEvent
33 *
34 * Representation of an static event for fine-grain dispatch control.
35 *
36 * UserAllocatedEvent provides mechanism for event posting and dispatching
37 * without utilization of queue internal memory. It embeds all underlying
38 * event data and doesn't require any memory allocation while posting and dispatching.
39 * All of these makes it cannot fail due to memory exhaustion while posting
40 *
41 * Usage:
42 * @code
43 * #include "mbed.h"
44 *
45 * void handler(int data) { ... }
46 *
47 * class Device {
48 * public:
49 * void handler(int data) { ... }
50 * };
51 *
52 * Device dev;
53 *
54 * // queue with not internal storage for dynamic events
55 * // accepts only user allocated events
56 * static EventQueue queue(0);
57 * // Create events
58 * static auto e1 = make_user_allocated_event(&dev, Device::handler, 2);
59 * static auto e2 = queue.make_user_allocated_event(handler, 3);
60 *
61 * int main()
62 * {
63 * e1.call_on(&queue);
64 * e2.call();
65 *
66 * queue.dispatch(1);
67 * }
68 * @endcode
69 */
70template <typename F, typename... ArgTs>
71class UserAllocatedEvent<F, void(ArgTs...)> {
72public:
73 typedef EventQueue::context<F, ArgTs...> C;
74
75 /** Create an event
76 *
77 * Constructs an event. The specified callback acts as the target
78 * for the event and is executed in the context of the
79 * event queue's dispatch loop once posted.
80 *
81 * @param f Function to execute when the event is dispatched
82 * @param args Arguments to bind to the callback
83 */
84 constexpr UserAllocatedEvent(F f, ArgTs... args) : _e(get_default_equeue_event()), _c(f, args...), _delay(), _period(-1), _equeue(), _post_ref()
85 {
86 }
87
88 /** Create an event
89 *
90 * Constructs an event. The specified callback acts as the target
91 * for the event and is executed in the context of the
92 * event queue's dispatch loop once posted.
93 *
94 * @param queue Event queue to dispatch on
95 * @param f Function to execute when the event is dispatched
96 * @param args Arguments to bind to the callback
97 */
98 constexpr UserAllocatedEvent(EventQueue *queue, F f, ArgTs... args) : _e(get_default_equeue_event()), _c(f, args...), _delay(), _period(-1), _equeue(&queue->_equeue), _post_ref()
99 {
100 }
101
102 /** Destructor for events
103 */
104#if !defined(NDEBUG)
105 // Remove the user provided destructor in release to allow constexpr optimization
106 // constexpr requires destructor to be trivial and only default one is treated as trivial
108 {
109 MBED_ASSERT(!_post_ref);
110 }
111#endif
112
113 /** Posts an event onto the underlying event queue, returning void
114 *
115 * The event is posted to the underlying queue and is executed in the
116 * context of the event queue's dispatch loop.
117 *
118 * This call cannot fail due queue memory exhaustion
119 * because it doesn't allocate any memory
120 *
121 * The post function is IRQ safe and can act as a mechanism for moving
122 * events out of IRQ contexts.
123 *
124 */
125 void call()
126 {
127 MBED_ASSERT(!_post_ref);
128 MBED_ASSERT(_equeue);
129 MBED_UNUSED bool status = post();
130 MBED_ASSERT(status);
131 }
132
133 /** Posts an event onto the event queue passed as argument, returning void
134 *
135 * The event is posted to the event queue passed as argument
136 * and is executed in the context of the event queue's dispatch loop.
137 *
138 * This call cannot fail due queue memory exhaustion
139 * because it doesn't allocate any memory
140 *
141 * The post function is IRQ safe and can act as a mechanism for moving
142 * events out of IRQ contexts.
143 *
144 * @param queue Event queue to dispatch on. Will replace earlier bound EventQueue.
145 *
146 */
147 void call_on(EventQueue *queue)
148 {
149 MBED_ASSERT(!_post_ref);
150 MBED_UNUSED bool status = post_on(queue);
151 MBED_ASSERT(status);
152 }
153
154 /** Posts an event onto the underlying event queue
155 *
156 * The event is posted to the event queue passed as argument
157 * and is executed in the context of the event queue's dispatch loop.
158 *
159 * This call cannot fail due queue memory exhaustion
160 * because it doesn't allocate any memory
161 *
162 * @return False if the event was already posted
163 * true otherwise
164 *
165 */
166 bool try_call()
167 {
168 return post();
169 }
170
171 /** Posts an event onto the event queue passed as argument,
172 *
173 * The event is posted to the underlying queue and is executed in the
174 * context of the event queue's dispatch loop.
175 *
176 * This call cannot fail due queue memory exhaustion
177 * because it doesn't allocate any memory
178 *
179 * @param queue Event queue to dispatch on. Will replace earlier bound EventQueue.
180 * @return False if the event was already posted
181 * true otherwise
182 *
183 */
185 {
186 return post_on(queue);
187 }
188
189 /** Posts an event onto the underlying event queue, returning void
190 *
191 * The event is posted to the underlying queue and is executed in the
192 * context of the event queue's dispatch loop.
193 *
194 * This call cannot fail due queue memory exhaustion
195 * because it doesn't allocate any memory
196 *
197 * The post function is IRQ safe and can act as a mechanism for moving
198 * events out of IRQ contexts.
199 *
200 */
202 {
203 return call();
204 }
205
206 /** Configure the delay of an event
207 *
208 * @param delay Millisecond delay before dispatching the event
209 */
210 void delay(int delay)
211 {
212 MBED_ASSERT(!_post_ref);
213 _delay = delay;
214 }
215
216 /** Configure the period of an event
217 *
218 * @param period Millisecond period for repeatedly dispatching an event
219 */
220 void period(int period)
221 {
222 MBED_ASSERT(!_post_ref);
223 _period = period;
224 }
225
226 /** Cancels posted event
227 *
228 * Attempts to cancel posted event. It is not safe to call
229 * cancel after an event has already been dispatched.
230 *
231 * The cancel function is IRQ safe.
232 *
233 * If called while the event queue's dispatch loop is active, the cancel
234 * function does not guarantee that the event will not execute after it
235 * returns, as the event may have already begun executing.
236 *
237 * @return true if event was successfully cancelled
238 */
239 bool cancel()
240 {
241 return _post_ref > 0 ? equeue_cancel_user_allocated(_equeue, &_e) : false;
242 }
243
244
245private:
246 friend class EventQueue;
247 struct equeue_event _e;
248 C _c;
249 int _delay;
250 int _period;
251 struct equeue *_equeue;
252 uint8_t _post_ref;
253
254 bool post()
255 {
256 if (_post_ref) {
257 return false;
258 }
259 core_util_atomic_incr_u8(&_post_ref, 1);
260 equeue_event_delay(&_e + 1, _delay);
261 equeue_event_period(&_e + 1, _period);
262 equeue_post_user_allocated(_equeue, &EventQueue::function_call<C>, &_e);
263 return true;
264 }
265
266 bool post_on(EventQueue *queue)
267 {
268 MBED_ASSERT(queue);
269 if (_post_ref) {
270 return false;
271 }
272 _equeue = &(queue->_equeue);
273 core_util_atomic_incr_u8(&_post_ref, 1);
274 equeue_event_delay(&_e + 1, _delay);
275 equeue_event_period(&_e + 1, _period);
276 equeue_post_user_allocated(_equeue, &EventQueue::function_call<C>, &_e);
277 return true;
278 }
279
280 static void event_dtor(void *p)
281 {
282 UserAllocatedEvent<F, void(ArgTs...)> *instance = (UserAllocatedEvent<F, void(ArgTs...)> *)(((equeue_event *)p) - 1);
283 core_util_atomic_decr_u8(&instance->_post_ref, 1);
284 MBED_ASSERT(!instance->_post_ref);
285 }
286
287 constexpr static equeue_event get_default_equeue_event()
288 {
289 return equeue_event{ 0, 0, 0, NULL, NULL, NULL, 0, -1, &UserAllocatedEvent::event_dtor, NULL };
290 }
291
292public:
293
294 /** Create an event
295 * @see UserAllocatedEvent::UserAllocatedEvent
296 */
297 template <typename T, typename R>
298 constexpr UserAllocatedEvent(T *obj, R(T::*method)(ArgTs...), ArgTs... args) :
299 UserAllocatedEvent(mbed::callback(obj, method), args...) { }
300
301 /** Create an event
302 * @see UserAllocatedEvent::UserAllocatedEvent
303 */
304 template <typename T, typename R>
305 constexpr UserAllocatedEvent(EventQueue *q, T *obj, R(T::*method)(ArgTs...), ArgTs... args) :
306 UserAllocatedEvent(q, mbed::callback(obj, method), args...) { }
307
308 /** Create an event
309 * @see UserAllocatedEvent::UserAllocatedEvent
310 */
311 template <typename T, typename R>
312 constexpr UserAllocatedEvent(const T *obj, R(T::*method)(ArgTs...) const, ArgTs... args) :
313 UserAllocatedEvent(mbed::callback(obj, method), args...) { }
314
315 /** Create an event
316 * @see UserAllocatedEvent::UserAllocatedEvent
317 */
318 template <typename T, typename R>
319 constexpr UserAllocatedEvent(EventQueue *q, const T *obj, R(T::*method)(ArgTs...) const, ArgTs... args) :
320 UserAllocatedEvent(q, mbed::callback(obj, method), args...) { }
321
322 /** Create an event
323 * @see UserAllocatedEvent::UserAllocatedEvent
324 */
325 template <typename T, typename R>
326 constexpr UserAllocatedEvent(volatile T *obj, R(T::*method)(ArgTs...) volatile, ArgTs... args) :
327 UserAllocatedEvent(mbed::callback(obj, method), args...) { }
328
329 /** Create an event
330 * @see UserAllocatedEvent::UserAllocatedEvent
331 */
332 template <typename T, typename R>
333 constexpr UserAllocatedEvent(EventQueue *q, volatile T *obj, R(T::*method)(ArgTs...) volatile, ArgTs... args) :
334 UserAllocatedEvent(q, mbed::callback(obj, method), args...) { }
335
336 /** Create an event
337 * @see UserAllocatedEvent::UserAllocatedEvent
338 */
339 template <typename T, typename R>
340 constexpr UserAllocatedEvent(const volatile T *obj, R(T::*method)(ArgTs...) const volatile, ArgTs... args) :
341 UserAllocatedEvent(mbed::callback(obj, method), args...) { }
342
343 /** Create an event
344 * @see UserAllocatedEvent::UserAllocatedEvent
345 */
346 template <typename T, typename R>
347 constexpr UserAllocatedEvent(EventQueue *q, const volatile T *obj, R(T::*method)(ArgTs...) const volatile, ArgTs... args) :
348 UserAllocatedEvent(q, mbed::callback(obj, method), args...) { }
349};
350
351// Convenience functions declared here to avoid cyclic
352// dependency between Event and EventQueue
353template <typename F, typename... ArgTs>
354UserAllocatedEvent<F, void(ArgTs...)> EventQueue::make_user_allocated_event(F f, ArgTs... args)
355{
356 return UserAllocatedEvent<F, void(ArgTs...)>(this, f, args...);
357}
358
359template <typename T, typename R, typename... ArgTs>
360UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> EventQueue::make_user_allocated_event(T *obj, R(T::*method)(ArgTs... args), ArgTs... args)
361{
362 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(this, mbed::callback(obj, method), args...);
363}
364
365template <typename T, typename R, typename... ArgTs>
366UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> EventQueue::make_user_allocated_event(const T *obj, R(T::*method)(ArgTs... args) const, ArgTs... args)
367{
368 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(this, mbed::callback(obj, method), args...);
369}
370
371template <typename T, typename R, typename... ArgTs>
372UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> EventQueue::make_user_allocated_event(volatile T *obj, R(T::*method)(ArgTs... args) volatile, ArgTs... args)
373{
374 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(this, mbed::callback(obj, method), args...);
375}
376
377template <typename T, typename R, typename... ArgTs>
378UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> EventQueue::make_user_allocated_event(const volatile T *obj, R(T::*method)(ArgTs... args) const volatile, ArgTs... args)
379{
380 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(this, mbed::callback(obj, method), args...);
381}
382
383
384/** Creates a UserAllocatedEvent object, deducing the target type from the types of arguments
385 *
386 * UserAllocatedEvent doesn't utilize EventQueue internal memory,
387 * therefore it can be posted on the queue without being afraid
388 * of post fail due to queue memory exhaustion
389 *
390 * @return UserAllocatedEvent object instance
391 *
392 */
393template <typename F, typename... ArgTs>
394constexpr UserAllocatedEvent<F, void(ArgTs...)> make_user_allocated_event(F f, ArgTs... args)
395{
396 return UserAllocatedEvent<F, void(ArgTs...)>(f, args...);
397}
398
399/** Creates a UserAllocatedEvent object, deducing the target type from the types of arguments
400 *
401 * UserAllocatedEvent doesn't utilize EventQueue internal memory,
402 * therefore it can be posted on the queue without being afraid
403 * of post fail due to queue memory exhaustion
404 *
405 * @return UserAllocatedEvent object instance
406 *
407 */
408template <typename T, typename R, typename... ArgTs>
409constexpr UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(T *obj, R(T::*method)(ArgTs... args), ArgTs... args)
410{
411 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(mbed::callback(obj, method), args...);
412}
413
414/** Creates a UserAllocatedEvent object, deducing the target type from the types of arguments
415 *
416 * UserAllocatedEvent doesn't utilize EventQueue internal memory,
417 * therefore it can be posted on the queue without being afraid
418 * of post fail due to queue memory exhaustion
419 *
420 * @return UserAllocatedEvent object instance
421 *
422 */
423template <typename T, typename R, typename... ArgTs>
424constexpr UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(const T *obj, R(T::*method)(ArgTs... args) const, ArgTs... args)
425{
426 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(mbed::callback(obj, method), args...);
427}
428
429/** Creates a UserAllocatedEvent object, deducing the target type from the types of arguments
430 *
431 * UserAllocatedEvent doesn't utilize EventQueue internal memory,
432 * therefore it can be posted on the queue without being afraid
433 * of post fail due to queue memory exhaustion
434 *
435 * @return UserAllocatedEvent object instance
436 *
437 */
438template <typename T, typename R, typename... ArgTs>
439constexpr UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(volatile T *obj, R(T::*method)(ArgTs... args) volatile, ArgTs... args)
440{
441 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(mbed::callback(obj, method), args...);
442}
443
444/** Creates a UserAllocatedEvent object, deducing the target type from the types of arguments
445 *
446 * UserAllocatedEvent doesn't utilize EventQueue internal memory,
447 * therefore it can be posted on the queue without being afraid
448 * of post fail due to queue memory exhaustion
449 *
450 * @return UserAllocatedEvent object instance
451 *
452 */
453template <typename T, typename R, typename... ArgTs>
454constexpr UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(const volatile T *obj, R(T::*method)(ArgTs... args) const volatile, ArgTs... args)
455{
456 return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(mbed::callback(obj, method), args...);
457}
458
459/** @}*/
460}
461#endif
EventQueue.
Definition: EventQueue.h:62
constexpr UserAllocatedEvent(EventQueue *q, const volatile T *obj, R(T::*method)(ArgTs...) const volatile, ArgTs... args)
Create an event.
constexpr UserAllocatedEvent(EventQueue *q, volatile T *obj, R(T::*method)(ArgTs...) volatile, ArgTs... args)
Create an event.
constexpr UserAllocatedEvent(const T *obj, R(T::*method)(ArgTs...) const, ArgTs... args)
Create an event.
void operator()()
Posts an event onto the underlying event queue, returning void.
void delay(int delay)
Configure the delay of an event.
constexpr UserAllocatedEvent(F f, ArgTs... args)
Create an event.
void call_on(EventQueue *queue)
Posts an event onto the event queue passed as argument, returning void.
bool try_call()
Posts an event onto the underlying event queue.
void period(int period)
Configure the period of an event.
constexpr UserAllocatedEvent(T *obj, R(T::*method)(ArgTs...), ArgTs... args)
Create an event.
constexpr UserAllocatedEvent(const volatile T *obj, R(T::*method)(ArgTs...) const volatile, ArgTs... args)
Create an event.
constexpr UserAllocatedEvent(volatile T *obj, R(T::*method)(ArgTs...) volatile, ArgTs... args)
Create an event.
bool try_call_on(EventQueue *queue)
Posts an event onto the event queue passed as argument,.
void call()
Posts an event onto the underlying event queue, returning void.
constexpr UserAllocatedEvent(EventQueue *queue, F f, ArgTs... args)
Create an event.
constexpr UserAllocatedEvent(EventQueue *q, T *obj, R(T::*method)(ArgTs...), ArgTs... args)
Create an event.
constexpr UserAllocatedEvent(EventQueue *q, const T *obj, R(T::*method)(ArgTs...) const, ArgTs... args)
Create an event.
Callback class based on template specialization.
Definition: Callback.h:53
UserAllocatedEvent< F, void(ArgTs...)> make_user_allocated_event(F f, ArgTs... args)
Creates an user allocated event bound to the event queue.
constexpr UserAllocatedEvent< F, void(ArgTs...)> make_user_allocated_event(F f, ArgTs... args)
Creates a UserAllocatedEvent object, deducing the target type from the types of arguments.
#define MBED_ASSERT(expr)
MBED_ASSERT Declare runtime assertions: results in runtime error if condition is false.
Definition: mbed_assert.h:66
Callback< R(ArgTs...)> callback(R(*func)(ArgTs...)=nullptr) noexcept
Create a callback class with type inferred from the arguments.
Definition: Callback.h:678
uint8_t core_util_atomic_decr_u8(volatile uint8_t *valuePtr, uint8_t delta)
Atomic decrement.
uint8_t core_util_atomic_incr_u8(volatile uint8_t *valuePtr, uint8_t delta)
Atomic increment.
#define MBED_UNUSED
MBED_UNUSED Declare a function argument to be unused, suppressing compiler warnings.
Definition: equeue.h:61