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.

EventQueue.cpp

Committer:
Christopher Haster
Date:
2016-04-22
Revision:
9:2b0910397844
Parent:
7:dcd589b578ca
Child:
10:62767e708bb6

File content as of revision 9:2b0910397844:

#include "EventQueue.h"
#include "Event.h"

#ifndef EVENTS_NO_RTOS
#include "rtos.h"
#endif


EventQueue::EventQueue() {
    _queue = 0;
    _tick = 0;
    _timer.start();
    _ticker.attach_us(this, &EventQueue::tick, (1 << 16) * 1000);
}

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) {
    mbed::Timeout timeout;
    struct event exit;
    
    if (ms >= 0) {
        memset(&exit, 0, sizeof exit);
        event_register(&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;
            e->registered = false;

            if (e == &exit) {
                return;
            }

            e->callback(e->data);

            if (e->period >= 0) {
                event_register(e, e->period);
            }
        }

#ifndef EVENTS_NO_RTOS
        Thread::yield();
#else
        __WFI();
#endif
    }
}

void EventQueue::event_register(struct event *event, int ms) {
    if (event->registered) {
        return;
    }

    event->target = get_tick() + (unsigned)ms;
    event->registered = true;

    uint32_t primask = __get_PRIMASK();
    __disable_irq();

    struct event *volatile *p = &_queue;
    while (*p && (*p)->target < event->target) {
        p = &(*p)->next;
    }

    event->next = *p;
    *p = event;

    __set_PRIMASK(primask);
}

void EventQueue::event_unregister(struct event *event) {
    uint32_t primask = __get_PRIMASK();
    __disable_irq();

    for (struct event *volatile *p = &_queue; *p; p = &(*p)->next) {
        if (*p == event) {
            *p = event->next;
            break;
        }
    }

    __set_PRIMASK(primask);
}