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
- Committer:
- Christopher Haster
- Date:
- 2016-05-10
- Revision:
- 14:5abf2ccf2dbf
- Parent:
- 10:62767e708bb6
- Child:
- 15:92d7c0b8a0f5
File content as of revision 14:5abf2ccf2dbf:
#include "EventQueue.h" #include "Event.h" #include "mbed.h" #ifndef EVENTS_NO_RTOS #include "rtos.h" #endif 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(); } void EventQueue::tick() { _timer.reset(); _tick += 1 << 16; } void EventQueue::wakeup() { } void EventQueue::dispatch(int ms) { Timeout timeout; struct event exit; if (ms >= 0) { trigger(&exit, ms); } while (true) { while (_queue) { int diff = (int)(_queue->target - get_tick()); if (diff > 0) { timeout.attach_us(this, &EventQueue::wakeup, diff * 1000); break; } struct event *volatile e = _queue; _queue = _queue->next; if (e == &exit) { return; } e->dispatch(reinterpret_cast<void *>(e + 1)); if (e->period >= 0) { trigger(e, e->period); } else { dealloc(e); } } #ifndef EVENTS_NO_RTOS Thread::yield(); #else __WFI(); #endif } } 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 < e->target) { p = &(*p)->next; } e->next = *p; *p = e; __set_PRIMASK(primask); } EventQueue::event *EventQueue::alloc(unsigned size, int ms) { if (size > _event_context) { return 0; } struct event *e; uint32_t primask = __get_PRIMASK(); __disable_irq(); 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); }