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...), _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...), _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  equeue_event_delay(&_e + 1, 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  equeue_event_period(&_e + 1, period);
229  }
230 
231  /** Cancels posted event
232  *
233  * Attempts to cancel posted event. It is 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 equeue_cancel_user_allocated(_equeue, &_e);
247  }
248 
249 
250 private:
251  friend class EventQueue;
252  struct equeue_event _e;
253  C _c;
254  struct equeue *_equeue;
255  uint8_t _post_ref;
256 
257  bool post()
258  {
259  if (_post_ref) {
260  return false;
261  }
262  core_util_atomic_incr_u8(&_post_ref, 1);
263  equeue_post_user_allocated(_equeue, &EventQueue::function_call<C>, &_e);
264  return true;
265  }
266 
267  bool post_on(EventQueue *queue)
268  {
269  if (_post_ref) {
270  return false;
271  }
272  _equeue = &(queue->_equeue);
273  core_util_atomic_incr_u8(&_post_ref, 1);
274  equeue_post_user_allocated(_equeue, &EventQueue::function_call<C>, &_e);
275  return true;
276  }
277 
278  static void event_dtor(void *p)
279  {
280  UserAllocatedEvent<F, void(ArgTs...)> *instance = (UserAllocatedEvent<F, void(ArgTs...)> *)(((equeue_event *)p) - 1);
281  core_util_atomic_decr_u8(&instance->_post_ref, 1);
282  MBED_ASSERT(!instance->_post_ref);
283  }
284 
285  constexpr static equeue_event get_default_equeue_event()
286  {
287  return equeue_event{ 0, 0, 0, NULL, NULL, NULL, 0, -1, &UserAllocatedEvent::event_dtor, NULL };
288  }
289 
290 public:
291 
292  /** Create an event
293  * @see UserAllocatedEvent::UserAllocatedEvent
294  */
295  template <typename T, typename R>
296  constexpr UserAllocatedEvent(T *obj, R(T::*method)(ArgTs...), ArgTs... args) :
297  UserAllocatedEvent(mbed::callback(obj, method), args...) { }
298 
299  /** Create an event
300  * @see UserAllocatedEvent::UserAllocatedEvent
301  */
302  template <typename T, typename R>
303  constexpr UserAllocatedEvent(EventQueue *q, T *obj, R(T::*method)(ArgTs...), ArgTs... args) :
304  UserAllocatedEvent(q, mbed::callback(obj, method), args...) { }
305 
306  /** Create an event
307  * @see UserAllocatedEvent::UserAllocatedEvent
308  */
309  template <typename T, typename R>
310  constexpr UserAllocatedEvent(const T *obj, R(T::*method)(ArgTs...) const, ArgTs... args) :
311  UserAllocatedEvent(mbed::callback(obj, method), args...) { }
312 
313  /** Create an event
314  * @see UserAllocatedEvent::UserAllocatedEvent
315  */
316  template <typename T, typename R>
317  constexpr UserAllocatedEvent(EventQueue *q, const T *obj, R(T::*method)(ArgTs...) const, ArgTs... args) :
318  UserAllocatedEvent(q, mbed::callback(obj, method), args...) { }
319 
320  /** Create an event
321  * @see UserAllocatedEvent::UserAllocatedEvent
322  */
323  template <typename T, typename R>
324  constexpr UserAllocatedEvent(volatile T *obj, R(T::*method)(ArgTs...) volatile, ArgTs... args) :
325  UserAllocatedEvent(mbed::callback(obj, method), args...) { }
326 
327  /** Create an event
328  * @see UserAllocatedEvent::UserAllocatedEvent
329  */
330  template <typename T, typename R>
331  constexpr UserAllocatedEvent(EventQueue *q, volatile T *obj, R(T::*method)(ArgTs...) volatile, ArgTs... args) :
332  UserAllocatedEvent(q, mbed::callback(obj, method), args...) { }
333 
334  /** Create an event
335  * @see UserAllocatedEvent::UserAllocatedEvent
336  */
337  template <typename T, typename R>
338  constexpr UserAllocatedEvent(const volatile T *obj, R(T::*method)(ArgTs...) const volatile, ArgTs... args) :
339  UserAllocatedEvent(mbed::callback(obj, method), args...) { }
340 
341  /** Create an event
342  * @see UserAllocatedEvent::UserAllocatedEvent
343  */
344  template <typename T, typename R>
345  constexpr UserAllocatedEvent(EventQueue *q, const volatile T *obj, R(T::*method)(ArgTs...) const volatile, ArgTs... args) :
346  UserAllocatedEvent(q, mbed::callback(obj, method), args...) { }
347 };
348 
349 // Convenience functions declared here to avoid cyclic
350 // dependency between Event and EventQueue
351 template <typename F, typename... ArgTs>
352 UserAllocatedEvent<F, void(ArgTs...)> EventQueue::make_user_allocated_event(F f, ArgTs... args)
353 {
354  return UserAllocatedEvent<F, void(ArgTs...)>(this, f, args...);
355 }
356 
357 template <typename T, typename R, typename... ArgTs>
358 UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> EventQueue::make_user_allocated_event(T *obj, R(T::*method)(ArgTs... args), ArgTs... args)
359 {
360  return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(this, mbed::callback(obj, method), args...);
361 }
362 
363 template <typename T, typename R, typename... ArgTs>
364 UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> EventQueue::make_user_allocated_event(const T *obj, R(T::*method)(ArgTs... args) const, ArgTs... args)
365 {
366  return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(this, mbed::callback(obj, method), args...);
367 }
368 
369 template <typename T, typename R, typename... ArgTs>
370 UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> EventQueue::make_user_allocated_event(volatile T *obj, R(T::*method)(ArgTs... args) volatile, ArgTs... args)
371 {
372  return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(this, mbed::callback(obj, method), args...);
373 }
374 
375 template <typename T, typename R, typename... ArgTs>
376 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)
377 {
378  return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(this, mbed::callback(obj, method), args...);
379 }
380 
381 
382 /** Creates a UserAllocatedEvent object, deducing the target type from the types of arguments
383  *
384  * UserAllocatedEvent doesn't utilize EventQueue internal memory,
385  * therefore it can be posted on the queue without being afraid
386  * of post fail due to queue memory exhaustion
387  *
388  * @return UserAllocatedEvent object instance
389  *
390  */
391 template <typename F, typename... ArgTs>
392 constexpr UserAllocatedEvent<F, void(ArgTs...)> make_user_allocated_event(F f, ArgTs... args)
393 {
394  return UserAllocatedEvent<F, void(ArgTs...)>(f, args...);
395 }
396 
397 /** Creates a UserAllocatedEvent object, deducing the target type from the types of arguments
398  *
399  * UserAllocatedEvent doesn't utilize EventQueue internal memory,
400  * therefore it can be posted on the queue without being afraid
401  * of post fail due to queue memory exhaustion
402  *
403  * @return UserAllocatedEvent object instance
404  *
405  */
406 template <typename T, typename R, typename... ArgTs>
407 constexpr UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(T *obj, R(T::*method)(ArgTs... args), ArgTs... args)
408 {
409  return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(mbed::callback(obj, method), args...);
410 }
411 
412 /** Creates a UserAllocatedEvent object, deducing the target type from the types of arguments
413  *
414  * UserAllocatedEvent doesn't utilize EventQueue internal memory,
415  * therefore it can be posted on the queue without being afraid
416  * of post fail due to queue memory exhaustion
417  *
418  * @return UserAllocatedEvent object instance
419  *
420  */
421 template <typename T, typename R, typename... ArgTs>
422 constexpr UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(const T *obj, R(T::*method)(ArgTs... args) const, ArgTs... args)
423 {
424  return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(mbed::callback(obj, method), args...);
425 }
426 
427 /** Creates a UserAllocatedEvent object, deducing the target type from the types of arguments
428  *
429  * UserAllocatedEvent doesn't utilize EventQueue internal memory,
430  * therefore it can be posted on the queue without being afraid
431  * of post fail due to queue memory exhaustion
432  *
433  * @return UserAllocatedEvent object instance
434  *
435  */
436 template <typename T, typename R, typename... ArgTs>
437 constexpr UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(volatile T *obj, R(T::*method)(ArgTs... args) volatile, ArgTs... args)
438 {
439  return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(mbed::callback(obj, method), args...);
440 }
441 
442 /** Creates a UserAllocatedEvent object, deducing the target type from the types of arguments
443  *
444  * UserAllocatedEvent doesn't utilize EventQueue internal memory,
445  * therefore it can be posted on the queue without being afraid
446  * of post fail due to queue memory exhaustion
447  *
448  * @return UserAllocatedEvent object instance
449  *
450  */
451 template <typename T, typename R, typename... ArgTs>
452 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)
453 {
454  return UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)>(mbed::callback(obj, method), args...);
455 }
456 
457 /** @}*/
458 
459 /** @}*/
460 }
461 #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:60
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.
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:65
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:60
Callback< R(ArgTs...)> callback(R(*func)(ArgTs...)=0)
Create a callback class with type inferred from the arguments.
Definition: Callback.h:709
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:39
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.