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-04-18
- Revision:
- 20:2f9d9c53a5af
- Parent:
- 17:6d564266850e
File content as of revision 20:2f9d9c53a5af:
#include "EventQueue.h" #include "Event.h" #include "mbed.h" #include "rtos.h" // 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); } // Event queue definitions EventQueue::EventQueue(unsigned event_count, unsigned event_context, unsigned char *event_pointer) { _event_context = sizeof(FuncPtr<void()>) + event_context; unsigned event_size = sizeof(struct event) + _event_context; if (!event_pointer) { _mem = malloc(event_count * event_size); _free = (struct event*)_mem; } else { _mem = 0; _free = (struct event*)event_pointer; } if (_free) { for (unsigned i = 0; i < event_count-1; i++) { ((struct event*)((char*)_free + i*event_size))->next = (struct event*)((char*)_free + (i+1)*event_size); } ((struct event*)((char*)_free + (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(); } bool EventQueue::past_tick(unsigned tick) { return static_cast<int>(tick - get_tick()) <= 0; } void EventQueue::tick() { _timer.reset(); _tick += 1 << 16; } void EventQueue::dispatch(int ms) { unsigned target = get_tick() + (unsigned)ms; while (true) { while (_queue) { if (!past_tick(_queue->target)) { break; } unsigned primask = irq_disable(); struct event *volatile e = _queue; _queue = _queue->next; irq_enable(primask); e->dispatch(reinterpret_cast<void *>(e + 1)); if (e->period >= 0) { event_trigger(e, e->period); } else { event_dealloc(e); } } if (ms >= 0 && past_tick(target)) { return; } osStatus status = Thread::yield(); if (status != osOK) { return; } } } void EventQueue::event_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::event_alloc(unsigned size, int ms) { if (size > _event_context) { return 0; } unsigned target = get_tick() + (unsigned)ms; struct event *e; while (true) { if (_free) { unsigned primask = irq_disable(); if (_free) { e = _free; _free = _free->next; } irq_enable(primask); } if (e || (ms >= 0 && past_tick(target))) { return e; } osStatus status = Thread::yield(); if (status != osOK) { return e; } } } void EventQueue::event_dealloc(struct event *e) { unsigned primask = irq_disable(); e->next = _free; _free = e; irq_enable(primask); }