Note! This project has moved to github.com/armmbed/mbed-events

Dependents:   SimpleHTTPExample

This repository has been superceded

This project has moved to mbed-events

Composable event loops combine the cheap synchronicity of event loops with the composability of preempted threads.

Two modular event queue classes are provided:

  • EventLoop - for loops coupled with a c++ managed thread
  • EventQueue - for manually managed event queues

The Event class takes advantage of the extensibility of FuncPtr to allow an event to be passed through APIs as a normal function.

More information on composable event loops.

Revision:
14:5abf2ccf2dbf
Parent:
10:62767e708bb6
Child:
15:92d7c0b8a0f5
--- a/EventQueue.cpp	Fri Apr 22 22:32:35 2016 -0500
+++ b/EventQueue.cpp	Tue May 10 07:51:44 2016 -0500
@@ -7,13 +7,31 @@
 #endif
 
 
-EventQueue::EventQueue() {
+
+EventQueue::EventQueue(unsigned event_count, unsigned event_context) {
+    _event_context = sizeof(FuncPtr<void()>) + event_context;
+    unsigned event_size = sizeof(struct event) + _event_context;
+    _mem = malloc(event_count * event_size);
+    _free = (struct event*)_mem;
+
+    if (_mem) {
+        for (unsigned i = 0; i < event_count-1; i++) {
+            ((struct event*)((char*)_mem + i*event_size))->next =
+                    (struct event*)((char*)_mem + (i+1)*event_size);
+        }
+        ((struct event*)((char*)_mem + (event_count-1)*event_size))->next = 0;
+    }
+
     _queue = 0;
     _tick = 0;
     _timer.start();
     _ticker.attach_us(this, &EventQueue::tick, (1 << 16) * 1000);
 }
 
+EventQueue::~EventQueue() {
+    free(_mem);
+}
+
 unsigned EventQueue::get_tick() {
     return _tick + (unsigned)_timer.read_ms();
 }
@@ -32,8 +50,7 @@
     struct event exit;
     
     if (ms >= 0) {
-        memset(&exit, 0, sizeof exit);
-        event_register(&exit, ms);
+        trigger(&exit, ms);
     }
 
     while (true) {
@@ -46,16 +63,17 @@
 
             struct event *volatile e = _queue;
             _queue = _queue->next;
-            e->registered = false;
 
             if (e == &exit) {
                 return;
             }
 
-            e->callback(e->data);
+            e->dispatch(reinterpret_cast<void *>(e + 1));
 
             if (e->period >= 0) {
-                event_register(e, e->period);
+                trigger(e, e->period);
+            } else {
+                dealloc(e);
             }
         }
 
@@ -67,39 +85,51 @@
     }
 }
 
-void EventQueue::event_register(struct event *event, int ms) {
-    if (event->registered) {
-        return;
-    }
-
-    event->target = get_tick() + (unsigned)ms;
-    event->registered = true;
+void EventQueue::trigger(struct event *e, int delay) {
+    e->target = get_tick() + (unsigned)delay;
 
     uint32_t primask = __get_PRIMASK();
     __disable_irq();
 
     struct event *volatile *p = &_queue;
-    while (*p && (*p)->target < event->target) {
+    while (*p && (*p)->target < e->target) {
         p = &(*p)->next;
     }
 
-    event->next = *p;
-    *p = event;
+    e->next = *p;
+    *p = e;
 
     __set_PRIMASK(primask);
 }
 
-void EventQueue::event_unregister(struct event *event) {
+EventQueue::event *EventQueue::alloc(unsigned size, int ms) {
+    if (size > _event_context) {
+        return 0;
+    }
+
+    struct event *e;
+
     uint32_t primask = __get_PRIMASK();
     __disable_irq();
 
-    for (struct event *volatile *p = &_queue; *p; p = &(*p)->next) {
-        if (*p == event) {
-            *p = event->next;
-            break;
-        }
+    e = _free;
+    if (e) {
+        _free = e->next;
     }
 
     __set_PRIMASK(primask);
+
+    return e;
 }
 
+void EventQueue::dealloc(struct event *e) {
+    uint32_t primask = __get_PRIMASK();
+    __disable_irq();
+
+    e->next = _free;
+    _free = e;
+
+    __set_PRIMASK(primask);
+
+}
+