Note! This project has moved to github.com/armmbed/mbed-events
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.
EventQueue.cpp@20:2f9d9c53a5af, 2016-04-18 (annotated)
- 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?
User | Revision | Line number | New 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 |