Skip to content
This repository has been archived by the owner on Aug 19, 2021. It is now read-only.

Commit

Permalink
Updated documentation
Browse files Browse the repository at this point in the history
- EventQueue documentation
- README documentation
  • Loading branch information
geky committed Aug 10, 2016
2 parents 3338ca1 + fe021da commit 17dfdd5
Show file tree
Hide file tree
Showing 8 changed files with 492 additions and 177 deletions.
127 changes: 89 additions & 38 deletions EventQueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,29 +39,37 @@ namespace events {

/** EventQueue
*
* Flexible event queue
* Flexible event queue for dispatching events
*/
class EventQueue {
public:
/** Create an event queue
/** EventQueue lifetime
*
* @param queue_size Size of buffer to use for events
* (default: EVENTS_QUEUE_SIZE)
* @param queue_pointer Pointer to memory region to use for events
* (default: NULL)
*/
EventQueue(unsigned queue_size=EVENTS_QUEUE_SIZE,
unsigned char *queue_pointer=NULL);

/** Destroy an event queue
* Create and destroy event queues. The event queue either allocates
* a buffer of the specified size with malloc or uses the user provided
* buffer.
*
* @param size Size of buffer to use for events in bytes
* (default to EVENTS_QUEUE_SIZE)
* @param buffer Pointer to buffer to use for events
* (default to NULL)
*/
EventQueue(unsigned size=EVENTS_QUEUE_SIZE, unsigned char *buffer=NULL);
~EventQueue();

/** Dispatch pending events
* @param ms Time to wait for events in milliseconds, 0 will return
* immediately if no events are pending, a negative
* value will dispatch events forever
* (default: -1)
/** Dispatch events
*
* Executes events until the specified milliseconds have passed.
* If ms is negative, the dispatch function will dispatch events
* indefinitely or until break_dispatch is called on this queue.
*
* When called with a finite timeout, the dispatch function is garunteed
* to terminate. When called with a timeout of 0, the dispatch function
* does not wait and is irq safe.
*
* @param ms Time to wait for events in milliseconds, a negative
* value will dispatch events indefinitely
* (default to -1)
*/
void dispatch(int ms);
void dispatch() { dispatch(-1); }
Expand All @@ -73,27 +81,43 @@ class EventQueue {
*/
void break_dispatch();

/* Monotonic counter for the event queue
* @return A monotonically incrementing counter in milliseconds
* this count intentionally overflows to 0 after 2^32-1
/** Millisecond counter
*
* Returns the underlying tick of the event queue represented as the
* number of milliseconds that have passed since an arbitrary point in
* time. Intentionally overflows to 0 after 2^32-1.
*
* @return The underlying tick of the event queue in milliseconds
*/
unsigned tick();

/** Cancel events that are in flight
/** Cancel an in-flight event
*
* Attempts to cancel an event referenced by the unique id returned from
* one of the call functions. It is safe to call cancel after an event
* has already been dispatched.
*
* The cancel function is irq safe.
*
* If event has already been dispatched or does not exist, no error occurs.
* If called while the event queue's dispatch loop is active, the cancel
* function does not garuntee that the event will not execute after it
* returns, as the event may have already begun executing.
*
* @param id Event id to cancel
* @note This can not stop a currently executing event
* @param id Unique id of the event
*/
void cancel(int id);

/** Background an event queue onto a single-shot timer
*
* The provided update function will be called to indicate when the queue
* should be dispatched. A negative timeout will be passed to the update
* function when the timer is no longer needed. A null update function
* will disable the existing timer.
* function when the time is no longer needed.
*
* Passing a null update function disables the existing timre.
*
* The background function allows an event queue to take advantage of
* hardware timers or even other event loops, allowing an event queue to
* be effectively backgrounded.
*
* @param update Function called to indicate when the queue should be
* dispatched
Expand All @@ -103,20 +127,33 @@ class EventQueue {
/** Chain an event queue onto another event queue
*
* After chaining a queue to a target, calling dispatch on the target
* queue will also dispatch events from this queue. The queues will use
* their own buffers and events are handled independently. A null queue
* as the target will unchain the queue.
* queue will also dispatch events from this queue. The queues use
* their own buffers and events must be handled independently.
*
* A null queue as the target will unchain the existing queue.
*
* @param target Queue to chain onto
* The chain function allows multiple event queuest to be composed,
* sharing the context of a dispatch loop while still being managed
* independently
*
* @param target Queue that will dispatch this queue's events as a
* part of its dispatch loop
*/
void chain(EventQueue *target);

/** Post an event to the queue
*
* @param f Function to call on event dispatch
* The specified callback will be executed in the context of the event
* queue's dispatch loop.
*
* The call function is irq safe and can act as a mechanism for moving
* events out of irq contexts.
*
* @param f Function to execute in the context of the dispatch loop
* @param a0..a4 Arguments to pass to the callback
* @return A positive id representing the event in the queue,
* or 0 on failure
* @return A unique id that represents the posted event and can
* be passed to cancel, or an id of 0 if there is not
* enough memory to allocate the event.
*/
template <typename F>
int call(F f) {
Expand Down Expand Up @@ -157,11 +194,18 @@ class EventQueue {

/** Post an event to the queue after a specified delay
*
* @param f Function to call on event dispatch
* The specified callback will be executed in the context of the event
* queue's dispatch loop.
*
* The call_in function is irq safe and can act as a mechanism for moving
* events out of irq contexts.
*
* @param f Function to execute in the context of the dispatch loop
* @param a0..a4 Arguments to pass to the callback
* @param ms Time to delay in milliseconds
* @return A positive id representing the event in the queue,
* or 0 on failure
* @return A unique id that represents the posted event and can
* be passed to cancel, or an id of 0 if there is not
* enough memory to allocate the event.
*/
template <typename F>
int call_in(int ms, F f) {
Expand Down Expand Up @@ -203,11 +247,18 @@ class EventQueue {

/** Post an event to the queue periodically
*
* @param f Function to call on event dispatch
* The specified callback will be executed in the context of the event
* queue's dispatch loop.
*
* The call_every function is irq safe and can act as a mechanism for
* moving events out of irq contexts.
*
* @param f Function to execute in the context of the dispatch loop
* @param a0..a4 Arguments to pass to the callback
* @param ms Period of the event in milliseconds
* @return A positive id representing the event in the queue,
* or 0 on failure
* @return A unique id that represents the posted event and can
* be passed to cancel, or an id of 0 if there is not
* enough memory to allocate the event.
*/
template <typename F>
int call_every(int ms, F f) {
Expand Down
113 changes: 63 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## The Events Library ##
## The mbed-events library ##

The events library provides a flexible event queue for scheduling events.
The mbed-events library provides a flexible queue for scheduling events.

``` cpp
#include "mbed_events.h"
Expand All @@ -15,57 +15,52 @@ int main() {
queue.call_in(2000, printf, "called in 2 seconds\n");
queue.call_every(1000, printf, "called every 1 seconds\n");

// executed by the dispatch method
// events are executed by the dispatch method
queue.dispatch();
}
```

The mbed-events library can be used as a normal event loop, or it can be
backgrounded on a single hardware timer or even another event loop. It is
both thread and irq safe, and provides functions for easily composing
independent event queues.

The mbed-events library can act as a drop-in scheduler, provide synchronization
between multiple threads, or just act as a mechanism for moving events out of
interrupt contexts.

### Usage ###

The core API of the events library is contained in the
[EventQueue](EventQueue.h) class.
The core of the mbed-events library is the [EventQueue](EventQueue.h) class,
which represents a single event queue. The `EventQueue::dispatch` function
runs the queue, providing the context for executing events.

``` cpp
// Creates an event queue with 2048 bytes of buffer space to use
// for enqueueing events. With no argument, the default buffer is
// allocated with enough space for 32 Callback classes.
EventQueue queue(2048);

// Enqueues events on the underlying event queue
queue.call(printf, "hi!\n");

// The dispatch method acts as the core entry point into the event loop
// A millisecond timeout can be provided to return from the event loop
queue.dispatch(500);
// Creates an event queue enough buffer space for 32 Callbacks. This
// is the default if no argument was provided. Alternatively the size
// can just be specified in bytes.
EventQueue queue(32*EVENTS_EVENT_SIZE);

// Events can be posted to the underlying event queue with dynamic
// context allocated from the specified buffer
queue.call(printf, "hello %d %d %d %d\n", 1, 2, 3, 4);
queue.call(Callback<void()>(&serial, &Serial::printf), "hi\n");

// The dispatch function provides the context for the running the queue
// and can take a millisecond timeout to run for a fixed time or to just
// dispatch any pending events
queue.dispatch();
```
Additionally, the events library provides the [EventLoop](EventLoop.h) class,
which combines the EventQueue with a Thread.
``` cpp
// Creates a high priority event loop.
EventLoop loop(osHighPriority);
// Starts the loop in a separate thread
loop.start();
// Posting events is thread and irq safe
loop.call(doit);
// Stops the event loop cleanly
loop.stop();
```

The EventQueue and EvenLoop classes provide several call functions for
sending events. The call functions are thread and irq safe and don't need
the underlying loop to be running.
The EventQueue class provides several call functions for posting events
to the underlying event queue. The call functions are thread and irq safe,
don't need the underlying loop to be running, and provide an easy mechanism
for moving events out of interrupt contexts.
``` cpp
// Simple call function registers events to be called as soon as possible
queue.call(doit);
queue.call(printf, "called immediately\n");
queue.call(Callback<void(char)>(&serial, &Serial::printf), "hello\n");
// The call_in function registers events to be called after a delay
// specified in milliseconds
Expand All @@ -78,30 +73,48 @@ queue.call_every(2000, doit_every_two_seconds);
queue.call_every(400, printf, "called every 0.4 seconds\n");
```

All call calls return an integer id that uniquely represents the event
on the event queue. The call calls can not block, so 0 is returned if
there is no memory or the queue's event size is exceeded.
The call functions return an id that uniquely represents the event in the
the event queue. This id can be passed to `EventQueue::cancel` to cancel
an in-flight event.

``` cpp
// The event id is uniqueue to the queue
// The event id uniquely represents the event in the queue
int id = queue.call_in(100, printf, "will this work?\n");

// An id of 0 indicates an error
// If there was not enough memory necessary to allocate the event,
// an id of 0 is returned from the call functions
if (id) {
error("oh no!");
}

// Events can also be cancelled
// Events can be cancelled as long as they have not been dispatched. If the
// event has already expired, cancel has no side-effects.
queue.cancel(id);
```

Event queuest easily align with module boundaries, where internal state can
be implicitely synchronized through event dispatch. Multiple modules can
use independent event queues, but still be composed through the
`EventQueue::chain` function.

``` cpp
// Create some event queues with pending events
EventQueue a;
a.call(printf, "hello from a!\n");

### Porting ###
EventQueue b;
b.call(printf, "hello from b!\n");

The events library actually provides a C++ and C API. To port to a different
platform, the events library only needs implementations of the following
files:
EventQueue c;
c.call(printf, "hello from c!\n");

// Chain c and b onto a's event queue. Both c and b will be dispatched
// in the context of a's dispatch function.
c.chain(&a);
b.chain(&a);

// Dispatching a will in turn dispatch b and c, printing hello from
// all three queues
a.dispatch();
```

- [events_tick.h](events-c/events_tick.h) - Monotonic counter with millisecond precision
- [events_mutex.h](events-c/events_mutex.h) - IRQ safe critical section
- [events_sema.h](events-c/events_sema.h) - Binary semaphore with timeout
Loading

0 comments on commit 17dfdd5

Please sign in to comment.