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:
- 15:92d7c0b8a0f5
- Parent:
- 14:5abf2ccf2dbf
- Child:
- 16:ff5d48fcce1b
File content as of revision 15:92d7c0b8a0f5:
#include "EventQueue.h" #include "Event.h" #include "mbed.h" #ifndef EVENTS_NO_RTOS #include "rtos.h" #endif // Platform specific definitions static inline unsigned irq_disable() { unsigned primask = __get_PRIMASK(); __disable_irq(); return primask; } static inline void irq_enable(unsigned primask) { __set_PRIMASK(primask); } static inline void irq_wfi() { #ifndef EVENTS_NO_RTOS Thread::yield(); #else __WFI(); #endif } // Event queue definitions 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::exit(volatile bool *exit) { *exit = true; } void EventQueue::dispatch(int ms) { Timeout timeout; volatile bool exit = false; if (ms >= 0) { Event<void(volatile bool*)> e(this, this, &EventQueue::exit); e.delay(ms); e.trigger(&exit); } 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; e->dispatch(reinterpret_cast<void *>(e + 1)); if (e->period >= 0) { trigger(e, e->period); } else { dealloc(e); } } if (exit) { break; } irq_wfi(); } } void EventQueue::trigger(struct event *e, int delay) { e->target = get_tick() + (unsigned)delay; unsigned primask = irq_disable(); struct event *volatile *p = &_queue; while (*p && (*p)->target < e->target) { p = &(*p)->next; } e->next = *p; *p = e; irq_enable(primask); } EventQueue::event *EventQueue::alloc(unsigned size, int ms) { if (size > _event_context) { return 0; } struct event *e; unsigned primask = irq_disable(); e = _free; if (e) { _free = e->next; } irq_enable(primask); return e; } void EventQueue::dealloc(struct event *e) { unsigned primask = irq_disable(); e->next = _free; _free = e; irq_enable(primask); }