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.

Committer:
Christopher Haster
Date:
Mon Apr 18 13:22:21 2016 -0500
Revision:
20:2f9d9c53a5af
Parent:
17:6d564266850e
Add event_pointer argument to avoid memory allocation

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Christopher Haster 2:11cda6bead99 1 #include "EventQueue.h"
Christopher Haster 2:11cda6bead99 2 #include "Event.h"
Christopher Haster 10:62767e708bb6 3 #include "mbed.h"
Christopher Haster 9:2b0910397844 4 #include "rtos.h"
Christopher Haster 9:2b0910397844 5
Christopher Haster 0:b1b901ae3696 6
Christopher Haster 15:92d7c0b8a0f5 7 // Platform specific definitions
Christopher Haster 15:92d7c0b8a0f5 8 static inline unsigned irq_disable() {
Christopher Haster 15:92d7c0b8a0f5 9 unsigned primask = __get_PRIMASK();
Christopher Haster 15:92d7c0b8a0f5 10 __disable_irq();
Christopher Haster 15:92d7c0b8a0f5 11 return primask;
Christopher Haster 15:92d7c0b8a0f5 12 }
Christopher Haster 14:5abf2ccf2dbf 13
Christopher Haster 15:92d7c0b8a0f5 14 static inline void irq_enable(unsigned primask) {
Christopher Haster 15:92d7c0b8a0f5 15 __set_PRIMASK(primask);
Christopher Haster 15:92d7c0b8a0f5 16 }
Christopher Haster 15:92d7c0b8a0f5 17
Christopher Haster 15:92d7c0b8a0f5 18
Christopher Haster 15:92d7c0b8a0f5 19 // Event queue definitions
Christopher Haster 20:2f9d9c53a5af 20 EventQueue::EventQueue(unsigned event_count,
Christopher Haster 20:2f9d9c53a5af 21 unsigned event_context,
Christopher Haster 20:2f9d9c53a5af 22 unsigned char *event_pointer) {
Christopher Haster 14:5abf2ccf2dbf 23 _event_context = sizeof(FuncPtr<void()>) + event_context;
Christopher Haster 14:5abf2ccf2dbf 24 unsigned event_size = sizeof(struct event) + _event_context;
Christopher Haster 14:5abf2ccf2dbf 25
Christopher Haster 20:2f9d9c53a5af 26 if (!event_pointer) {
Christopher Haster 20:2f9d9c53a5af 27 _mem = malloc(event_count * event_size);
Christopher Haster 20:2f9d9c53a5af 28 _free = (struct event*)_mem;
Christopher Haster 20:2f9d9c53a5af 29 } else {
Christopher Haster 20:2f9d9c53a5af 30 _mem = 0;
Christopher Haster 20:2f9d9c53a5af 31 _free = (struct event*)event_pointer;
Christopher Haster 20:2f9d9c53a5af 32 }
Christopher Haster 20:2f9d9c53a5af 33
Christopher Haster 20:2f9d9c53a5af 34 if (_free) {
Christopher Haster 14:5abf2ccf2dbf 35 for (unsigned i = 0; i < event_count-1; i++) {
Christopher Haster 20:2f9d9c53a5af 36 ((struct event*)((char*)_free + i*event_size))->next =
Christopher Haster 20:2f9d9c53a5af 37 (struct event*)((char*)_free + (i+1)*event_size);
Christopher Haster 14:5abf2ccf2dbf 38 }
Christopher Haster 20:2f9d9c53a5af 39 ((struct event*)((char*)_free + (event_count-1)*event_size))->next = 0;
Christopher Haster 14:5abf2ccf2dbf 40 }
Christopher Haster 14:5abf2ccf2dbf 41
Christopher Haster 5:9963a617f952 42 _queue = 0;
Christopher Haster 2:11cda6bead99 43 _tick = 0;
Christopher Haster 2:11cda6bead99 44 _timer.start();
Christopher Haster 2:11cda6bead99 45 _ticker.attach_us(this, &EventQueue::tick, (1 << 16) * 1000);
Christopher Haster 2:11cda6bead99 46 }
Christopher Haster 2:11cda6bead99 47
Christopher Haster 14:5abf2ccf2dbf 48 EventQueue::~EventQueue() {
Christopher Haster 14:5abf2ccf2dbf 49 free(_mem);
Christopher Haster 14:5abf2ccf2dbf 50 }
Christopher Haster 14:5abf2ccf2dbf 51
Christopher Haster 2:11cda6bead99 52 unsigned EventQueue::get_tick() {
Christopher Haster 2:11cda6bead99 53 return _tick + (unsigned)_timer.read_ms();
Christopher Haster 2:11cda6bead99 54 }
Christopher Haster 2:11cda6bead99 55
Christopher Haster 16:ff5d48fcce1b 56 bool EventQueue::past_tick(unsigned tick) {
Christopher Haster 16:ff5d48fcce1b 57 return static_cast<int>(tick - get_tick()) <= 0;
Christopher Haster 16:ff5d48fcce1b 58 }
Christopher Haster 16:ff5d48fcce1b 59
Christopher Haster 2:11cda6bead99 60 void EventQueue::tick() {
Christopher Haster 2:11cda6bead99 61 _timer.reset();
Christopher Haster 2:11cda6bead99 62 _tick += 1 << 16;
Christopher Haster 2:11cda6bead99 63 }
Christopher Haster 2:11cda6bead99 64
Christopher Haster 1:2202c19570e5 65 void EventQueue::dispatch(int ms) {
Christopher Haster 16:ff5d48fcce1b 66 unsigned target = get_tick() + (unsigned)ms;
Christopher Haster 0:b1b901ae3696 67
Christopher Haster 0:b1b901ae3696 68 while (true) {
Christopher Haster 0:b1b901ae3696 69 while (_queue) {
Christopher Haster 16:ff5d48fcce1b 70 if (!past_tick(_queue->target)) {
Christopher Haster 2:11cda6bead99 71 break;
Christopher Haster 2:11cda6bead99 72 }
Christopher Haster 2:11cda6bead99 73
Christopher Haster 16:ff5d48fcce1b 74 unsigned primask = irq_disable();
Christopher Haster 2:11cda6bead99 75 struct event *volatile e = _queue;
Christopher Haster 0:b1b901ae3696 76 _queue = _queue->next;
Christopher Haster 16:ff5d48fcce1b 77 irq_enable(primask);
Christopher Haster 2:11cda6bead99 78
Christopher Haster 14:5abf2ccf2dbf 79 e->dispatch(reinterpret_cast<void *>(e + 1));
Christopher Haster 2:11cda6bead99 80
Christopher Haster 2:11cda6bead99 81 if (e->period >= 0) {
Christopher Haster 17:6d564266850e 82 event_trigger(e, e->period);
Christopher Haster 14:5abf2ccf2dbf 83 } else {
Christopher Haster 17:6d564266850e 84 event_dealloc(e);
Christopher Haster 2:11cda6bead99 85 }
Christopher Haster 0:b1b901ae3696 86 }
Christopher Haster 0:b1b901ae3696 87
Christopher Haster 16:ff5d48fcce1b 88 if (ms >= 0 && past_tick(target)) {
Christopher Haster 16:ff5d48fcce1b 89 return;
Christopher Haster 15:92d7c0b8a0f5 90 }
Christopher Haster 15:92d7c0b8a0f5 91
Christopher Haster 16:ff5d48fcce1b 92 osStatus status = Thread::yield();
Christopher Haster 16:ff5d48fcce1b 93 if (status != osOK) {
Christopher Haster 16:ff5d48fcce1b 94 return;
Christopher Haster 16:ff5d48fcce1b 95 }
Christopher Haster 0:b1b901ae3696 96 }
Christopher Haster 0:b1b901ae3696 97 }
Christopher Haster 0:b1b901ae3696 98
Christopher Haster 17:6d564266850e 99 void EventQueue::event_trigger(struct event *e, int delay) {
Christopher Haster 14:5abf2ccf2dbf 100 e->target = get_tick() + (unsigned)delay;
Christopher Haster 2:11cda6bead99 101
Christopher Haster 15:92d7c0b8a0f5 102 unsigned primask = irq_disable();
Christopher Haster 2:11cda6bead99 103 struct event *volatile *p = &_queue;
Christopher Haster 14:5abf2ccf2dbf 104 while (*p && (*p)->target < e->target) {
Christopher Haster 2:11cda6bead99 105 p = &(*p)->next;
Christopher Haster 0:b1b901ae3696 106 }
Christopher Haster 2:11cda6bead99 107
Christopher Haster 14:5abf2ccf2dbf 108 e->next = *p;
Christopher Haster 14:5abf2ccf2dbf 109 *p = e;
Christopher Haster 15:92d7c0b8a0f5 110 irq_enable(primask);
Christopher Haster 0:b1b901ae3696 111 }
Christopher Haster 0:b1b901ae3696 112
Christopher Haster 17:6d564266850e 113 EventQueue::event *EventQueue::event_alloc(unsigned size, int ms) {
Christopher Haster 14:5abf2ccf2dbf 114 if (size > _event_context) {
Christopher Haster 14:5abf2ccf2dbf 115 return 0;
Christopher Haster 14:5abf2ccf2dbf 116 }
Christopher Haster 14:5abf2ccf2dbf 117
Christopher Haster 16:ff5d48fcce1b 118 unsigned target = get_tick() + (unsigned)ms;
Christopher Haster 14:5abf2ccf2dbf 119 struct event *e;
Christopher Haster 14:5abf2ccf2dbf 120
Christopher Haster 16:ff5d48fcce1b 121 while (true) {
Christopher Haster 16:ff5d48fcce1b 122 if (_free) {
Christopher Haster 16:ff5d48fcce1b 123 unsigned primask = irq_disable();
Christopher Haster 16:ff5d48fcce1b 124 if (_free) {
Christopher Haster 16:ff5d48fcce1b 125 e = _free;
Christopher Haster 16:ff5d48fcce1b 126 _free = _free->next;
Christopher Haster 16:ff5d48fcce1b 127 }
Christopher Haster 16:ff5d48fcce1b 128 irq_enable(primask);
Christopher Haster 16:ff5d48fcce1b 129 }
Christopher Haster 16:ff5d48fcce1b 130
Christopher Haster 16:ff5d48fcce1b 131 if (e || (ms >= 0 && past_tick(target))) {
Christopher Haster 16:ff5d48fcce1b 132 return e;
Christopher Haster 16:ff5d48fcce1b 133 }
Christopher Haster 16:ff5d48fcce1b 134
Christopher Haster 16:ff5d48fcce1b 135 osStatus status = Thread::yield();
Christopher Haster 16:ff5d48fcce1b 136 if (status != osOK) {
Christopher Haster 16:ff5d48fcce1b 137 return e;
Christopher Haster 16:ff5d48fcce1b 138 }
Christopher Haster 0:b1b901ae3696 139 }
Christopher Haster 0:b1b901ae3696 140 }
Christopher Haster 0:b1b901ae3696 141
Christopher Haster 17:6d564266850e 142 void EventQueue::event_dealloc(struct event *e) {
Christopher Haster 15:92d7c0b8a0f5 143 unsigned primask = irq_disable();
Christopher Haster 14:5abf2ccf2dbf 144 e->next = _free;
Christopher Haster 14:5abf2ccf2dbf 145 _free = e;
Christopher Haster 15:92d7c0b8a0f5 146 irq_enable(primask);
Christopher Haster 14:5abf2ccf2dbf 147 }
Christopher Haster 14:5abf2ccf2dbf 148