Skip to content

Commit 19e33ba

Browse files
UserAllocatedEvent implementation
UserAllocatedEvent provides mechanism for event posting and dispatching without utilization of queue internal memory. UserAllocatedEvent embeds all underlying event data and doesn't require any memory allocation while posting and dispatching. All of these makes it cannot fail due to memory exhaustion while posting.
1 parent e7e5cd2 commit 19e33ba

File tree

4 files changed

+627
-11
lines changed

4 files changed

+627
-11
lines changed

events/EventQueue.h

Lines changed: 156 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ namespace events {
4545
// Predeclared classes
4646
template <typename F>
4747
class Event;
48+
template <typename F, typename A>
49+
class UserAllocatedEvent;
4850

4951
/**
5052
* \defgroup events_EventQueue EventQueue class
@@ -60,10 +62,17 @@ class EventQueue : private mbed::NonCopyable<EventQueue> {
6062
/** Create an EventQueue
6163
*
6264
* Create an event queue. The event queue either allocates a buffer of
63-
* the specified size with malloc or uses the user provided buffer.
65+
* the specified size with malloc or uses the user provided buffer or
66+
* uses 1B dummy buffer if 0 size passed.
67+
*
68+
* 0 size queue is a special purpose queue to dispatch static events
69+
* only (see UserAllocatedEvent). Such a queue gives the guarantee
70+
* that no dynamic memory allocation will take place while queue
71+
* creation and events posting & dispatching.
6472
*
6573
* @param size Size of buffer to use for events in bytes
6674
* (default to EVENTS_QUEUE_SIZE)
75+
* If 0 provided then 1B dummy buffer is used
6776
* @param buffer Pointer to buffer to use for events
6877
* (default to NULL)
6978
*/
@@ -139,6 +148,34 @@ class EventQueue : private mbed::NonCopyable<EventQueue> {
139148
*/
140149
bool cancel(int id);
141150

151+
/** Cancel an in-flight user allocated event
152+
*
153+
* Attempts to cancel an UserAllocatedEvent referenced by its address
154+
* It is safe to call cancel after an event has already been dispatched.
155+
*
156+
* Event must be valid i.e. event must have not finished executing
157+
* and must have been bound to this queue.
158+
*
159+
* The cancel function is IRQ safe.
160+
*
161+
* If called while the event queue's dispatch loop is active in another thread,
162+
* the cancel function does not guarantee that the event will not execute after it
163+
* returns, as the event may have already begun executing. A call made from
164+
* the same thread as the dispatch loop will always succeed with a valid id.
165+
*
166+
* @param event Address of the event
167+
* @return true if event was successfully cancelled
168+
* false if event was not cancelled (invalid queue or executing already begun)
169+
*/
170+
template<typename... Args>
171+
bool cancel(UserAllocatedEvent<Args...> *event)
172+
{
173+
if (event->_equeue != &_equeue) {
174+
return false;
175+
}
176+
return equeue_cancel_user_allocated(&_equeue, event);
177+
}
178+
142179
/** Query how much time is left for delayed event
143180
*
144181
* If the event is delayed, this function can be used to query how much time
@@ -158,6 +195,33 @@ class EventQueue : private mbed::NonCopyable<EventQueue> {
158195
*/
159196
int time_left(int id);
160197

198+
/** Query how much time is left for delayed UserAllocatedEvent
199+
*
200+
* If the event is delayed, this function can be used to query how much time
201+
* is left until the event is due to be dispatched.
202+
*
203+
* Event must be valid i.e. event must have not finished executing
204+
* and must have been bound to this queue.
205+
*
206+
* This function is IRQ safe.
207+
*
208+
* @param event Address of the event
209+
*
210+
* @return Remaining time in milliseconds or
211+
* 0 if event is already due to be dispatched or
212+
* is currently executing.
213+
* Undefined if id is invalid.
214+
*
215+
*/
216+
template<typename... Args>
217+
int time_left(UserAllocatedEvent<Args...> *event)
218+
{
219+
if (event && event->_equeue != &_equeue) {
220+
return -1;
221+
}
222+
return equeue_timeleft_user_allocated(&_equeue, &event->_e);
223+
}
224+
161225
/** Background an event queue onto a single-shot timer-interrupt
162226
*
163227
* When updated, the event queue will call the provided update function
@@ -597,6 +661,53 @@ class EventQueue : private mbed::NonCopyable<EventQueue> {
597661
template <typename R, typename ...BoundArgs, typename ...ContextArgs, typename ...Args>
598662
Event<void(Args...)> event(mbed::Callback<R(BoundArgs..., Args...)> cb, ContextArgs ...context_args);
599663

664+
/** Creates an user allocated event bound to the event queue
665+
*
666+
* Constructs an user allocated event bound to the specified event queue.
667+
* The specified callback acts as the target for the event and is executed
668+
* in the context of the event queue's dispatch loop once posted.
669+
*
670+
* @code
671+
* #include "mbed.h"
672+
*
673+
* void handler(int data) { ... }
674+
*
675+
* class Device {
676+
* public:
677+
* void handler(int data) { ... }
678+
* };
679+
*
680+
* Device dev;
681+
*
682+
* // queue with not internal storage for dynamic events
683+
* // accepts only user allocated events
684+
* static EventQueue queue(0);
685+
* // Create events
686+
* static auto e1 = make_user_allocated_event(&dev, Device::handler, 2);
687+
* static auto e2 = queue.make_user_allocated_event(handler, 3);
688+
*
689+
* int main()
690+
* {
691+
* e1.call_on(&queue);
692+
* e2.call();
693+
*
694+
* queue.dispatch(1);
695+
* }
696+
* @endcode
697+
*
698+
* @param f Function to execute when the event is dispatched
699+
* @return Event that will dispatch on the specific queue
700+
*/
701+
template <typename F, typename... ArgTs>
702+
UserAllocatedEvent<F, void(ArgTs...)> make_user_allocated_event(F f, ArgTs... args);
703+
704+
/** Creates an user allocated event bound to the event queue
705+
* @see EventQueue::make_user_allocated_event
706+
*/
707+
template <typename T, typename R, typename... ArgTs>
708+
UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(T *obj, R(T::*method)(ArgTs... args), ArgTs... args);
709+
710+
600711
#else
601712

602713
/** Calls an event on the queue
@@ -1068,12 +1179,50 @@ class EventQueue : private mbed::NonCopyable<EventQueue> {
10681179
*/
10691180
template <typename R, typename B0, typename B1, typename B2, typename B3, typename B4, typename C0, typename C1, typename C2, typename C3, typename C4, typename... ArgTs>
10701181
Event<void(ArgTs...)> event(mbed::Callback<R(B0, B1, B2, B3, B4, ArgTs...)> cb, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4);
1182+
1183+
/** Creates an user allocated event bound to the event queue
1184+
*
1185+
* Constructs an user allocated event bound to the specified event queue.
1186+
* The specified callback acts as the target for the event and is executed
1187+
* in the context of the event queue's dispatch loop once posted.
1188+
*
1189+
* @param f Function to execute when the event is dispatched
1190+
* @return Event that will dispatch on the specific queue
1191+
*/
1192+
template <typename F, typename... ArgTs>
1193+
UserAllocatedEvent<F, void(ArgTs...)> make_user_allocated_event(F f, ArgTs... args);
1194+
1195+
/** Creates an user allocated event bound to the event queue
1196+
* @see EventQueue::make_user_allocated_event
1197+
*/
1198+
template <typename T, typename R, typename... ArgTs>
1199+
UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(T *obj, R(T::*method)(ArgTs... args), ArgTs... args);
1200+
1201+
/** Creates an user allocated event bound to the event queue
1202+
* @see EventQueue::make_user_allocated_event
1203+
*/
1204+
template <typename T, typename R, typename... ArgTs>
1205+
UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(const T *obj, R(T::*method)(ArgTs... args) const, ArgTs... args);
1206+
1207+
/** Creates an user allocated event bound to the event queue
1208+
* @see EventQueue::make_user_allocated_event
1209+
*/
1210+
template <typename T, typename R, typename... ArgTs>
1211+
UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(volatile T *obj, R(T::*method)(ArgTs... args) volatile, ArgTs... args);
1212+
1213+
/** Creates an user allocated event bound to the event queue
1214+
* @see EventQueue::make_user_allocated_event
1215+
*/
1216+
template <typename T, typename R, typename... ArgTs>
1217+
UserAllocatedEvent<mbed::Callback<void(ArgTs...)>, void(ArgTs...)> make_user_allocated_event(const volatile T *obj, R(T::*method)(ArgTs... args) const volatile, ArgTs... args);
10711218
#endif
10721219

10731220
protected:
10741221
#if !defined(DOXYGEN_ONLY)
10751222
template <typename F>
10761223
friend class Event;
1224+
template <typename F, typename A>
1225+
friend class UserAllocatedEvent;
10771226
struct equeue _equeue;
10781227
mbed::Callback<void(int)> _update;
10791228

@@ -1098,7 +1247,7 @@ class EventQueue : private mbed::NonCopyable<EventQueue> {
10981247
struct context<F> {
10991248
F f;
11001249

1101-
context(F f)
1250+
constexpr context(F f)
11021251
: f(f) {}
11031252

11041253
template <typename... ArgTs>
@@ -1113,7 +1262,7 @@ class EventQueue : private mbed::NonCopyable<EventQueue> {
11131262
F f;
11141263
C0 c0;
11151264

1116-
context(F f, C0 c0)
1265+
constexpr context(F f, C0 c0)
11171266
: f(f), c0(c0) {}
11181267

11191268
template <typename... ArgTs>
@@ -1129,7 +1278,7 @@ class EventQueue : private mbed::NonCopyable<EventQueue> {
11291278
C0 c0;
11301279
C1 c1;
11311280

1132-
context(F f, C0 c0, C1 c1)
1281+
constexpr context(F f, C0 c0, C1 c1)
11331282
: f(f), c0(c0), c1(c1) {}
11341283

11351284
template <typename... ArgTs>
@@ -1146,7 +1295,7 @@ class EventQueue : private mbed::NonCopyable<EventQueue> {
11461295
C1 c1;
11471296
C2 c2;
11481297

1149-
context(F f, C0 c0, C1 c1, C2 c2)
1298+
constexpr context(F f, C0 c0, C1 c1, C2 c2)
11501299
: f(f), c0(c0), c1(c1), c2(c2) {}
11511300

11521301
template <typename... ArgTs>
@@ -1164,7 +1313,7 @@ class EventQueue : private mbed::NonCopyable<EventQueue> {
11641313
C2 c2;
11651314
C3 c3;
11661315

1167-
context(F f, C0 c0, C1 c1, C2 c2, C3 c3)
1316+
constexpr context(F f, C0 c0, C1 c1, C2 c2, C3 c3)
11681317
: f(f), c0(c0), c1(c1), c2(c2), c3(c3) {}
11691318

11701319
template <typename... ArgTs>
@@ -1183,7 +1332,7 @@ class EventQueue : private mbed::NonCopyable<EventQueue> {
11831332
C3 c3;
11841333
C4 c4;
11851334

1186-
context(F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4)
1335+
constexpr context(F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4)
11871336
: f(f), c0(c0), c1(c1), c2(c2), c3(c3), c4(c4) {}
11881337

11891338
template <typename... ArgTs>

0 commit comments

Comments
 (0)