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.h

Committer:
Christopher Haster
Date:
2016-04-18
Revision:
20:2f9d9c53a5af
Parent:
19:86ffaa34870b

File content as of revision 20:2f9d9c53a5af:

/*  EventQueue
 *
 *  Flexible queue for managing events
 */
#ifndef EVENT_QUEUE_H
#define EVENT_QUEUE_H

#include "Timer.h"
#include "Ticker.h"
#include "FuncPtr.h"
#include "Binder.h"


/** Flexible queue for managing events
 */
class EventQueue {
public:
    /** Create an event queue
     *  @param event_count      Number of events to allow enqueueing at once
     *                          (default: 32)
     *  @param event_context    Max size of arguments passed with an event
     *                          (default: 0)
     *  @param event_pointer    Pointer to memory area to be used for events
     *                          (default: NULL)
     */
    EventQueue(unsigned event_count=32,
               unsigned event_context=0,
               unsigned char *event_pointer=NULL);

    /** Clean up event queue
     */
    ~EventQueue();

    /** Dispatch pending events
     *  @param ms       Time to wait for events in milliseconds,
     *                  0 indicates to return immediately if no events are pending
     */
    void dispatch(int ms=-1);

    /** Get current tick of the event queue
     *  @return         Number of milliseconds since the queue was instantiated,
     *                  this count intentionally overflows to 0 after 2^32-1
     */
    unsigned get_tick();

    /** Determine if tick has been passed
     *  @param          Tick to check
     *  @param          True if tick has been passed
     */
    bool past_tick(unsigned tick);

private:
    struct event {
        struct event *volatile next;
        unsigned target;
        int period;

        void (*dispatch)(void *p);
        // data follows
    };

    struct event *event_alloc(unsigned size, int ms=-1);
    void event_dealloc(struct event *);

    void event_trigger(struct event *e, int delay);

    template <typename F>
    bool event_trigger(F func, int delay, int period, int tolerance, int ms=-1) {
        struct event *e = event_alloc(sizeof(F), ms);
        if (!e) {
            return false;
        }

        e->period = period;
        (void)tolerance; // unused
        e->dispatch = &F::thunk;
        *reinterpret_cast<F*>(e+1) = func;

        event_trigger(e, delay);
        return true;
    }

    void tick();

    unsigned _event_context;
    void *_mem;

    struct event *volatile _free;
    struct event *volatile _queue;

    unsigned _tick;
    mbed::Ticker _ticker;
    mbed::Timer _timer;

    template <typename F>
    friend class Event;

public:
    // An event loop provides three additional convenience functions
    // trigger       - Immediately post an event to the queue
    // trigger_in    - Post an event after a specified time in milliseconds
    // trigger_every - Post an event periodically in milliseconds
    //
    // Unfortunately, the lack of converting constructors in
    // template functions combined with a lack of variadic
    // templates requires 18 declarations for each function

    /** Immediately post an event to the queue
     */
    template <typename F, typename A0, typename A1, typename A2, typename A3, typename A4>
    bool trigger(F func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
        return event_trigger(Binder<void(A0,A1,A2,A3,A4),A0,A1,A2,A3,A4>(func,a0,a1,a2,a3,a4), 0, -1, 0);
    }

    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4>
    bool trigger(T *obj, void (*func)(T*,A0,A1,A2,A3,A4), A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
        return trigger(FuncPtr<void(A0,A1,A2,A3,A4)>(obj,func),a0,a1,a2,a3,a4);
    }

    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4>
    bool trigger(T *obj, void (T::*func)(A0,A1,A2,A3,A4), A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
        return trigger(FuncPtr<void(A0,A1,A2,A3,A4)>(obj,func),a0,a1,a2,a3,a4);
    }

    /** Immediately post an event to the queue
     */
    template <typename F, typename A0, typename A1, typename A2, typename A3>
    bool trigger(F func, A0 a0, A1 a1, A2 a2, A3 a3) {
        return event_trigger(Binder<void(A0,A1,A2,A3),A0,A1,A2,A3>(func,a0,a1,a2,a3), 0, -1, 0);
    }

    template <typename T, typename A0, typename A1, typename A2, typename A3>
    bool trigger(T *obj, void (*func)(T*,A0,A1,A2,A3), A0 a0, A1 a1, A2 a2, A3 a3) {
        return trigger(FuncPtr<void(A0,A1,A2,A3)>(obj,func),a0,a1,a2,a3);
    }

    template <typename T, typename A0, typename A1, typename A2, typename A3>
    bool trigger(T *obj, void (T::*func)(A0,A1,A2,A3), A0 a0, A1 a1, A2 a2, A3 a3) {
        return trigger(FuncPtr<void(A0,A1,A2,A3)>(obj,func),a0,a1,a2,a3);
    }

    /** Immediately post an event to the queue
     */
    template <typename F, typename A0, typename A1, typename A2>
    bool trigger(F func, A0 a0, A1 a1, A2 a2) {
        return event_trigger(Binder<void(A0,A1,A2),A0,A1,A2>(func,a0,a1,a2), 0, -1, 0);
    }

    template <typename T, typename A0, typename A1, typename A2>
    bool trigger(T *obj, void (*func)(T*,A0,A1,A2), A0 a0, A1 a1, A2 a2) {
        return trigger(FuncPtr<void(A0,A1,A2)>(obj,func),a0,a1,a2);
    }

    template <typename T, typename A0, typename A1, typename A2>
    bool trigger(T *obj, void (T::*func)(A0,A1,A2), A0 a0, A1 a1, A2 a2) {
        return trigger(FuncPtr<void(A0,A1,A2)>(obj,func),a0,a1,a2);
    }

    /** Immediately post an event to the queue
     */
    template <typename F, typename A0, typename A1>
    bool trigger(F func, A0 a0, A1 a1) {
        return event_trigger(Binder<void(A0,A1),A0,A1>(func,a0,a1), 0, -1, 0);
    }

    template <typename T, typename A0, typename A1>
    bool trigger(T *obj, void (*func)(T*,A0,A1), A0 a0, A1 a1) {
        return trigger(FuncPtr<void(A0,A1)>(obj,func),a0,a1);
    }

    template <typename T, typename A0, typename A1>
    bool trigger(T *obj, void (T::*func)(A0,A1), A0 a0, A1 a1) {
        return trigger(FuncPtr<void(A0,A1)>(obj,func),a0,a1);
    }

    /** Immediately post an event to the queue
     */
    template <typename F, typename A0>
    bool trigger(F func, A0 a0) {
        return event_trigger(Binder<void(A0),A0>(func,a0), 0, -1, 0);
    }

    template <typename T, typename A0>
    bool trigger(T *obj, void (*func)(T*,A0), A0 a0) {
        return trigger(FuncPtr<void(A0)>(obj,func),a0);
    }

    template <typename T, typename A0>
    bool trigger(T *obj, void (T::*func)(A0), A0 a0) {
        return trigger(FuncPtr<void(A0)>(obj,func),a0);
    }

    /** Immediately post an event to the queue
     */
    template <typename F>
    bool trigger(F func) {
        return event_trigger(Binder<void()>(func), 0, -1, 0);
    }

    template <typename T>
    bool trigger(T *obj, void (*func)(T*)) {
        return trigger(FuncPtr<void()>(obj,func));
    }

    template <typename T>
    bool trigger(T *obj, void (T::*func)()) {
        return trigger(FuncPtr<void()>(obj,func));
    }

    /** Post an event after a specified time
     *  @param ms   Delay in milliseconds
     */
    template <typename F, typename A0, typename A1, typename A2, typename A3, typename A4>
    bool trigger_in(F func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, int ms) {
        return event_trigger(Binder<void(A0,A1,A2,A3,A4),A0,A1,A2,A3,A4>(func,a0,a1,a2,a3,a4), ms, -1, 0);
    }

    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4>
    bool trigger_in(T *obj, void (*func)(T*,A0,A1,A2,A3,A4), A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, int ms) {
        return trigger_in(FuncPtr<void(A0,A1,A2,A3,A4)>(obj,func),a0,a1,a2,a3,a4,ms);
    }

    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4>
    bool trigger_in(T *obj, void (T::*func)(A0,A1,A2,A3,A4), A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, int ms) {
        return trigger_in(FuncPtr<void(A0,A1,A2,A3,A4)>(obj,func),a0,a1,a2,a3,a4,ms);
    }

    /** Post an event after a specified time
     *  @param ms   Delay in milliseconds
     */
    template <typename F, typename A0, typename A1, typename A2, typename A3>
    bool trigger_in(F func, A0 a0, A1 a1, A2 a2, A3 a3, int ms) {
        return event_trigger(Binder<void(A0,A1,A2,A3),A0,A1,A2,A3>(func,a0,a1,a2,a3), ms, -1, 0);
    }

    template <typename T, typename A0, typename A1, typename A2, typename A3>
    bool trigger_in(T *obj, void (*func)(T*,A0,A1,A2,A3), A0 a0, A1 a1, A2 a2, A3 a3, int ms) {
        return trigger_in(FuncPtr<void(A0,A1,A2,A3)>(obj,func),a0,a1,a2,a3,ms);
    }

    template <typename T, typename A0, typename A1, typename A2, typename A3>
    bool trigger_in(T *obj, void (T::*func)(A0,A1,A2,A3), A0 a0, A1 a1, A2 a2, A3 a3, int ms) {
        return trigger_in(FuncPtr<void(A0,A1,A2,A3)>(obj,func),a0,a1,a2,a3,ms);
    }

    /** Post an event after a specified time
     *  @param ms   Delay in milliseconds
     */
    template <typename F, typename A0, typename A1, typename A2>
    bool trigger_in(F func, A0 a0, A1 a1, A2 a2, int ms) {
        return event_trigger(Binder<void(A0,A1,A2),A0,A1,A2>(func,a0,a1,a2), ms, -1, 0);
    }

    template <typename T, typename A0, typename A1, typename A2>
    bool trigger_in(T *obj, void (*func)(T*,A0,A1,A2), A0 a0, A1 a1, A2 a2, int ms) {
        return trigger_in(FuncPtr<void(A0,A1,A2)>(obj,func),a0,a1,a2,ms);
    }

    template <typename T, typename A0, typename A1, typename A2>
    bool trigger_in(T *obj, void (T::*func)(A0,A1,A2), A0 a0, A1 a1, A2 a2, int ms) {
        return trigger_in(FuncPtr<void(A0,A1,A2)>(obj,func),a0,a1,a2,ms);
    }

    /** Post an event after a specified time
     *  @param ms   Delay in milliseconds
     */
    template <typename F, typename A0, typename A1>
    bool trigger_in(F func, A0 a0, A1 a1, int ms) {
        return event_trigger(Binder<void(A0,A1),A0,A1>(func,a0,a1), ms, -1, 0);
    }

    template <typename T, typename A0, typename A1>
    bool trigger_in(T *obj, void (*func)(T*,A0,A1), A0 a0, A1 a1, int ms) {
        return trigger_in(FuncPtr<void(A0,A1)>(obj,func),a0,a1,ms);
    }

    template <typename T, typename A0, typename A1>
    bool trigger_in(T *obj, void (T::*func)(A0,A1), A0 a0, A1 a1, int ms) {
        return trigger_in(FuncPtr<void(A0,A1)>(obj,func),a0,a1,ms);
    }

    /** Post an event after a specified time
     *  @param ms   Delay in milliseconds
     */
    template <typename F, typename A0>
    bool trigger_in(F func, A0 a0, int ms) {
        return event_trigger(Binder<void(A0),A0>(func,a0), ms, -1, 0);
    }

    template <typename T, typename A0>
    bool trigger_in(T *obj, void (*func)(T*,A0), A0 a0, int ms) {
        return trigger_in(FuncPtr<void(A0)>(obj,func),a0,ms);
    }

    template <typename T, typename A0>
    bool trigger_in(T *obj, void (T::*func)(A0), A0 a0, int ms) {
        return trigger_in(FuncPtr<void(A0)>(obj,func),a0,ms);
    }

    /** Post an event after a specified time
     *  @param ms   Delay in milliseconds
     */
    template <typename F>
    bool trigger_in(F func, int ms) {
        return event_trigger(Binder<void()>(func), ms, -1, 0);
    }

    template <typename T>
    bool trigger_in(T *obj, void (*func)(T*), int ms) {
        return trigger_in(FuncPtr<void()>(obj,func),ms);
    }

    template <typename T>
    bool trigger_in(T *obj, void (T::*func)(), int ms) {
        return trigger_in(FuncPtr<void()>(obj,func),ms);
    }

    /** Post an event periodically
     *  @param ms   Delay in milliseconds
     */
    template <typename F, typename A0, typename A1, typename A2, typename A3, typename A4>
    bool trigger_every(F func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, int ms) {
        return event_trigger(Binder<void(A0,A1,A2,A3,A4),A0,A1,A2,A3,A4>(func,a0,a1,a2,a3,a4), 0, ms, 0);
    }

    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4>
    bool trigger_every(T *obj, void (*func)(T*,A0,A1,A2,A3,A4), A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, int ms) {
        return trigger_every(FuncPtr<void(A0,A1,A2,A3,A4)>(obj,func),a0,a1,a2,a3,a4,ms);
    }

    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4>
    bool trigger_every(T *obj, void (T::*func)(A0,A1,A2,A3,A4), A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, int ms) {
        return trigger_every(FuncPtr<void(A0,A1,A2,A3,A4)>(obj,func),a0,a1,a2,a3,a4,ms);
    }

    /** Post an event periodically
     *  @param ms   Delay in milliseconds
     */
    template <typename F, typename A0, typename A1, typename A2, typename A3>
    bool trigger_every(F func, A0 a0, A1 a1, A2 a2, A3 a3, int ms) {
        return event_trigger(Binder<void(A0,A1,A2,A3),A0,A1,A2,A3>(func,a0,a1,a2,a3), 0, ms, 0);
    }

    template <typename T, typename A0, typename A1, typename A2, typename A3>
    bool trigger_every(T *obj, void (*func)(T*,A0,A1,A2,A3), A0 a0, A1 a1, A2 a2, A3 a3, int ms) {
        return trigger_every(FuncPtr<void(A0,A1,A2,A3)>(obj,func),a0,a1,a2,a3,ms);
    }

    template <typename T, typename A0, typename A1, typename A2, typename A3>
    bool trigger_every(T *obj, void (T::*func)(A0,A1,A2,A3), A0 a0, A1 a1, A2 a2, A3 a3, int ms) {
        return trigger_every(FuncPtr<void(A0,A1,A2,A3)>(obj,func),a0,a1,a2,a3,ms);
    }

    /** Post an event periodically
     *  @param ms   Delay in milliseconds
     */
    template <typename F, typename A0, typename A1, typename A2>
    bool trigger_every(F func, A0 a0, A1 a1, A2 a2, int ms) {
        return event_trigger(Binder<void(A0,A1,A2),A0,A1,A2>(func,a0,a1,a2), 0, ms, 0);
    }

    template <typename T, typename A0, typename A1, typename A2>
    bool trigger_every(T *obj, void (*func)(T*,A0,A1,A2), A0 a0, A1 a1, A2 a2, int ms) {
        return trigger_every(FuncPtr<void(A0,A1,A2)>(obj,func),a0,a1,a2,ms);
    }

    template <typename T, typename A0, typename A1, typename A2>
    bool trigger_every(T *obj, void (T::*func)(A0,A1,A2), A0 a0, A1 a1, A2 a2, int ms) {
        return trigger_every(FuncPtr<void(A0,A1,A2)>(obj,func),a0,a1,a2,ms);
    }

    /** Post an event periodically
     *  @param ms   Delay in milliseconds
     */
    template <typename F, typename A0, typename A1>
    bool trigger_every(F func, A0 a0, A1 a1, int ms) {
        return event_trigger(Binder<void(A0,A1),A0,A1>(func,a0,a1), 0, ms, 0);
    }

    template <typename T, typename A0, typename A1>
    bool trigger_every(T *obj, void (*func)(T*,A0,A1), A0 a0, A1 a1, int ms) {
        return trigger_every(FuncPtr<void(A0,A1)>(obj,func),a0,a1,ms);
    }

    template <typename T, typename A0, typename A1>
    bool trigger_every(T *obj, void (T::*func)(A0,A1), A0 a0, A1 a1, int ms) {
        return trigger_every(FuncPtr<void(A0,A1)>(obj,func),a0,a1,ms);
    }

    /** Post an event periodically
     *  @param ms   Delay in milliseconds
     */
    template <typename F, typename A0>
    bool trigger_every(F func, A0 a0, int ms) {
        return event_trigger(Binder<void(A0),A0>(func,a0), 0, ms, 0);
    }

    template <typename T, typename A0>
    bool trigger_every(T *obj, void (*func)(T*,A0), A0 a0, int ms) {
        return trigger_every(FuncPtr<void(A0)>(obj,func),a0,ms);
    }

    template <typename T, typename A0>
    bool trigger_every(T *obj, void (T::*func)(A0), A0 a0, int ms) {
        return trigger_every(FuncPtr<void(A0)>(obj,func),a0,ms);
    }

    /** Post an event periodically
     *  @param ms   Delay in milliseconds
     */
    template <typename F>
    bool trigger_every(F func, int ms) {
        return event_trigger(Binder<void()>(func), 0, ms, 0);
    }

    template <typename T>
    bool trigger_every(T *obj, void (*func)(T*), int ms) {
        return trigger_every(FuncPtr<void()>(obj,func),ms);
    }

    template <typename T>
    bool trigger_every(T *obj, void (T::*func)(), int ms) {
        return trigger_every(FuncPtr<void()>(obj,func),ms);
    }
};


#endif