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

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.