diff --git a/TESTS/events/queue/main.cpp b/TESTS/events/queue/main.cpp new file mode 100644 index 0000000..f973e7e --- /dev/null +++ b/TESTS/events/queue/main.cpp @@ -0,0 +1,267 @@ +#include "mbed_events.h" +#include "mbed.h" +#include "rtos.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" + +using namespace utest::v1; + + +// flag for called +volatile bool touched = false; + +// static functions +void func5(int a0, int a1, int a2, int a3, int a4) { + touched = true; + TEST_ASSERT_EQUAL(a0 | a1 | a2 | a3 | a4, 0x1f); +} + +void func4(int a0, int a1, int a2, int a3) { + touched = true; + TEST_ASSERT_EQUAL(a0 | a1 | a2 | a3, 0xf); +} + +void func3(int a0, int a1, int a2) { + touched = true; + TEST_ASSERT_EQUAL(a0 | a1 | a2, 0x7); +} + +void func2(int a0, int a1) { + touched = true; + TEST_ASSERT_EQUAL(a0 | a1, 0x3); +} + +void func1(int a0) { + touched = true; + TEST_ASSERT_EQUAL(a0, 0x1); +} + +void func0() { + touched = true; +} + +#define SIMPLE_POSTS_TEST(i, ...) \ +void simple_posts_test##i() { \ + EventQueue queue; \ + \ + touched = false; \ + queue.call(func##i,##__VA_ARGS__); \ + queue.dispatch(0); \ + TEST_ASSERT(touched); \ + \ + touched = false; \ + queue.call_in(1, func##i,##__VA_ARGS__); \ + queue.dispatch(2); \ + TEST_ASSERT(touched); \ + \ + touched = false; \ + queue.call_every(1, func##i,##__VA_ARGS__); \ + queue.dispatch(2); \ + TEST_ASSERT(touched); \ +} + +SIMPLE_POSTS_TEST(5, 0x01, 0x02, 0x04, 0x08, 0x010) +SIMPLE_POSTS_TEST(4, 0x01, 0x02, 0x04, 0x08) +SIMPLE_POSTS_TEST(3, 0x01, 0x02, 0x04) +SIMPLE_POSTS_TEST(2, 0x01, 0x02) +SIMPLE_POSTS_TEST(1, 0x01) +SIMPLE_POSTS_TEST(0) + + +void time_func(Timer *t, int ms) { + TEST_ASSERT_INT_WITHIN(2, ms, t->read_ms()); + t->reset(); +} + +template +void call_in_test() { + Timer tickers[N]; + + EventQueue queue; + + for (int i = 0; i < N; i++) { + tickers[i].start(); + queue.call_in((i+1)*100, time_func, &tickers[i], (i+1)*100); + } + + queue.dispatch(N*100); +} + +template +void call_every_test() { + Timer tickers[N]; + + EventQueue queue; + + for (int i = 0; i < N; i++) { + tickers[i].start(); + queue.call_every((i+1)*100, time_func, &tickers[i], (i+1)*100); + } + + queue.dispatch(N*100); +} + +struct big { char data[1024]; } big; + +void allocate_failure_test1() { + EventQueue queue(32); + int id = queue.call((void (*)(struct big))0, big); + TEST_ASSERT(!id); +} + +void allocate_failure_test2() { + EventQueue queue; + int id; + + for (int i = 0; i < 100; i++) { + id = queue.call((void (*)())0); + } + + TEST_ASSERT(!id); +} + +void no() { + TEST_ASSERT(false); +} + +template +void cancel_test1() { + EventQueue queue; + + int ids[N]; + + for (int i = 0; i < N; i++) { + ids[i] = queue.call_in(1000, no); + } + + for (int i = N-1; i >= 0; i--) { + queue.cancel(ids[i]); + } + + queue.dispatch(0); +} + + +// Testing the dynamic arguments to the event class +unsigned counter = 0; + +void count5(unsigned a0, unsigned a1, unsigned a2, unsigned a3, unsigned a5) { + counter += a0 + a1 + a2 + a3 + a5; +} + +void count4(unsigned a0, unsigned a1, unsigned a2, unsigned a3) { + counter += a0 + a1 + a2 + a3; +} + +void count3(unsigned a0, unsigned a1, unsigned a2) { + counter += a0 + a1 + a2; +} + +void count2(unsigned a0, unsigned a1) { + counter += a0 + a1; +} + +void count1(unsigned a0) { + counter += a0; +} + +void count0() { + counter += 0; +} + +void event_class_test() { + counter = 0; + EventQueue queue(2048); + + Event e5(&queue, count5); + Event e4(&queue, count5, 1); + Event e3(&queue, count5, 1, 1); + Event e2(&queue, count5, 1, 1, 1); + Event e1(&queue, count5, 1, 1, 1, 1); + Event e0(&queue, count5, 1, 1, 1, 1, 1); + + e5.post(1, 1, 1, 1, 1); + e4.post(1, 1, 1, 1); + e3.post(1, 1, 1); + e2.post(1, 1); + e1.post(1); + e0.post(); + + queue.dispatch(0); + + TEST_ASSERT_EQUAL(counter, 30); +} + +void event_class_helper_test() { + counter = 0; + EventQueue queue(2048); + + Event e5 = queue.event(count5, 1, 1, 1, 1, 1); + Event e4 = queue.event(count4, 1, 1, 1, 1); + Event e3 = queue.event(count3, 1, 1, 1); + Event e2 = queue.event(count2, 1, 1); + Event e1 = queue.event(count1, 1); + Event e0 = queue.event(count0); + + e5.post(); + e4.post(); + e3.post(); + e2.post(); + e1.post(); + e0.post(); + + queue.dispatch(0); + + TEST_ASSERT_EQUAL(counter, 15); +} + +void event_inference_test() { + counter = 0; + EventQueue queue (2048); + + queue.event(count5, 1, 1, 1, 1, 1).post(); + queue.event(count5, 1, 1, 1, 1).post(1); + queue.event(count5, 1, 1, 1).post(1, 1); + queue.event(count5, 1, 1).post(1, 1, 1); + queue.event(count5, 1).post(1, 1, 1, 1); + queue.event(count5).post(1, 1, 1, 1, 1); + + queue.dispatch(0); + + TEST_ASSERT_EQUAL(counter, 30); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(20, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +const Case cases[] = { + Case("Testing calls with 5 args", simple_posts_test5), + Case("Testing calls with 4 args", simple_posts_test4), + Case("Testing calls with 3 args", simple_posts_test3), + Case("Testing calls with 2 args", simple_posts_test2), + Case("Testing calls with 1 args", simple_posts_test1), + Case("Testing calls with 0 args", simple_posts_test0), + + Case("Testing call_in", call_in_test<20>), + Case("Testing call_every", call_every_test<20>), + + Case("Testing allocate failure 1", allocate_failure_test1), + Case("Testing allocate failure 2", allocate_failure_test2), + + Case("Testing event cancel 1", cancel_test1<20>), + Case("Testing the event class", event_class_test), + Case("Testing the event class helpers", event_class_helper_test), + Case("Testing the event inference", event_inference_test), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} + diff --git a/events/Event.h b/events/Event.h new file mode 100644 index 0000000..bcf68f9 --- /dev/null +++ b/events/Event.h @@ -0,0 +1,3313 @@ +/* events + * Copyright (c) 2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef EVENT_H +#define EVENT_H + +#include "EventQueue.h" +#include "mbed_assert.h" + +namespace events { + +/** Event + * + * Representation of an event for fine-grain dispatch control + */ +template +class Event; + +/** Event + * + * Representation of an event for fine-grain dispatch control + */ +template <> +class Event { +public: + /** Create an event + * + * Constructs an event bound to the specified event queue. The specified + * callback acts as the target for the event and is executed in the + * context of the event queue's dispatch loop once posted. + * + * @param q Event queue to dispatch on + * @param f Function to execute when the event is dispatched + * @param a0..a4 Arguments to pass to the callback + */ + template + Event(EventQueue *q, F f) { + struct local { + static int post(struct event *e) { + typedef EventQueue::context00 C; + struct local { + static void call(void *p) { (*static_cast(p))(); } + static void dtor(void *p) { static_cast(p)->~C(); } + }; + + void *p = equeue_alloc(e->equeue, sizeof(C)); + if (!p) { + return 0; + } + + new (p) C(*reinterpret_cast(e+1)); + equeue_event_delay(p, e->delay); + equeue_event_period(p, e->period); + equeue_event_dtor(p, &local::dtor); + return equeue_post(e->equeue, &local::call, p); + } + + static void dtor(struct event *e) { + reinterpret_cast(e+1)->~F(); + } + }; + + _event = static_cast( + equeue_alloc(&q->_equeue, sizeof(struct event) + sizeof(F))); + if (_event) { + _event->equeue = &q->_equeue; + _event->id = 0; + _event->delay = 0; + _event->period = -1; + + _event->post = &local::post; + _event->dtor = &local::dtor; + + new (_event+1) F(f); + + _event->ref = 1; + } + } + + /** Copy constructor for events + */ + Event(const Event &e) { + _event = 0; + if (e._event) { + _event = e._event; + _event->ref += 1; + } + } + + /** Assignment operator for events + */ + Event &operator=(const Event &that) { + if (this != &that) { + this->~Event(); + new (this) Event(that); + } + + return *this; + } + + /** Destructor for events + */ + ~Event() { + if (_event) { + _event->ref -= 1; + if (_event->ref == 0) { + _event->dtor(_event); + equeue_dealloc(_event->equeue, _event); + } + } + } + + /** Configure the delay of an event + * + * @param delay Millisecond delay before dispatching the event + */ + void delay(int delay) { + if (_event) { + _event->delay = delay; + } + } + + /** Configure the period of an event + * + * @param period Millisecond period for repeatedly dispatching an event + */ + void period(int period) { + if (_event) { + _event->period = period; + } + } + + /** Posts an event onto the underlying event queue + * + * The event is posted to the underlying queue and is executed in the + * context of the event queue's dispatch loop. + * + * The post function is irq safe and can act as a mechanism for moving + * events out of irq contexts. + * + * @param a0..a4 Arguments to pass to the event + * @return A unique id that represents the posted event and can + * be passed to EventQueue::cancel, or an id of 0 if + * there is not enough memory to allocate the event. + */ + int post() const { + if (!_event) { + return 0; + } + + _event->id = _event->post(_event); + return _event->id; + } + + /** Posts an event onto the underlying event queue, returning void + * + * @param a0..a4 Arguments to pass to the event + */ + void call() const { + int id = post(); + MBED_ASSERT(id); + } + + /** Posts an event onto the underlying event queue, returning void + * + * @param a0..a4 Arguments to pass to the event + */ + void operator()() const { + return call(); + } + + /** Static thunk for passing as C-style function + * + * @param func Event to call passed as a void pointer + * @param a0..a4 Arguments to pass to the event + */ + static void thunk(void *func) { + return static_cast(func)->call(); + } + + /** Cancels the most recently posted event + * + * Attempts to cancel the most recently posted event. It is safe to call + * cancel after an event has already been dispatched. + * + * The cancel function is irq safe. + * + * 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. + */ + void cancel() const { + if (_event) { + equeue_cancel(_event->equeue, _event->id); + } + } + +private: + struct event { + unsigned ref; + equeue_t *equeue; + int id; + + int delay; + int period; + + int (*post)(struct event *); + void (*dtor)(struct event *); + + // F follows + } *_event; + +public: + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0) { + new (this) Event(q, EventQueue::context10(f, c0)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1) { + new (this) Event(q, EventQueue::context20(f, c0, c1)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2) { + new (this) Event(q, EventQueue::context30(f, c0, c1, c2)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2, C3 c3) { + new (this) Event(q, EventQueue::context40(f, c0, c1, c2, c3)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + new (this) Event(q, EventQueue::context50(f, c0, c1, c2, c3, c4)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0), B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0) const, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0) volatile, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0) const volatile, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1), B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1) const, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1) volatile, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1) const volatile, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2), B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2) const, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2) volatile, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2) const volatile, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, B3), B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, B3) const, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, B3) volatile, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, B3) const volatile, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, B3, B4), B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, B3, B4) const, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4) volatile, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4) const volatile, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } +}; + +/** Event + * + * Representation of an event for fine-grain dispatch control + */ +template +class Event { +public: + /** Create an event + * + * Constructs an event bound to the specified event queue. The specified + * callback acts as the target for the event and is executed in the + * context of the event queue's dispatch loop once posted. + * + * @param q Event queue to dispatch on + * @param f Function to execute when the event is dispatched + * @param a0..a4 Arguments to pass to the callback + */ + template + Event(EventQueue *q, F f) { + struct local { + static int post(struct event *e, A0 a0) { + typedef EventQueue::context10 C; + struct local { + static void call(void *p) { (*static_cast(p))(); } + static void dtor(void *p) { static_cast(p)->~C(); } + }; + + void *p = equeue_alloc(e->equeue, sizeof(C)); + if (!p) { + return 0; + } + + new (p) C(*reinterpret_cast(e+1), a0); + equeue_event_delay(p, e->delay); + equeue_event_period(p, e->period); + equeue_event_dtor(p, &local::dtor); + return equeue_post(e->equeue, &local::call, p); + } + + static void dtor(struct event *e) { + reinterpret_cast(e+1)->~F(); + } + }; + + _event = static_cast( + equeue_alloc(&q->_equeue, sizeof(struct event) + sizeof(F))); + if (_event) { + _event->equeue = &q->_equeue; + _event->id = 0; + _event->delay = 0; + _event->period = -1; + + _event->post = &local::post; + _event->dtor = &local::dtor; + + new (_event+1) F(f); + + _event->ref = 1; + } + } + + /** Copy constructor for events + */ + Event(const Event &e) { + _event = 0; + if (e._event) { + _event = e._event; + _event->ref += 1; + } + } + + /** Assignment operator for events + */ + Event &operator=(const Event &that) { + if (this != &that) { + this->~Event(); + new (this) Event(that); + } + + return *this; + } + + /** Destructor for events + */ + ~Event() { + if (_event) { + _event->ref -= 1; + if (_event->ref == 0) { + _event->dtor(_event); + equeue_dealloc(_event->equeue, _event); + } + } + } + + /** Configure the delay of an event + * + * @param delay Millisecond delay before dispatching the event + */ + void delay(int delay) { + if (_event) { + _event->delay = delay; + } + } + + /** Configure the period of an event + * + * @param period Millisecond period for repeatedly dispatching an event + */ + void period(int period) { + if (_event) { + _event->period = period; + } + } + + /** Posts an event onto the underlying event queue + * + * The event is posted to the underlying queue and is executed in the + * context of the event queue's dispatch loop. + * + * The post function is irq safe and can act as a mechanism for moving + * events out of irq contexts. + * + * @param a0..a4 Arguments to pass to the event + * @return A unique id that represents the posted event and can + * be passed to EventQueue::cancel, or an id of 0 if + * there is not enough memory to allocate the event. + */ + int post(A0 a0) const { + if (!_event) { + return 0; + } + + _event->id = _event->post(_event, a0); + return _event->id; + } + + /** Posts an event onto the underlying event queue, returning void + * + * @param a0..a4 Arguments to pass to the event + */ + void call(A0 a0) const { + int id = post(a0); + MBED_ASSERT(id); + } + + /** Posts an event onto the underlying event queue, returning void + * + * @param a0..a4 Arguments to pass to the event + */ + void operator()(A0 a0) const { + return call(a0); + } + + /** Static thunk for passing as C-style function + * + * @param func Event to call passed as a void pointer + * @param a0..a4 Arguments to pass to the event + */ + static void thunk(void *func, A0 a0) { + return static_cast(func)->call(a0); + } + + /** Cancels the most recently posted event + * + * Attempts to cancel the most recently posted event. It is safe to call + * cancel after an event has already been dispatched. + * + * The cancel function is irq safe. + * + * 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. + */ + void cancel() const { + if (_event) { + equeue_cancel(_event->equeue, _event->id); + } + } + +private: + struct event { + unsigned ref; + equeue_t *equeue; + int id; + + int delay; + int period; + + int (*post)(struct event *, A0 a0); + void (*dtor)(struct event *); + + // F follows + } *_event; + +public: + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0) { + new (this) Event(q, EventQueue::context11(f, c0)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1) { + new (this) Event(q, EventQueue::context21(f, c0, c1)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2) { + new (this) Event(q, EventQueue::context31(f, c0, c1, c2)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2, C3 c3) { + new (this) Event(q, EventQueue::context41(f, c0, c1, c2, c3)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + new (this) Event(q, EventQueue::context51(f, c0, c1, c2, c3, c4)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, A0), B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, A0) const, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, A0) volatile, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, A0) const volatile, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, A0), B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, A0) const, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, A0) volatile, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, A0) const volatile, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, A0), B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, A0) const, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, A0) volatile, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, A0) const volatile, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, B3, A0), B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, B3, A0) const, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0) volatile, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0) const volatile, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0), B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0) const, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0) volatile, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0) const volatile, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } +}; + +/** Event + * + * Representation of an event for fine-grain dispatch control + */ +template +class Event { +public: + /** Create an event + * + * Constructs an event bound to the specified event queue. The specified + * callback acts as the target for the event and is executed in the + * context of the event queue's dispatch loop once posted. + * + * @param q Event queue to dispatch on + * @param f Function to execute when the event is dispatched + * @param a0..a4 Arguments to pass to the callback + */ + template + Event(EventQueue *q, F f) { + struct local { + static int post(struct event *e, A0 a0, A1 a1) { + typedef EventQueue::context20 C; + struct local { + static void call(void *p) { (*static_cast(p))(); } + static void dtor(void *p) { static_cast(p)->~C(); } + }; + + void *p = equeue_alloc(e->equeue, sizeof(C)); + if (!p) { + return 0; + } + + new (p) C(*reinterpret_cast(e+1), a0, a1); + equeue_event_delay(p, e->delay); + equeue_event_period(p, e->period); + equeue_event_dtor(p, &local::dtor); + return equeue_post(e->equeue, &local::call, p); + } + + static void dtor(struct event *e) { + reinterpret_cast(e+1)->~F(); + } + }; + + _event = static_cast( + equeue_alloc(&q->_equeue, sizeof(struct event) + sizeof(F))); + if (_event) { + _event->equeue = &q->_equeue; + _event->id = 0; + _event->delay = 0; + _event->period = -1; + + _event->post = &local::post; + _event->dtor = &local::dtor; + + new (_event+1) F(f); + + _event->ref = 1; + } + } + + /** Copy constructor for events + */ + Event(const Event &e) { + _event = 0; + if (e._event) { + _event = e._event; + _event->ref += 1; + } + } + + /** Assignment operator for events + */ + Event &operator=(const Event &that) { + if (this != &that) { + this->~Event(); + new (this) Event(that); + } + + return *this; + } + + /** Destructor for events + */ + ~Event() { + if (_event) { + _event->ref -= 1; + if (_event->ref == 0) { + _event->dtor(_event); + equeue_dealloc(_event->equeue, _event); + } + } + } + + /** Configure the delay of an event + * + * @param delay Millisecond delay before dispatching the event + */ + void delay(int delay) { + if (_event) { + _event->delay = delay; + } + } + + /** Configure the period of an event + * + * @param period Millisecond period for repeatedly dispatching an event + */ + void period(int period) { + if (_event) { + _event->period = period; + } + } + + /** Posts an event onto the underlying event queue + * + * The event is posted to the underlying queue and is executed in the + * context of the event queue's dispatch loop. + * + * The post function is irq safe and can act as a mechanism for moving + * events out of irq contexts. + * + * @param a0..a4 Arguments to pass to the event + * @return A unique id that represents the posted event and can + * be passed to EventQueue::cancel, or an id of 0 if + * there is not enough memory to allocate the event. + */ + int post(A0 a0, A1 a1) const { + if (!_event) { + return 0; + } + + _event->id = _event->post(_event, a0, a1); + return _event->id; + } + + /** Posts an event onto the underlying event queue, returning void + * + * @param a0..a4 Arguments to pass to the event + */ + void call(A0 a0, A1 a1) const { + int id = post(a0, a1); + MBED_ASSERT(id); + } + + /** Posts an event onto the underlying event queue, returning void + * + * @param a0..a4 Arguments to pass to the event + */ + void operator()(A0 a0, A1 a1) const { + return call(a0, a1); + } + + /** Static thunk for passing as C-style function + * + * @param func Event to call passed as a void pointer + * @param a0..a4 Arguments to pass to the event + */ + static void thunk(void *func, A0 a0, A1 a1) { + return static_cast(func)->call(a0, a1); + } + + /** Cancels the most recently posted event + * + * Attempts to cancel the most recently posted event. It is safe to call + * cancel after an event has already been dispatched. + * + * The cancel function is irq safe. + * + * 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. + */ + void cancel() const { + if (_event) { + equeue_cancel(_event->equeue, _event->id); + } + } + +private: + struct event { + unsigned ref; + equeue_t *equeue; + int id; + + int delay; + int period; + + int (*post)(struct event *, A0 a0, A1 a1); + void (*dtor)(struct event *); + + // F follows + } *_event; + +public: + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0) { + new (this) Event(q, EventQueue::context12(f, c0)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1) { + new (this) Event(q, EventQueue::context22(f, c0, c1)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2) { + new (this) Event(q, EventQueue::context32(f, c0, c1, c2)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2, C3 c3) { + new (this) Event(q, EventQueue::context42(f, c0, c1, c2, c3)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + new (this) Event(q, EventQueue::context52(f, c0, c1, c2, c3, c4)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, A0, A1), B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, A0, A1) const, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, A0, A1) volatile, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, A0, A1) const volatile, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, A0, A1), B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, A0, A1) const, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, A0, A1) volatile, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, A0, A1) const volatile, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, A0, A1), B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, A0, A1) const, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1) volatile, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1) const volatile, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1), B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1) const, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1) volatile, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1) const volatile, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1), B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1) const, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1) volatile, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1) const volatile, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } +}; + +/** Event + * + * Representation of an event for fine-grain dispatch control + */ +template +class Event { +public: + /** Create an event + * + * Constructs an event bound to the specified event queue. The specified + * callback acts as the target for the event and is executed in the + * context of the event queue's dispatch loop once posted. + * + * @param q Event queue to dispatch on + * @param f Function to execute when the event is dispatched + * @param a0..a4 Arguments to pass to the callback + */ + template + Event(EventQueue *q, F f) { + struct local { + static int post(struct event *e, A0 a0, A1 a1, A2 a2) { + typedef EventQueue::context30 C; + struct local { + static void call(void *p) { (*static_cast(p))(); } + static void dtor(void *p) { static_cast(p)->~C(); } + }; + + void *p = equeue_alloc(e->equeue, sizeof(C)); + if (!p) { + return 0; + } + + new (p) C(*reinterpret_cast(e+1), a0, a1, a2); + equeue_event_delay(p, e->delay); + equeue_event_period(p, e->period); + equeue_event_dtor(p, &local::dtor); + return equeue_post(e->equeue, &local::call, p); + } + + static void dtor(struct event *e) { + reinterpret_cast(e+1)->~F(); + } + }; + + _event = static_cast( + equeue_alloc(&q->_equeue, sizeof(struct event) + sizeof(F))); + if (_event) { + _event->equeue = &q->_equeue; + _event->id = 0; + _event->delay = 0; + _event->period = -1; + + _event->post = &local::post; + _event->dtor = &local::dtor; + + new (_event+1) F(f); + + _event->ref = 1; + } + } + + /** Copy constructor for events + */ + Event(const Event &e) { + _event = 0; + if (e._event) { + _event = e._event; + _event->ref += 1; + } + } + + /** Assignment operator for events + */ + Event &operator=(const Event &that) { + if (this != &that) { + this->~Event(); + new (this) Event(that); + } + + return *this; + } + + /** Destructor for events + */ + ~Event() { + if (_event) { + _event->ref -= 1; + if (_event->ref == 0) { + _event->dtor(_event); + equeue_dealloc(_event->equeue, _event); + } + } + } + + /** Configure the delay of an event + * + * @param delay Millisecond delay before dispatching the event + */ + void delay(int delay) { + if (_event) { + _event->delay = delay; + } + } + + /** Configure the period of an event + * + * @param period Millisecond period for repeatedly dispatching an event + */ + void period(int period) { + if (_event) { + _event->period = period; + } + } + + /** Posts an event onto the underlying event queue + * + * The event is posted to the underlying queue and is executed in the + * context of the event queue's dispatch loop. + * + * The post function is irq safe and can act as a mechanism for moving + * events out of irq contexts. + * + * @param a0..a4 Arguments to pass to the event + * @return A unique id that represents the posted event and can + * be passed to EventQueue::cancel, or an id of 0 if + * there is not enough memory to allocate the event. + */ + int post(A0 a0, A1 a1, A2 a2) const { + if (!_event) { + return 0; + } + + _event->id = _event->post(_event, a0, a1, a2); + return _event->id; + } + + /** Posts an event onto the underlying event queue, returning void + * + * @param a0..a4 Arguments to pass to the event + */ + void call(A0 a0, A1 a1, A2 a2) const { + int id = post(a0, a1, a2); + MBED_ASSERT(id); + } + + /** Posts an event onto the underlying event queue, returning void + * + * @param a0..a4 Arguments to pass to the event + */ + void operator()(A0 a0, A1 a1, A2 a2) const { + return call(a0, a1, a2); + } + + /** Static thunk for passing as C-style function + * + * @param func Event to call passed as a void pointer + * @param a0..a4 Arguments to pass to the event + */ + static void thunk(void *func, A0 a0, A1 a1, A2 a2) { + return static_cast(func)->call(a0, a1, a2); + } + + /** Cancels the most recently posted event + * + * Attempts to cancel the most recently posted event. It is safe to call + * cancel after an event has already been dispatched. + * + * The cancel function is irq safe. + * + * 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. + */ + void cancel() const { + if (_event) { + equeue_cancel(_event->equeue, _event->id); + } + } + +private: + struct event { + unsigned ref; + equeue_t *equeue; + int id; + + int delay; + int period; + + int (*post)(struct event *, A0 a0, A1 a1, A2 a2); + void (*dtor)(struct event *); + + // F follows + } *_event; + +public: + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0) { + new (this) Event(q, EventQueue::context13(f, c0)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1) { + new (this) Event(q, EventQueue::context23(f, c0, c1)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2) { + new (this) Event(q, EventQueue::context33(f, c0, c1, c2)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2, C3 c3) { + new (this) Event(q, EventQueue::context43(f, c0, c1, c2, c3)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + new (this) Event(q, EventQueue::context53(f, c0, c1, c2, c3, c4)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, A0, A1, A2), B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, A0, A1, A2) const, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, A0, A1, A2) volatile, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, A0, A1, A2) const volatile, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, A0, A1, A2), B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, A0, A1, A2) const, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2) volatile, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2) const volatile, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2), B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2) const, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2) volatile, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2) const volatile, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2), B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2) const, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2) volatile, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2) const volatile, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2), B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2) const, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2) volatile, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2) const volatile, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } +}; + +/** Event + * + * Representation of an event for fine-grain dispatch control + */ +template +class Event { +public: + /** Create an event + * + * Constructs an event bound to the specified event queue. The specified + * callback acts as the target for the event and is executed in the + * context of the event queue's dispatch loop once posted. + * + * @param q Event queue to dispatch on + * @param f Function to execute when the event is dispatched + * @param a0..a4 Arguments to pass to the callback + */ + template + Event(EventQueue *q, F f) { + struct local { + static int post(struct event *e, A0 a0, A1 a1, A2 a2, A3 a3) { + typedef EventQueue::context40 C; + struct local { + static void call(void *p) { (*static_cast(p))(); } + static void dtor(void *p) { static_cast(p)->~C(); } + }; + + void *p = equeue_alloc(e->equeue, sizeof(C)); + if (!p) { + return 0; + } + + new (p) C(*reinterpret_cast(e+1), a0, a1, a2, a3); + equeue_event_delay(p, e->delay); + equeue_event_period(p, e->period); + equeue_event_dtor(p, &local::dtor); + return equeue_post(e->equeue, &local::call, p); + } + + static void dtor(struct event *e) { + reinterpret_cast(e+1)->~F(); + } + }; + + _event = static_cast( + equeue_alloc(&q->_equeue, sizeof(struct event) + sizeof(F))); + if (_event) { + _event->equeue = &q->_equeue; + _event->id = 0; + _event->delay = 0; + _event->period = -1; + + _event->post = &local::post; + _event->dtor = &local::dtor; + + new (_event+1) F(f); + + _event->ref = 1; + } + } + + /** Copy constructor for events + */ + Event(const Event &e) { + _event = 0; + if (e._event) { + _event = e._event; + _event->ref += 1; + } + } + + /** Assignment operator for events + */ + Event &operator=(const Event &that) { + if (this != &that) { + this->~Event(); + new (this) Event(that); + } + + return *this; + } + + /** Destructor for events + */ + ~Event() { + if (_event) { + _event->ref -= 1; + if (_event->ref == 0) { + _event->dtor(_event); + equeue_dealloc(_event->equeue, _event); + } + } + } + + /** Configure the delay of an event + * + * @param delay Millisecond delay before dispatching the event + */ + void delay(int delay) { + if (_event) { + _event->delay = delay; + } + } + + /** Configure the period of an event + * + * @param period Millisecond period for repeatedly dispatching an event + */ + void period(int period) { + if (_event) { + _event->period = period; + } + } + + /** Posts an event onto the underlying event queue + * + * The event is posted to the underlying queue and is executed in the + * context of the event queue's dispatch loop. + * + * The post function is irq safe and can act as a mechanism for moving + * events out of irq contexts. + * + * @param a0..a4 Arguments to pass to the event + * @return A unique id that represents the posted event and can + * be passed to EventQueue::cancel, or an id of 0 if + * there is not enough memory to allocate the event. + */ + int post(A0 a0, A1 a1, A2 a2, A3 a3) const { + if (!_event) { + return 0; + } + + _event->id = _event->post(_event, a0, a1, a2, a3); + return _event->id; + } + + /** Posts an event onto the underlying event queue, returning void + * + * @param a0..a4 Arguments to pass to the event + */ + void call(A0 a0, A1 a1, A2 a2, A3 a3) const { + int id = post(a0, a1, a2, a3); + MBED_ASSERT(id); + } + + /** Posts an event onto the underlying event queue, returning void + * + * @param a0..a4 Arguments to pass to the event + */ + void operator()(A0 a0, A1 a1, A2 a2, A3 a3) const { + return call(a0, a1, a2, a3); + } + + /** Static thunk for passing as C-style function + * + * @param func Event to call passed as a void pointer + * @param a0..a4 Arguments to pass to the event + */ + static void thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3) { + return static_cast(func)->call(a0, a1, a2, a3); + } + + /** Cancels the most recently posted event + * + * Attempts to cancel the most recently posted event. It is safe to call + * cancel after an event has already been dispatched. + * + * The cancel function is irq safe. + * + * 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. + */ + void cancel() const { + if (_event) { + equeue_cancel(_event->equeue, _event->id); + } + } + +private: + struct event { + unsigned ref; + equeue_t *equeue; + int id; + + int delay; + int period; + + int (*post)(struct event *, A0 a0, A1 a1, A2 a2, A3 a3); + void (*dtor)(struct event *); + + // F follows + } *_event; + +public: + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0) { + new (this) Event(q, EventQueue::context14(f, c0)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1) { + new (this) Event(q, EventQueue::context24(f, c0, c1)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2) { + new (this) Event(q, EventQueue::context34(f, c0, c1, c2)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2, C3 c3) { + new (this) Event(q, EventQueue::context44(f, c0, c1, c2, c3)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + new (this) Event(q, EventQueue::context54(f, c0, c1, c2, c3, c4)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, A0, A1, A2, A3), B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, A0, A1, A2, A3) const, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3) volatile, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3) const volatile, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3), B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3) const, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3) volatile, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3) const volatile, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3), B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3) const, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3) volatile, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3) const volatile, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3), B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3) const, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3) volatile, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3) const volatile, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3), B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3) const, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3) volatile, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3) const volatile, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } +}; + +/** Event + * + * Representation of an event for fine-grain dispatch control + */ +template +class Event { +public: + /** Create an event + * + * Constructs an event bound to the specified event queue. The specified + * callback acts as the target for the event and is executed in the + * context of the event queue's dispatch loop once posted. + * + * @param q Event queue to dispatch on + * @param f Function to execute when the event is dispatched + * @param a0..a4 Arguments to pass to the callback + */ + template + Event(EventQueue *q, F f) { + struct local { + static int post(struct event *e, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + typedef EventQueue::context50 C; + struct local { + static void call(void *p) { (*static_cast(p))(); } + static void dtor(void *p) { static_cast(p)->~C(); } + }; + + void *p = equeue_alloc(e->equeue, sizeof(C)); + if (!p) { + return 0; + } + + new (p) C(*reinterpret_cast(e+1), a0, a1, a2, a3, a4); + equeue_event_delay(p, e->delay); + equeue_event_period(p, e->period); + equeue_event_dtor(p, &local::dtor); + return equeue_post(e->equeue, &local::call, p); + } + + static void dtor(struct event *e) { + reinterpret_cast(e+1)->~F(); + } + }; + + _event = static_cast( + equeue_alloc(&q->_equeue, sizeof(struct event) + sizeof(F))); + if (_event) { + _event->equeue = &q->_equeue; + _event->id = 0; + _event->delay = 0; + _event->period = -1; + + _event->post = &local::post; + _event->dtor = &local::dtor; + + new (_event+1) F(f); + + _event->ref = 1; + } + } + + /** Copy constructor for events + */ + Event(const Event &e) { + _event = 0; + if (e._event) { + _event = e._event; + _event->ref += 1; + } + } + + /** Assignment operator for events + */ + Event &operator=(const Event &that) { + if (this != &that) { + this->~Event(); + new (this) Event(that); + } + + return *this; + } + + /** Destructor for events + */ + ~Event() { + if (_event) { + _event->ref -= 1; + if (_event->ref == 0) { + _event->dtor(_event); + equeue_dealloc(_event->equeue, _event); + } + } + } + + /** Configure the delay of an event + * + * @param delay Millisecond delay before dispatching the event + */ + void delay(int delay) { + if (_event) { + _event->delay = delay; + } + } + + /** Configure the period of an event + * + * @param period Millisecond period for repeatedly dispatching an event + */ + void period(int period) { + if (_event) { + _event->period = period; + } + } + + /** Posts an event onto the underlying event queue + * + * The event is posted to the underlying queue and is executed in the + * context of the event queue's dispatch loop. + * + * The post function is irq safe and can act as a mechanism for moving + * events out of irq contexts. + * + * @param a0..a4 Arguments to pass to the event + * @return A unique id that represents the posted event and can + * be passed to EventQueue::cancel, or an id of 0 if + * there is not enough memory to allocate the event. + */ + int post(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) const { + if (!_event) { + return 0; + } + + _event->id = _event->post(_event, a0, a1, a2, a3, a4); + return _event->id; + } + + /** Posts an event onto the underlying event queue, returning void + * + * @param a0..a4 Arguments to pass to the event + */ + void call(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) const { + int id = post(a0, a1, a2, a3, a4); + MBED_ASSERT(id); + } + + /** Posts an event onto the underlying event queue, returning void + * + * @param a0..a4 Arguments to pass to the event + */ + void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) const { + return call(a0, a1, a2, a3, a4); + } + + /** Static thunk for passing as C-style function + * + * @param func Event to call passed as a void pointer + * @param a0..a4 Arguments to pass to the event + */ + static void thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return static_cast(func)->call(a0, a1, a2, a3, a4); + } + + /** Cancels the most recently posted event + * + * Attempts to cancel the most recently posted event. It is safe to call + * cancel after an event has already been dispatched. + * + * The cancel function is irq safe. + * + * 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. + */ + void cancel() const { + if (_event) { + equeue_cancel(_event->equeue, _event->id); + } + } + +private: + struct event { + unsigned ref; + equeue_t *equeue; + int id; + + int delay; + int period; + + int (*post)(struct event *, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4); + void (*dtor)(struct event *); + + // F follows + } *_event; + +public: + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0) { + new (this) Event(q, EventQueue::context15(f, c0)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1) { + new (this) Event(q, EventQueue::context25(f, c0, c1)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2) { + new (this) Event(q, EventQueue::context35(f, c0, c1, c2)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2, C3 c3) { + new (this) Event(q, EventQueue::context45(f, c0, c1, c2, c3)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + new (this) Event(q, EventQueue::context55(f, c0, c1, c2, c3, c4)); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4), B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4) const, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4) volatile, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4) const volatile, B0 b0) { + new (this) Event(q, mbed::callback(obj, method), b0); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4), B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4) const, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4) volatile, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4) const volatile, B0 b0, B1 b1) { + new (this) Event(q, mbed::callback(obj, method), b0, b1); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4), B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4) const, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4) volatile, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4) const volatile, B0 b0, B1 b1, B2 b2) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4), B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4) const, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4) volatile, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4) const volatile, B0 b0, B1 b1, B2 b2, B3 b3) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4), B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4) const, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4) volatile, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } + + /** Create an event + * @see Event::Event + */ + template + Event(EventQueue *q, const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4) const volatile, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) { + new (this) Event(q, mbed::callback(obj, method), b0, b1, b2, b3, b4); + } +}; + + + +// Convenience functions declared here to avoid cyclic +// dependency between Event and EventQueue +template +Event EventQueue::event(R (*func)()) { + return Event(this, func); +} + +template +Event EventQueue::event(T *obj, R (T::*method)()) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)() const) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)() volatile) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)() const volatile) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(R (*func)(B0), C0 c0) { + return Event(this, func, c0); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0), C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0) const, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0) volatile, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0) const volatile, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(R (*func)(B0, B1), C0 c0, C1 c1) { + return Event(this, func, c0, c1); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1), C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1) const, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1) volatile, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1) const volatile, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2), C0 c0, C1 c1, C2 c2) { + return Event(this, func, c0, c1, c2); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2), C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2) const, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2) volatile, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2) const volatile, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, B3), C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, func, c0, c1, c2, c3); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, B3), C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, B3) const, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, B3) volatile, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3) const volatile, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, B3, B4), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, func, c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, B3, B4), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(R (*func)(A0)) { + return Event(this, func); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(A0)) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(A0) const) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(A0) volatile) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(A0) const volatile) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(R (*func)(B0, A0), C0 c0) { + return Event(this, func, c0); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, A0), C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, A0) const, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, A0) volatile, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, A0) const volatile, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(R (*func)(B0, B1, A0), C0 c0, C1 c1) { + return Event(this, func, c0, c1); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, A0), C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, A0) const, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, A0) volatile, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, A0) const volatile, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, A0), C0 c0, C1 c1, C2 c2) { + return Event(this, func, c0, c1, c2); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, A0), C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, A0) const, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, A0) volatile, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, A0) const volatile, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, B3, A0), C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, func, c0, c1, c2, c3); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, B3, A0), C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, B3, A0) const, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0) volatile, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0) const volatile, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, B3, B4, A0), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, func, c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(R (*func)(A0, A1)) { + return Event(this, func); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(A0, A1)) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(A0, A1) const) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(A0, A1) volatile) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(A0, A1) const volatile) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(R (*func)(B0, A0, A1), C0 c0) { + return Event(this, func, c0); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, A0, A1), C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, A0, A1) const, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, A0, A1) volatile, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, A0, A1) const volatile, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(R (*func)(B0, B1, A0, A1), C0 c0, C1 c1) { + return Event(this, func, c0, c1); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, A0, A1), C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, A0, A1) const, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, A0, A1) volatile, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, A0, A1) const volatile, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, A0, A1), C0 c0, C1 c1, C2 c2) { + return Event(this, func, c0, c1, c2); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, A0, A1), C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, A0, A1) const, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1) volatile, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1) const volatile, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, B3, A0, A1), C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, func, c0, c1, c2, c3); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1), C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1) const, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1) volatile, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1) const volatile, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, B3, B4, A0, A1), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, func, c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(R (*func)(A0, A1, A2)) { + return Event(this, func); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(A0, A1, A2)) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(A0, A1, A2) const) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(A0, A1, A2) volatile) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(A0, A1, A2) const volatile) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(R (*func)(B0, A0, A1, A2), C0 c0) { + return Event(this, func, c0); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, A0, A1, A2), C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, A0, A1, A2) const, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, A0, A1, A2) volatile, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, A0, A1, A2) const volatile, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(R (*func)(B0, B1, A0, A1, A2), C0 c0, C1 c1) { + return Event(this, func, c0, c1); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, A0, A1, A2), C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, A0, A1, A2) const, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2) volatile, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2) const volatile, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, A0, A1, A2), C0 c0, C1 c1, C2 c2) { + return Event(this, func, c0, c1, c2); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2), C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2) const, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2) volatile, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2) const volatile, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, B3, A0, A1, A2), C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, func, c0, c1, c2, c3); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2), C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2) const, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2) volatile, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2) const volatile, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, B3, B4, A0, A1, A2), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, func, c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(R (*func)(A0, A1, A2, A3)) { + return Event(this, func); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(A0, A1, A2, A3)) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(A0, A1, A2, A3) const) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(A0, A1, A2, A3) volatile) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(A0, A1, A2, A3) const volatile) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(R (*func)(B0, A0, A1, A2, A3), C0 c0) { + return Event(this, func, c0); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, A0, A1, A2, A3), C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, A0, A1, A2, A3) const, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3) volatile, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3) const volatile, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(R (*func)(B0, B1, A0, A1, A2, A3), C0 c0, C1 c1) { + return Event(this, func, c0, c1); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3), C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3) const, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3) volatile, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3) const volatile, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2) { + return Event(this, func, c0, c1, c2); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3) const, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3) volatile, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3) const volatile, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, B3, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, func, c0, c1, c2, c3); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3) const, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3) volatile, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3) const volatile, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, B3, B4, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, func, c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(R (*func)(A0, A1, A2, A3, A4)) { + return Event(this, func); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(A0, A1, A2, A3, A4)) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(A0, A1, A2, A3, A4) const) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) volatile) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) const volatile) { + return Event(this, mbed::callback(obj, method)); +} + +template +Event EventQueue::event(R (*func)(B0, A0, A1, A2, A3, A4), C0 c0) { + return Event(this, func, c0); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4), C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4) const, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4) volatile, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4) const volatile, C0 c0) { + return Event(this, mbed::callback(obj, method), c0); +} + +template +Event EventQueue::event(R (*func)(B0, B1, A0, A1, A2, A3, A4), C0 c0, C1 c1) { + return Event(this, func, c0, c1); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4), C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4) const, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4) volatile, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4) const volatile, C0 c0, C1 c1) { + return Event(this, mbed::callback(obj, method), c0, c1); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2) { + return Event(this, func, c0, c1, c2); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4) const, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4) volatile, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4) const volatile, C0 c0, C1 c1, C2 c2) { + return Event(this, mbed::callback(obj, method), c0, c1, c2); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, B3, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, func, c0, c1, c2, c3); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4) const, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4) volatile, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4) const volatile, C0 c0, C1 c1, C2 c2, C3 c3) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3); +} + +template +Event EventQueue::event(R (*func)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, func, c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +template +Event EventQueue::event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) { + return Event(this, mbed::callback(obj, method), c0, c1, c2, c3, c4); +} + +} + +#endif diff --git a/events/EventQueue.cpp b/events/EventQueue.cpp new file mode 100644 index 0000000..e23d714 --- /dev/null +++ b/events/EventQueue.cpp @@ -0,0 +1,66 @@ +/* events + * Copyright (c) 2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "EventQueue.h" + +#include "mbed_events.h" +#include "mbed.h" + + +EventQueue::EventQueue(unsigned event_size, unsigned char *event_pointer) { + if (!event_pointer) { + equeue_create(&_equeue, event_size); + } else { + equeue_create_inplace(&_equeue, event_size, event_pointer); + } +} + +EventQueue::~EventQueue() { + equeue_destroy(&_equeue); +} + +void EventQueue::dispatch(int ms) { + return equeue_dispatch(&_equeue, ms); +} + +void EventQueue::break_dispatch() { + return equeue_break(&_equeue); +} + +unsigned EventQueue::tick() { + return equeue_tick(); +} + +void EventQueue::cancel(int id) { + return equeue_cancel(&_equeue, id); +} + +void EventQueue::background(Callback update) { + _update = update; + + if (_update) { + equeue_background(&_equeue, &Callback::thunk, &_update); + } else { + equeue_background(&_equeue, 0, 0); + } +} + +void EventQueue::chain(EventQueue *target) { + if (target) { + equeue_chain(&_equeue, &target->_equeue); + } else { + equeue_chain(&_equeue, 0); + } +} diff --git a/events/EventQueue.h b/events/EventQueue.h new file mode 100644 index 0000000..4c0f5f5 --- /dev/null +++ b/events/EventQueue.h @@ -0,0 +1,2480 @@ +/* events + * Copyright (c) 2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef EVENT_QUEUE_H +#define EVENT_QUEUE_H + +#include "equeue/equeue.h" +#include "Callback.h" +#include +#include + +namespace events { + +/** EVENTS_EVENT_SIZE + * Minimum size of an event + * This size fits a Callback at minimum + */ +#define EVENTS_EVENT_SIZE \ + (EQUEUE_EVENT_SIZE - 2*sizeof(void*) + sizeof(mbed::Callback)) + +/** EVENTS_QUEUE_SIZE + * Default size of buffer for events + */ +#define EVENTS_QUEUE_SIZE (32*EVENTS_EVENT_SIZE) + +// Predeclared classes +template +class Event; + + +/** EventQueue + * + * Flexible event queue for dispatching events + */ +class EventQueue { +public: + /** Create an EventQueue + * + * Create an event queue. 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); + + /** Destroy an EventQueue + */ + ~EventQueue(); + + /** 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 guaranteed + * 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=-1); + + /** Dispatch events without a timeout + * + * This is equivalent to EventQueue::dispatch with no arguments, but + * avoids overload ambiguities when passed as a callback. + * + * @see EventQueue::dispatch + */ + void dispatch_forever() { dispatch(); } + + /** Break out of a running event loop + * + * Forces the specified event queue's dispatch loop to terminate. Pending + * events may finish executing, but no new events will be executed. + */ + void break_dispatch(); + + /** 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 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 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 Unique id of the event + */ + void cancel(int id); + + /** Background an event queue onto a single-shot timer-interrupt + * + * When updated, the event queue will call the provided update function + * with a timeout indicating when the queue should be dispatched. A + * negative timeout will be passed to the update function when the + * timer-interrupt is no longer needed. + * + * Passing a null function disables the existing update function. + * + * The background function allows an event queue to take advantage of + * hardware timers or other event loops, allowing an event queue to be + * ran in the background without consuming the foreground thread. + * + * @param update Function called to indicate when the queue should be + * dispatched + */ + void background(mbed::Callback update); + + /** 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 use + * their own buffers and events must be handled independently. + * + * A null queue as the target will unchain the existing queue. + * + * The chain function allows multiple event queues 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); + + /** Calls an event on the queue + * + * 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 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 + int call(F f) { + struct local { + static void call(void *p) { (*static_cast(p))(); } + static void dtor(void *p) { static_cast(p)->~F(); } + }; + + void *p = equeue_alloc(&_equeue, sizeof(F)); + if (!p) { + return 0; + } + + F *e = new (p) F(f); + equeue_event_dtor(e, &local::dtor); + return equeue_post(&_equeue, &local::call, e); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(F f, A0 a0) { + return call(context10(f, a0)); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(F f, A0 a0, A1 a1) { + return call(context20(f, a0, a1)); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(F f, A0 a0, A1 a1, A2 a2) { + return call(context30(f, a0, a1, a2)); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(F f, A0 a0, A1 a1, A2 a2, A3 a3) { + return call(context40(f, a0, a1, a2, a3)); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(F f, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call(context50(f, a0, a1, a2, a3, a4)); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(T *obj, R (T::*method)()) { + return call(mbed::callback(obj, method)); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(const T *obj, R (T::*method)() const) { + return call(mbed::callback(obj, method)); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(volatile T *obj, R (T::*method)() volatile) { + return call(mbed::callback(obj, method)); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(const volatile T *obj, R (T::*method)() const volatile) { + return call(mbed::callback(obj, method)); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(T *obj, R (T::*method)(A0), A0 a0) { + return call(mbed::callback(obj, method), a0); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(const T *obj, R (T::*method)(A0) const, A0 a0) { + return call(mbed::callback(obj, method), a0); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(volatile T *obj, R (T::*method)(A0) volatile, A0 a0) { + return call(mbed::callback(obj, method), a0); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(const volatile T *obj, R (T::*method)(A0) const volatile, A0 a0) { + return call(mbed::callback(obj, method), a0); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(T *obj, R (T::*method)(A0, A1), A0 a0, A1 a1) { + return call(mbed::callback(obj, method), a0, a1); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(const T *obj, R (T::*method)(A0, A1) const, A0 a0, A1 a1) { + return call(mbed::callback(obj, method), a0, a1); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(volatile T *obj, R (T::*method)(A0, A1) volatile, A0 a0, A1 a1) { + return call(mbed::callback(obj, method), a0, a1); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(const volatile T *obj, R (T::*method)(A0, A1) const volatile, A0 a0, A1 a1) { + return call(mbed::callback(obj, method), a0, a1); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(T *obj, R (T::*method)(A0, A1, A2), A0 a0, A1 a1, A2 a2) { + return call(mbed::callback(obj, method), a0, a1, a2); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(const T *obj, R (T::*method)(A0, A1, A2) const, A0 a0, A1 a1, A2 a2) { + return call(mbed::callback(obj, method), a0, a1, a2); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(volatile T *obj, R (T::*method)(A0, A1, A2) volatile, A0 a0, A1 a1, A2 a2) { + return call(mbed::callback(obj, method), a0, a1, a2); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(const volatile T *obj, R (T::*method)(A0, A1, A2) const volatile, A0 a0, A1 a1, A2 a2) { + return call(mbed::callback(obj, method), a0, a1, a2); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(T *obj, R (T::*method)(A0, A1, A2, A3), A0 a0, A1 a1, A2 a2, A3 a3) { + return call(mbed::callback(obj, method), a0, a1, a2, a3); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(const T *obj, R (T::*method)(A0, A1, A2, A3) const, A0 a0, A1 a1, A2 a2, A3 a3) { + return call(mbed::callback(obj, method), a0, a1, a2, a3); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(volatile T *obj, R (T::*method)(A0, A1, A2, A3) volatile, A0 a0, A1 a1, A2 a2, A3 a3) { + return call(mbed::callback(obj, method), a0, a1, a2, a3); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(const volatile T *obj, R (T::*method)(A0, A1, A2, A3) const volatile, A0 a0, A1 a1, A2 a2, A3 a3) { + return call(mbed::callback(obj, method), a0, a1, a2, a3); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(T *obj, R (T::*method)(A0, A1, A2, A3, A4), A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call(mbed::callback(obj, method), a0, a1, a2, a3, a4); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(const T *obj, R (T::*method)(A0, A1, A2, A3, A4) const, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call(mbed::callback(obj, method), a0, a1, a2, a3, a4); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) volatile, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call(mbed::callback(obj, method), a0, a1, a2, a3, a4); + } + + /** Calls an event on the queue + * @see EventQueue::call + */ + template + int call(const volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) const volatile, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call(mbed::callback(obj, method), a0, a1, a2, a3, a4); + } + + /** Calls an event on the queue after a specified delay + * + * 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 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 + int call_in(int ms, F f) { + struct local { + static void call(void *p) { (*static_cast(p))(); } + static void dtor(void *p) { static_cast(p)->~F(); } + }; + + void *p = equeue_alloc(&_equeue, sizeof(F)); + if (!p) { + return 0; + } + + F *e = new (p) F(f); + equeue_event_delay(e, ms); + equeue_event_dtor(e, &local::dtor); + return equeue_post(&_equeue, &local::call, e); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, F f, A0 a0) { + return call_in(ms, context10(f, a0)); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, F f, A0 a0, A1 a1) { + return call_in(ms, context20(f, a0, a1)); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, F f, A0 a0, A1 a1, A2 a2) { + return call_in(ms, context30(f, a0, a1, a2)); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, F f, A0 a0, A1 a1, A2 a2, A3 a3) { + return call_in(ms, context40(f, a0, a1, a2, a3)); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, F f, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call_in(ms, context50(f, a0, a1, a2, a3, a4)); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, T *obj, R (T::*method)()) { + return call_in(ms, mbed::callback(obj, method)); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, const T *obj, R (T::*method)() const) { + return call_in(ms, mbed::callback(obj, method)); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, volatile T *obj, R (T::*method)() volatile) { + return call_in(ms, mbed::callback(obj, method)); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, const volatile T *obj, R (T::*method)() const volatile) { + return call_in(ms, mbed::callback(obj, method)); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, T *obj, R (T::*method)(A0), A0 a0) { + return call_in(ms, mbed::callback(obj, method), a0); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, const T *obj, R (T::*method)(A0) const, A0 a0) { + return call_in(ms, mbed::callback(obj, method), a0); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, volatile T *obj, R (T::*method)(A0) volatile, A0 a0) { + return call_in(ms, mbed::callback(obj, method), a0); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, const volatile T *obj, R (T::*method)(A0) const volatile, A0 a0) { + return call_in(ms, mbed::callback(obj, method), a0); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, T *obj, R (T::*method)(A0, A1), A0 a0, A1 a1) { + return call_in(ms, mbed::callback(obj, method), a0, a1); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, const T *obj, R (T::*method)(A0, A1) const, A0 a0, A1 a1) { + return call_in(ms, mbed::callback(obj, method), a0, a1); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, volatile T *obj, R (T::*method)(A0, A1) volatile, A0 a0, A1 a1) { + return call_in(ms, mbed::callback(obj, method), a0, a1); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, const volatile T *obj, R (T::*method)(A0, A1) const volatile, A0 a0, A1 a1) { + return call_in(ms, mbed::callback(obj, method), a0, a1); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, T *obj, R (T::*method)(A0, A1, A2), A0 a0, A1 a1, A2 a2) { + return call_in(ms, mbed::callback(obj, method), a0, a1, a2); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, const T *obj, R (T::*method)(A0, A1, A2) const, A0 a0, A1 a1, A2 a2) { + return call_in(ms, mbed::callback(obj, method), a0, a1, a2); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, volatile T *obj, R (T::*method)(A0, A1, A2) volatile, A0 a0, A1 a1, A2 a2) { + return call_in(ms, mbed::callback(obj, method), a0, a1, a2); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, const volatile T *obj, R (T::*method)(A0, A1, A2) const volatile, A0 a0, A1 a1, A2 a2) { + return call_in(ms, mbed::callback(obj, method), a0, a1, a2); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, T *obj, R (T::*method)(A0, A1, A2, A3), A0 a0, A1 a1, A2 a2, A3 a3) { + return call_in(ms, mbed::callback(obj, method), a0, a1, a2, a3); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, const T *obj, R (T::*method)(A0, A1, A2, A3) const, A0 a0, A1 a1, A2 a2, A3 a3) { + return call_in(ms, mbed::callback(obj, method), a0, a1, a2, a3); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, volatile T *obj, R (T::*method)(A0, A1, A2, A3) volatile, A0 a0, A1 a1, A2 a2, A3 a3) { + return call_in(ms, mbed::callback(obj, method), a0, a1, a2, a3); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, const volatile T *obj, R (T::*method)(A0, A1, A2, A3) const volatile, A0 a0, A1 a1, A2 a2, A3 a3) { + return call_in(ms, mbed::callback(obj, method), a0, a1, a2, a3); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, T *obj, R (T::*method)(A0, A1, A2, A3, A4), A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call_in(ms, mbed::callback(obj, method), a0, a1, a2, a3, a4); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, const T *obj, R (T::*method)(A0, A1, A2, A3, A4) const, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call_in(ms, mbed::callback(obj, method), a0, a1, a2, a3, a4); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) volatile, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call_in(ms, mbed::callback(obj, method), a0, a1, a2, a3, a4); + } + + /** Calls an event on the queue after a specified delay + * @see EventQueue::call_in + */ + template + int call_in(int ms, const volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) const volatile, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call_in(ms, mbed::callback(obj, method), a0, a1, a2, a3, a4); + } + + /** Calls an event on the queue periodically + * + * 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 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 + int call_every(int ms, F f) { + struct local { + static void call(void *p) { (*static_cast(p))(); } + static void dtor(void *p) { static_cast(p)->~F(); } + }; + + void *p = equeue_alloc(&_equeue, sizeof(F)); + if (!p) { + return 0; + } + + F *e = new (p) F(f); + equeue_event_delay(e, ms); + equeue_event_period(e, ms); + equeue_event_dtor(e, &local::dtor); + return equeue_post(&_equeue, &local::call, e); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, F f, A0 a0) { + return call_every(ms, context10(f, a0)); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, F f, A0 a0, A1 a1) { + return call_every(ms, context20(f, a0, a1)); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, F f, A0 a0, A1 a1, A2 a2) { + return call_every(ms, context30(f, a0, a1, a2)); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, F f, A0 a0, A1 a1, A2 a2, A3 a3) { + return call_every(ms, context40(f, a0, a1, a2, a3)); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, F f, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call_every(ms, context50(f, a0, a1, a2, a3, a4)); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, T *obj, R (T::*method)()) { + return call_every(ms, mbed::callback(obj, method)); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, const T *obj, R (T::*method)() const) { + return call_every(ms, mbed::callback(obj, method)); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, volatile T *obj, R (T::*method)() volatile) { + return call_every(ms, mbed::callback(obj, method)); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, const volatile T *obj, R (T::*method)() const volatile) { + return call_every(ms, mbed::callback(obj, method)); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, T *obj, R (T::*method)(A0), A0 a0) { + return call_every(ms, mbed::callback(obj, method), a0); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, const T *obj, R (T::*method)(A0) const, A0 a0) { + return call_every(ms, mbed::callback(obj, method), a0); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, volatile T *obj, R (T::*method)(A0) volatile, A0 a0) { + return call_every(ms, mbed::callback(obj, method), a0); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, const volatile T *obj, R (T::*method)(A0) const volatile, A0 a0) { + return call_every(ms, mbed::callback(obj, method), a0); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, T *obj, R (T::*method)(A0, A1), A0 a0, A1 a1) { + return call_every(ms, mbed::callback(obj, method), a0, a1); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, const T *obj, R (T::*method)(A0, A1) const, A0 a0, A1 a1) { + return call_every(ms, mbed::callback(obj, method), a0, a1); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, volatile T *obj, R (T::*method)(A0, A1) volatile, A0 a0, A1 a1) { + return call_every(ms, mbed::callback(obj, method), a0, a1); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, const volatile T *obj, R (T::*method)(A0, A1) const volatile, A0 a0, A1 a1) { + return call_every(ms, mbed::callback(obj, method), a0, a1); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, T *obj, R (T::*method)(A0, A1, A2), A0 a0, A1 a1, A2 a2) { + return call_every(ms, mbed::callback(obj, method), a0, a1, a2); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, const T *obj, R (T::*method)(A0, A1, A2) const, A0 a0, A1 a1, A2 a2) { + return call_every(ms, mbed::callback(obj, method), a0, a1, a2); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, volatile T *obj, R (T::*method)(A0, A1, A2) volatile, A0 a0, A1 a1, A2 a2) { + return call_every(ms, mbed::callback(obj, method), a0, a1, a2); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, const volatile T *obj, R (T::*method)(A0, A1, A2) const volatile, A0 a0, A1 a1, A2 a2) { + return call_every(ms, mbed::callback(obj, method), a0, a1, a2); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, T *obj, R (T::*method)(A0, A1, A2, A3), A0 a0, A1 a1, A2 a2, A3 a3) { + return call_every(ms, mbed::callback(obj, method), a0, a1, a2, a3); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, const T *obj, R (T::*method)(A0, A1, A2, A3) const, A0 a0, A1 a1, A2 a2, A3 a3) { + return call_every(ms, mbed::callback(obj, method), a0, a1, a2, a3); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, volatile T *obj, R (T::*method)(A0, A1, A2, A3) volatile, A0 a0, A1 a1, A2 a2, A3 a3) { + return call_every(ms, mbed::callback(obj, method), a0, a1, a2, a3); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, const volatile T *obj, R (T::*method)(A0, A1, A2, A3) const volatile, A0 a0, A1 a1, A2 a2, A3 a3) { + return call_every(ms, mbed::callback(obj, method), a0, a1, a2, a3); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, T *obj, R (T::*method)(A0, A1, A2, A3, A4), A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call_every(ms, mbed::callback(obj, method), a0, a1, a2, a3, a4); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, const T *obj, R (T::*method)(A0, A1, A2, A3, A4) const, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call_every(ms, mbed::callback(obj, method), a0, a1, a2, a3, a4); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) volatile, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call_every(ms, mbed::callback(obj, method), a0, a1, a2, a3, a4); + } + + /** Calls an event on the queue periodically + * @see EventQueue::call_every + */ + template + int call_every(int ms, const volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) const volatile, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + return call_every(ms, mbed::callback(obj, method), a0, a1, a2, a3, a4); + } + + /** Creates an event bound to the event queue + * + * Constructs an event bound to the specified event queue. The specified + * callback acts as the target for the event and is executed in the + * context of the event queue's dispatch loop once posted. + * + * @param f Function to execute when the event is dispatched + * @param a0..a4 Arguments to pass to the callback + * @return Event that will dispatch on the specific queue + */ + template + Event event(R (*func)()); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)()); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)() const); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)() volatile); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)() const volatile); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0), C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0), C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0) const, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0) volatile, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0) const volatile, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1), C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1), C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1) const, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1) volatile, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1) const volatile, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2), C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2), C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2) const, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2) volatile, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2) const volatile, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, B3), C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, B3), C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, B3) const, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3) volatile, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3) const volatile, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, B3, B4), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, B3, B4), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(A0)); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(A0)); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(A0) const); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(A0) volatile); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(A0) const volatile); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, A0), C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, A0), C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, A0) const, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, A0) volatile, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, A0) const volatile, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, A0), C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, A0), C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, A0) const, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, A0) volatile, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, A0) const volatile, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, A0), C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, A0), C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, A0) const, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, A0) volatile, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, A0) const volatile, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, B3, A0), C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, B3, A0), C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, A0) const, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0) volatile, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0) const volatile, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, B3, B4, A0), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(A0, A1)); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(A0, A1)); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(A0, A1) const); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(A0, A1) volatile); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(A0, A1) const volatile); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, A0, A1), C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, A0, A1), C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, A0, A1) const, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, A0, A1) volatile, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, A0, A1) const volatile, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, A0, A1), C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, A0, A1), C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, A0, A1) const, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, A0, A1) volatile, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, A0, A1) const volatile, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, A0, A1), C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, A0, A1), C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, A0, A1) const, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1) volatile, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1) const volatile, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, B3, A0, A1), C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1), C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1) const, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1) volatile, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1) const volatile, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, B3, B4, A0, A1), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(A0, A1, A2)); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(A0, A1, A2)); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(A0, A1, A2) const); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(A0, A1, A2) volatile); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(A0, A1, A2) const volatile); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, A0, A1, A2), C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, A0, A1, A2), C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, A0, A1, A2) const, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, A0, A1, A2) volatile, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, A0, A1, A2) const volatile, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, A0, A1, A2), C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, A0, A1, A2), C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, A0, A1, A2) const, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2) volatile, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2) const volatile, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, A0, A1, A2), C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2), C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2) const, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2) volatile, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2) const volatile, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, B3, A0, A1, A2), C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2), C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2) const, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2) volatile, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2) const volatile, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, B3, B4, A0, A1, A2), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(A0, A1, A2, A3)); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(A0, A1, A2, A3)); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(A0, A1, A2, A3) const); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(A0, A1, A2, A3) volatile); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(A0, A1, A2, A3) const volatile); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, A0, A1, A2, A3), C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, A0, A1, A2, A3), C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, A0, A1, A2, A3) const, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3) volatile, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3) const volatile, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, A0, A1, A2, A3), C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3), C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3) const, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3) volatile, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3) const volatile, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3) const, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3) volatile, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3) const volatile, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, B3, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3) const, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3) volatile, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3) const volatile, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, B3, B4, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(A0, A1, A2, A3, A4)); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(A0, A1, A2, A3, A4)); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(A0, A1, A2, A3, A4) const); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) volatile); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(A0, A1, A2, A3, A4) const volatile); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, A0, A1, A2, A3, A4), C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4), C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4) const, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4) volatile, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, A0, A1, A2, A3, A4) const volatile, C0 c0); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, A0, A1, A2, A3, A4), C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4), C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4) const, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4) volatile, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, A0, A1, A2, A3, A4) const volatile, C0 c0, C1 c1); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4) const, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4) volatile, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, A0, A1, A2, A3, A4) const volatile, C0 c0, C1 c1, C2 c2); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, B3, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4) const, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4) volatile, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, A0, A1, A2, A3, A4) const volatile, C0 c0, C1 c1, C2 c2, C3 c3); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(R (*func)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4), C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4) const, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4) volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + + /** Creates an event bound to the event queue + * @see EventQueue::event + */ + template + Event event(const volatile T *obj, R (T::*method)(B0, B1, B2, B3, B4, A0, A1, A2, A3, A4) const volatile, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4); + +protected: + template + friend class Event; + struct equeue _equeue; + mbed::Callback _update; + + template + struct context00 { + F f; + + context00(F f) + : f(f) {} + + void operator()() { + f(); + } + }; + + template + struct context10 { + F f; C0 c0; + + context10(F f, C0 c0) + : f(f), c0(c0) {} + + void operator()() { + f(c0); + } + }; + + template + struct context20 { + F f; C0 c0; C1 c1; + + context20(F f, C0 c0, C1 c1) + : f(f), c0(c0), c1(c1) {} + + void operator()() { + f(c0, c1); + } + }; + + template + struct context30 { + F f; C0 c0; C1 c1; C2 c2; + + context30(F f, C0 c0, C1 c1, C2 c2) + : f(f), c0(c0), c1(c1), c2(c2) {} + + void operator()() { + f(c0, c1, c2); + } + }; + + template + struct context40 { + F f; C0 c0; C1 c1; C2 c2; C3 c3; + + context40(F f, C0 c0, C1 c1, C2 c2, C3 c3) + : f(f), c0(c0), c1(c1), c2(c2), c3(c3) {} + + void operator()() { + f(c0, c1, c2, c3); + } + }; + + template + struct context50 { + F f; C0 c0; C1 c1; C2 c2; C3 c3; C4 c4; + + context50(F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) + : f(f), c0(c0), c1(c1), c2(c2), c3(c3), c4(c4) {} + + void operator()() { + f(c0, c1, c2, c3, c4); + } + }; + + template + struct context01 { + F f; + + context01(F f) + : f(f) {} + + void operator()(A0 a0) { + f(a0); + } + }; + + template + struct context11 { + F f; C0 c0; + + context11(F f, C0 c0) + : f(f), c0(c0) {} + + void operator()(A0 a0) { + f(c0, a0); + } + }; + + template + struct context21 { + F f; C0 c0; C1 c1; + + context21(F f, C0 c0, C1 c1) + : f(f), c0(c0), c1(c1) {} + + void operator()(A0 a0) { + f(c0, c1, a0); + } + }; + + template + struct context31 { + F f; C0 c0; C1 c1; C2 c2; + + context31(F f, C0 c0, C1 c1, C2 c2) + : f(f), c0(c0), c1(c1), c2(c2) {} + + void operator()(A0 a0) { + f(c0, c1, c2, a0); + } + }; + + template + struct context41 { + F f; C0 c0; C1 c1; C2 c2; C3 c3; + + context41(F f, C0 c0, C1 c1, C2 c2, C3 c3) + : f(f), c0(c0), c1(c1), c2(c2), c3(c3) {} + + void operator()(A0 a0) { + f(c0, c1, c2, c3, a0); + } + }; + + template + struct context51 { + F f; C0 c0; C1 c1; C2 c2; C3 c3; C4 c4; + + context51(F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) + : f(f), c0(c0), c1(c1), c2(c2), c3(c3), c4(c4) {} + + void operator()(A0 a0) { + f(c0, c1, c2, c3, c4, a0); + } + }; + + template + struct context02 { + F f; + + context02(F f) + : f(f) {} + + void operator()(A0 a0, A1 a1) { + f(a0, a1); + } + }; + + template + struct context12 { + F f; C0 c0; + + context12(F f, C0 c0) + : f(f), c0(c0) {} + + void operator()(A0 a0, A1 a1) { + f(c0, a0, a1); + } + }; + + template + struct context22 { + F f; C0 c0; C1 c1; + + context22(F f, C0 c0, C1 c1) + : f(f), c0(c0), c1(c1) {} + + void operator()(A0 a0, A1 a1) { + f(c0, c1, a0, a1); + } + }; + + template + struct context32 { + F f; C0 c0; C1 c1; C2 c2; + + context32(F f, C0 c0, C1 c1, C2 c2) + : f(f), c0(c0), c1(c1), c2(c2) {} + + void operator()(A0 a0, A1 a1) { + f(c0, c1, c2, a0, a1); + } + }; + + template + struct context42 { + F f; C0 c0; C1 c1; C2 c2; C3 c3; + + context42(F f, C0 c0, C1 c1, C2 c2, C3 c3) + : f(f), c0(c0), c1(c1), c2(c2), c3(c3) {} + + void operator()(A0 a0, A1 a1) { + f(c0, c1, c2, c3, a0, a1); + } + }; + + template + struct context52 { + F f; C0 c0; C1 c1; C2 c2; C3 c3; C4 c4; + + context52(F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) + : f(f), c0(c0), c1(c1), c2(c2), c3(c3), c4(c4) {} + + void operator()(A0 a0, A1 a1) { + f(c0, c1, c2, c3, c4, a0, a1); + } + }; + + template + struct context03 { + F f; + + context03(F f) + : f(f) {} + + void operator()(A0 a0, A1 a1, A2 a2) { + f(a0, a1, a2); + } + }; + + template + struct context13 { + F f; C0 c0; + + context13(F f, C0 c0) + : f(f), c0(c0) {} + + void operator()(A0 a0, A1 a1, A2 a2) { + f(c0, a0, a1, a2); + } + }; + + template + struct context23 { + F f; C0 c0; C1 c1; + + context23(F f, C0 c0, C1 c1) + : f(f), c0(c0), c1(c1) {} + + void operator()(A0 a0, A1 a1, A2 a2) { + f(c0, c1, a0, a1, a2); + } + }; + + template + struct context33 { + F f; C0 c0; C1 c1; C2 c2; + + context33(F f, C0 c0, C1 c1, C2 c2) + : f(f), c0(c0), c1(c1), c2(c2) {} + + void operator()(A0 a0, A1 a1, A2 a2) { + f(c0, c1, c2, a0, a1, a2); + } + }; + + template + struct context43 { + F f; C0 c0; C1 c1; C2 c2; C3 c3; + + context43(F f, C0 c0, C1 c1, C2 c2, C3 c3) + : f(f), c0(c0), c1(c1), c2(c2), c3(c3) {} + + void operator()(A0 a0, A1 a1, A2 a2) { + f(c0, c1, c2, c3, a0, a1, a2); + } + }; + + template + struct context53 { + F f; C0 c0; C1 c1; C2 c2; C3 c3; C4 c4; + + context53(F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) + : f(f), c0(c0), c1(c1), c2(c2), c3(c3), c4(c4) {} + + void operator()(A0 a0, A1 a1, A2 a2) { + f(c0, c1, c2, c3, c4, a0, a1, a2); + } + }; + + template + struct context04 { + F f; + + context04(F f) + : f(f) {} + + void operator()(A0 a0, A1 a1, A2 a2, A3 a3) { + f(a0, a1, a2, a3); + } + }; + + template + struct context14 { + F f; C0 c0; + + context14(F f, C0 c0) + : f(f), c0(c0) {} + + void operator()(A0 a0, A1 a1, A2 a2, A3 a3) { + f(c0, a0, a1, a2, a3); + } + }; + + template + struct context24 { + F f; C0 c0; C1 c1; + + context24(F f, C0 c0, C1 c1) + : f(f), c0(c0), c1(c1) {} + + void operator()(A0 a0, A1 a1, A2 a2, A3 a3) { + f(c0, c1, a0, a1, a2, a3); + } + }; + + template + struct context34 { + F f; C0 c0; C1 c1; C2 c2; + + context34(F f, C0 c0, C1 c1, C2 c2) + : f(f), c0(c0), c1(c1), c2(c2) {} + + void operator()(A0 a0, A1 a1, A2 a2, A3 a3) { + f(c0, c1, c2, a0, a1, a2, a3); + } + }; + + template + struct context44 { + F f; C0 c0; C1 c1; C2 c2; C3 c3; + + context44(F f, C0 c0, C1 c1, C2 c2, C3 c3) + : f(f), c0(c0), c1(c1), c2(c2), c3(c3) {} + + void operator()(A0 a0, A1 a1, A2 a2, A3 a3) { + f(c0, c1, c2, c3, a0, a1, a2, a3); + } + }; + + template + struct context54 { + F f; C0 c0; C1 c1; C2 c2; C3 c3; C4 c4; + + context54(F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) + : f(f), c0(c0), c1(c1), c2(c2), c3(c3), c4(c4) {} + + void operator()(A0 a0, A1 a1, A2 a2, A3 a3) { + f(c0, c1, c2, c3, c4, a0, a1, a2, a3); + } + }; + + template + struct context05 { + F f; + + context05(F f) + : f(f) {} + + void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + f(a0, a1, a2, a3, a4); + } + }; + + template + struct context15 { + F f; C0 c0; + + context15(F f, C0 c0) + : f(f), c0(c0) {} + + void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + f(c0, a0, a1, a2, a3, a4); + } + }; + + template + struct context25 { + F f; C0 c0; C1 c1; + + context25(F f, C0 c0, C1 c1) + : f(f), c0(c0), c1(c1) {} + + void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + f(c0, c1, a0, a1, a2, a3, a4); + } + }; + + template + struct context35 { + F f; C0 c0; C1 c1; C2 c2; + + context35(F f, C0 c0, C1 c1, C2 c2) + : f(f), c0(c0), c1(c1), c2(c2) {} + + void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + f(c0, c1, c2, a0, a1, a2, a3, a4); + } + }; + + template + struct context45 { + F f; C0 c0; C1 c1; C2 c2; C3 c3; + + context45(F f, C0 c0, C1 c1, C2 c2, C3 c3) + : f(f), c0(c0), c1(c1), c2(c2), c3(c3) {} + + void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + f(c0, c1, c2, c3, a0, a1, a2, a3, a4); + } + }; + + template + struct context55 { + F f; C0 c0; C1 c1; C2 c2; C3 c3; C4 c4; + + context55(F f, C0 c0, C1 c1, C2 c2, C3 c3, C4 c4) + : f(f), c0(c0), c1(c1), c2(c2), c3(c3), c4(c4) {} + + void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + f(c0, c1, c2, c3, c4, a0, a1, a2, a3, a4); + } + }; +}; + +} + +#endif diff --git a/events/LICENSE b/events/LICENSE new file mode 100644 index 0000000..59cd3f8 --- /dev/null +++ b/events/LICENSE @@ -0,0 +1,165 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. diff --git a/events/README.md b/events/README.md new file mode 100644 index 0000000..9e0263c --- /dev/null +++ b/events/README.md @@ -0,0 +1,153 @@ +## The mbed-events library ## + +The mbed-events library provides a flexible queue for scheduling events. + +``` cpp +#include "mbed_events.h" +#include + +int main() { + // creates a queue with the default size + EventQueue queue; + + // events are simple callbacks + queue.call(printf, "called immediately\n"); + queue.call_in(2000, printf, "called in 2 seconds\n"); + queue.call_every(1000, printf, "called every 1 seconds\n"); + + // 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 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 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(&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(); +``` + +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"); + +// The call_in function registers events to be called after a delay +// specified in milliseconds +queue.call_in(2000, doit_in_two_seconds); +queue.call_in(300, printf, "called in 0.3 seconds\n"); + +// The call_every function registers events to be called repeatedly +// with a period specified in milliseconds +queue.call_every(2000, doit_every_two_seconds); +queue.call_every(400, printf, "called every 0.4 seconds\n"); +``` + +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 uniquely represents the event in the queue +int id = queue.call_in(100, printf, "will this work?\n"); + +// 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 be cancelled as long as they have not been dispatched. If the +// event has already expired, cancel has no side-effects. +queue.cancel(id); +``` + +For a more fine-grain control of event dispatch, the `Event` class can be +manually instantiated and configured. An `Event` represents an event as +a C++ style function object and can be directly passed to other APIs that +expect a callback. + +``` cpp +// Creates an event bound to the specified event queue +EventQueue queue; +Event event(&queue, doit); + +// The event can be manually configured for special timing requirements +// specified in milliseconds +event.delay(10); +event.period(10000); + +// Posted events are dispatched in the context of the queue's +// dispatch function +queue.dispatch(); + +// Events can also pass arguments to the underlying callback when both +// initially constructed and posted. +Event event(&queue, printf, "recieved %d and %d\n"); + +// Events can be posted multiple times and enqueue gracefully until +// the dispatch function is called. +event.post(1, 2); +event.post(3, 4); +event.post(5, 6); + +queue.dispatch(); +``` + +Event queues easily align with module boundaries, where internal state can +be implicitly 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"); + +EventQueue b; +b.call(printf, "hello from b!\n"); + +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(); +``` + + diff --git a/events/equeue/.mbedignore b/events/equeue/.mbedignore new file mode 100644 index 0000000..e7e1fb0 --- /dev/null +++ b/events/equeue/.mbedignore @@ -0,0 +1 @@ +tests/* diff --git a/events/equeue/Makefile b/events/equeue/Makefile new file mode 100644 index 0000000..183f71c --- /dev/null +++ b/events/equeue/Makefile @@ -0,0 +1,60 @@ +TARGET = libequeue.a + +CC = gcc +AR = ar +SIZE = size + +SRC += $(wildcard *.c) +OBJ := $(SRC:.c=.o) +DEP := $(SRC:.c=.d) +ASM := $(SRC:.c=.s) + +ifdef DEBUG +CFLAGS += -O0 -g3 +else +CFLAGS += -O2 +endif +ifdef WORD +CFLAGS += -m$(WORD) +endif +CFLAGS += -I. +CFLAGS += -std=c99 +CFLAGS += -Wall +CFLAGS += -D_XOPEN_SOURCE=600 + +LFLAGS += -pthread + + +all: $(TARGET) + +test: tests/tests.o $(OBJ) + $(CC) $(CFLAGS) $^ $(LFLAGS) -o tests/tests + tests/tests + +prof: tests/prof.o $(OBJ) + $(CC) $(CFLAGS) $^ $(LFLAGS) -o tests/prof + tests/prof + +asm: $(ASM) + +size: $(OBJ) + $(SIZE) -t $^ + +-include $(DEP) + +%.a: $(OBJ) + $(AR) rcs $@ $^ + +%.o: %.c + $(CC) -c -MMD $(CFLAGS) $< -o $@ + +%.s: %.c + $(CC) -S $(CFLAGS) $< -o $@ + +clean: + rm -f $(TARGET) + rm -f tests/tests tests/tests.o tests/tests.d + rm -f tests/prof tests/prof.o tests/prof.d + rm -f $(OBJ) + rm -f $(DEP) + rm -f $(ASM) diff --git a/events/equeue/README.md b/events/equeue/README.md new file mode 100644 index 0000000..10f500c --- /dev/null +++ b/events/equeue/README.md @@ -0,0 +1,210 @@ +## The equeue library ## + +The equeue library is designed as a simple but powerful library for scheduling +events on composable queues. + +``` c +#include "equeue.h" +#include + +int main() { + // creates a queue with space for 32 basic events + equeue_t queue; + equeue_create(&queue, 32*EQUEUE_EVENT_SIZE); + + // events can be simple callbacks + equeue_call(&queue, print, "called immediately"); + equeue_call_in(&queue, 2000, print, "called in 2 seconds"); + equeue_call_every(&queue, 1000, print, "called every 1 seconds"); + + // events are executed in equeue_dispatch + equeue_dispatch(&queue, 3000); + + print("called after 3 seconds"); + + equeue_destroy(&queue); +} +``` + +The equeue 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 +multiple queues. + +The equeue 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. + +## Documentation ## + +The in-depth documentation on specific functions can be found in +[equeue.h](equeue.h). + +The core of the equeue library is the `equeue_t` type which represents a +single event queue, and the `equeue_dispatch` function which runs the equeue, +providing the context for executing events. + +On top of this, `equeue_call`, `equeue_call_in`, and `equeue_call_every` +provide easy methods for posting events to execute in the context of the +`equeue_dispatch` function. + +``` c +#include "equeue.h" +#include "game.h" + +equeue_t queue; +struct game game; + +// button_isr may be in interrupt context +void button_isr(void) { + equeue_call(&queue, game_button_update, &game); +} + +// a simple user-interface framework +int main() { + equeue_create(&queue, 4096); + game_create(&game); + + // call game_screen_udpate at 60 Hz + equeue_call_every(&queue, 1000/60, game_screen_update, &game); + + // dispatch forever + equeue_dispatch(&queue, -1); +} +``` + +In addition to simple callbacks, an event can be manually allocated with +`equeue_alloc` and posted with `equeue_post` to allow passing an arbitrary +amount of context to the execution of the event. This memory is allocated out +of the equeue's buffer, and dynamic memory can be completely avoided. + +The equeue allocator is designed to minimize jitter in interrupt contexts as +well as avoid memory fragmentation on small devices. The allocator achieves +both constant-runtime and zero-fragmentation for fixed-size events, however +grows linearly as the quantity of differently-sized allocations increases. + +``` c +#include "equeue.h" + +equeue_t queue; + +// arbitrary data can be moved to a different context +int enet_consume(void *buffer, int size) { + if (size > 512) { + size = 512; + } + + void *data = equeue_alloc(&queue, 512); + memcpy(data, buffer, size); + equeue_post(&queue, handle_data_elsewhere, data); + + return size; +} +``` + +Additionally, in-flight events can be cancelled with `equeue_cancel`. Events +are given unique ids on post, allowing safe cancellation of expired events. + +``` c +#include "equeue.h" + +equeue_t queue; +int sonar_value; +int sonar_timeout_id; + +void sonar_isr(int value) { + equeue_cancel(&queue, sonar_timeout_id); + sonar_value = value; +} + +void sonar_timeout(void *) { + sonar_value = -1; +} + +void sonar_read(void) { + sonar_timeout_id = equeue_call_in(&queue, 300, sonar_timeout, 0); + sonar_start(); +} +``` + +From an architectural standpoint, event queues easily align with module +boundaries, where internal state can be implicitly synchronized through +event dispatch. + +On platforms where multiple threads are unavailable, multiple modules +can use independent event queues and still be composed through the +`equeue_chain` function. + +``` c +#include "equeue.h" + +// run a simultaneous localization and mapping loop in one queue +struct slam { + equeue_t queue; +}; + +void slam_create(struct slam *s, equeue_t *target) { + equeue_create(&s->queue, 4096); + equeue_chain(&s->queue, target); + equeue_call_every(&s->queue, 100, slam_filter); +} + +// run a sonar with it's own queue +struct sonar { + equeue_t equeue; + struct slam *slam; +}; + +void sonar_create(struct sonar *s, equeue_t *target) { + equeue_create(&s->queue, 64); + equeue_chain(&s->queue, target); + equeue_call_in(&s->queue, 5, sonar_update, s); +} + +// all of the above queues can be combined into a single thread of execution +int main() { + equeue_t queue; + equeue_create(&queue, 1024); + + struct sonar s1, s2, s3; + sonar_create(&s1, &queue); + sonar_create(&s2, &queue); + sonar_create(&s3, &queue); + + struct slam slam; + slam_create(&slam, &queue); + + // dispatches events from all of the modules + equeue_dispatch(&queue, -1); +} +``` + +## Platform ## + +The equeue library has a minimal porting layer that is flexible depending +on the requirements of the underlying platform. Platform specific declarations +and more information can be found in [equeue_platform.h](equeue_platform.h). + +## Tests ## + +The equeue library uses a set of local tests based on the posix implementation. + +Runtime tests are located in [tests.c](tests/tests.c): + +``` bash +make test +``` + +Profiling tests based on rdtsc are located in [prof.c](tests/prof.c): + +``` bash +make prof +``` + +To make profiling results more tangible, the profiler also supports percentage +comparison with previous runs: +``` bash +make prof | tee results.txt +cat results.txt | make prof +``` + diff --git a/events/equeue/equeue.c b/events/equeue/equeue.c new file mode 100644 index 0000000..9de980d --- /dev/null +++ b/events/equeue/equeue.c @@ -0,0 +1,569 @@ +/* + * Flexible event queue for dispatching events + * + * Copyright (c) 2016 Christopher Haster + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "equeue.h" + +#include +#include + + +// calculate the relative-difference between absolute times while +// correctly handling overflow conditions +static inline int equeue_tickdiff(unsigned a, unsigned b) { + return (int)(a - b); +} + +// calculate the relative-difference between absolute times, but +// also clamp to zero, resulting in only non-zero values. +static inline int equeue_clampdiff(unsigned a, unsigned b) { + int diff = equeue_tickdiff(a, b); + return ~(diff >> (8*sizeof(int)-1)) & diff; +} + +// Increment the unique id in an event, hiding the event from cancel +static inline void equeue_incid(equeue_t *q, struct equeue_event *e) { + e->id += 1; + if (!(e->id << q->npw2)) { + e->id = 1; + } +} + + +// equeue lifetime management +int equeue_create(equeue_t *q, size_t size) { + // dynamically allocate the specified buffer + void *buffer = malloc(size); + if (!buffer) { + return -1; + } + + int err = equeue_create_inplace(q, size, buffer); + q->allocated = buffer; + return err; +} + +int equeue_create_inplace(equeue_t *q, size_t size, void *buffer) { + // setup queue around provided buffer + q->buffer = buffer; + q->allocated = 0; + + q->npw2 = 0; + for (unsigned s = size; s; s >>= 1) { + q->npw2++; + } + + q->chunks = 0; + q->slab.size = size; + q->slab.data = buffer; + + q->queue = 0; + q->tick = equeue_tick(); + q->generation = 0; + q->breaks = 0; + + q->background.active = false; + q->background.update = 0; + q->background.timer = 0; + + // initialize platform resources + int err; + err = equeue_sema_create(&q->eventsema); + if (err < 0) { + return err; + } + + err = equeue_mutex_create(&q->queuelock); + if (err < 0) { + return err; + } + + err = equeue_mutex_create(&q->memlock); + if (err < 0) { + return err; + } + + return 0; +} + +void equeue_destroy(equeue_t *q) { + // call destructors on pending events + for (struct equeue_event *es = q->queue; es; es = es->next) { + for (struct equeue_event *e = q->queue; e; e = e->sibling) { + if (e->dtor) { + e->dtor(e + 1); + } + } + } + + // notify background timer + if (q->background.update) { + q->background.update(q->background.timer, -1); + } + + // clean up platform resources + memory + equeue_mutex_destroy(&q->memlock); + equeue_mutex_destroy(&q->queuelock); + equeue_sema_destroy(&q->eventsema); + free(q->allocated); +} + + +// equeue chunk allocation functions +static struct equeue_event *equeue_mem_alloc(equeue_t *q, size_t size) { + // add event overhead + size += sizeof(struct equeue_event); + size = (size + sizeof(void*)-1) & ~(sizeof(void*)-1); + + equeue_mutex_lock(&q->memlock); + + // check if a good chunk is available + for (struct equeue_event **p = &q->chunks; *p; p = &(*p)->next) { + if ((*p)->size >= size) { + struct equeue_event *e = *p; + if (e->sibling) { + *p = e->sibling; + (*p)->next = e->next; + } else { + *p = e->next; + } + + equeue_mutex_unlock(&q->memlock); + return e; + } + } + + // otherwise allocate a new chunk out of the slab + if (q->slab.size >= size) { + struct equeue_event *e = (struct equeue_event *)q->slab.data; + q->slab.data += size; + q->slab.size -= size; + e->size = size; + e->id = 1; + + equeue_mutex_unlock(&q->memlock); + return e; + } + + equeue_mutex_unlock(&q->memlock); + return 0; +} + +static void equeue_mem_dealloc(equeue_t *q, struct equeue_event *e) { + equeue_mutex_lock(&q->memlock); + + // stick chunk into list of chunks + struct equeue_event **p = &q->chunks; + while (*p && (*p)->size < e->size) { + p = &(*p)->next; + } + + if (*p && (*p)->size == e->size) { + e->sibling = *p; + e->next = (*p)->next; + } else { + e->sibling = 0; + e->next = *p; + } + *p = e; + + equeue_mutex_unlock(&q->memlock); +} + +void *equeue_alloc(equeue_t *q, size_t size) { + struct equeue_event *e = equeue_mem_alloc(q, size); + if (!e) { + return 0; + } + + e->target = 0; + e->period = -1; + e->dtor = 0; + + return e + 1; +} + +void equeue_dealloc(equeue_t *q, void *p) { + struct equeue_event *e = (struct equeue_event*)p - 1; + + if (e->dtor) { + e->dtor(e+1); + } + + equeue_mem_dealloc(q, e); +} + + +// equeue scheduling functions +static int equeue_enqueue(equeue_t *q, struct equeue_event *e, unsigned tick) { + // setup event and hash local id with buffer offset for unique id + int id = (e->id << q->npw2) | ((unsigned char *)e - q->buffer); + e->target = tick + equeue_clampdiff(e->target, tick); + e->generation = q->generation; + + equeue_mutex_lock(&q->queuelock); + + // find the event slot + struct equeue_event **p = &q->queue; + while (*p && equeue_tickdiff((*p)->target, e->target) < 0) { + p = &(*p)->next; + } + + // insert at head in slot + if (*p && (*p)->target == e->target) { + e->next = (*p)->next; + if (e->next) { + e->next->ref = &e->next; + } + + e->sibling = *p; + e->sibling->ref = &e->sibling; + } else { + e->next = *p; + if (e->next) { + e->next->ref = &e->next; + } + + e->sibling = 0; + } + + *p = e; + e->ref = p; + + // notify background timer + if ((q->background.update && q->background.active) && + (q->queue == e && !e->sibling)) { + q->background.update(q->background.timer, + equeue_clampdiff(e->target, tick)); + } + + equeue_mutex_unlock(&q->queuelock); + + return id; +} + +static struct equeue_event *equeue_unqueue(equeue_t *q, int id) { + // decode event from unique id and check that the local id matches + struct equeue_event *e = (struct equeue_event *) + &q->buffer[id & ((1 << q->npw2)-1)]; + + equeue_mutex_lock(&q->queuelock); + if (e->id != id >> q->npw2) { + equeue_mutex_unlock(&q->queuelock); + return 0; + } + + // clear the event and check if already in-flight + e->cb = 0; + e->period = -1; + + int diff = equeue_tickdiff(e->target, q->tick); + if (diff < 0 || (diff == 0 && e->generation != q->generation)) { + equeue_mutex_unlock(&q->queuelock); + return 0; + } + + // disentangle from queue + if (e->sibling) { + e->sibling->next = e->next; + if (e->sibling->next) { + e->sibling->next->ref = &e->sibling->next; + } + + *e->ref = e->sibling; + e->sibling->ref = e->ref; + } else { + *e->ref = e->next; + if (e->next) { + e->next->ref = e->ref; + } + } + + equeue_incid(q, e); + equeue_mutex_unlock(&q->queuelock); + + return e; +} + +static struct equeue_event *equeue_dequeue(equeue_t *q, unsigned target) { + equeue_mutex_lock(&q->queuelock); + + // find all expired events and mark a new generation + q->generation += 1; + if (equeue_tickdiff(q->tick, target) <= 0) { + q->tick = target; + } + + struct equeue_event *head = q->queue; + struct equeue_event **p = &head; + while (*p && equeue_tickdiff((*p)->target, target) <= 0) { + p = &(*p)->next; + } + + q->queue = *p; + if (q->queue) { + q->queue->ref = &q->queue; + } + + *p = 0; + + equeue_mutex_unlock(&q->queuelock); + + // reverse and flatten each slot to match insertion order + struct equeue_event **tail = &head; + struct equeue_event *ess = head; + while (ess) { + struct equeue_event *es = ess; + ess = es->next; + + struct equeue_event *prev = 0; + for (struct equeue_event *e = es; e; e = e->sibling) { + e->next = prev; + prev = e; + } + + *tail = prev; + tail = &es->next; + } + + return head; +} + +int equeue_post(equeue_t *q, void (*cb)(void*), void *p) { + struct equeue_event *e = (struct equeue_event*)p - 1; + unsigned tick = equeue_tick(); + e->cb = cb; + e->target = tick + e->target; + + int id = equeue_enqueue(q, e, tick); + equeue_sema_signal(&q->eventsema); + return id; +} + +void equeue_cancel(equeue_t *q, int id) { + if (!id) { + return; + } + + struct equeue_event *e = equeue_unqueue(q, id); + if (e) { + equeue_dealloc(q, e + 1); + } +} + +void equeue_break(equeue_t *q) { + equeue_mutex_lock(&q->queuelock); + q->breaks++; + equeue_mutex_unlock(&q->queuelock); + equeue_sema_signal(&q->eventsema); +} + +void equeue_dispatch(equeue_t *q, int ms) { + unsigned tick = equeue_tick(); + unsigned timeout = tick + ms; + q->background.active = false; + + while (1) { + // collect all the available events and next deadline + struct equeue_event *es = equeue_dequeue(q, tick); + + // dispatch events + while (es) { + struct equeue_event *e = es; + es = e->next; + + // actually dispatch the callbacks + void (*cb)(void *) = e->cb; + if (cb) { + cb(e + 1); + } + + // reenqueue periodic events or deallocate + if (e->period >= 0) { + e->target += e->period; + equeue_enqueue(q, e, equeue_tick()); + } else { + equeue_incid(q, e); + equeue_dealloc(q, e+1); + } + } + + int deadline = -1; + tick = equeue_tick(); + + // check if we should stop dispatching soon + if (ms >= 0) { + deadline = equeue_tickdiff(timeout, tick); + if (deadline <= 0) { + // update background timer if necessary + if (q->background.update) { + equeue_mutex_lock(&q->queuelock); + if (q->background.update && q->queue) { + q->background.update(q->background.timer, + equeue_clampdiff(q->queue->target, tick)); + } + q->background.active = true; + equeue_mutex_unlock(&q->queuelock); + } + return; + } + } + + // find closest deadline + equeue_mutex_lock(&q->queuelock); + if (q->queue) { + int diff = equeue_clampdiff(q->queue->target, tick); + if ((unsigned)diff < (unsigned)deadline) { + deadline = diff; + } + } + equeue_mutex_unlock(&q->queuelock); + + // wait for events + equeue_sema_wait(&q->eventsema, deadline); + + // check if we were notified to break out of dispatch + if (q->breaks) { + equeue_mutex_lock(&q->queuelock); + if (q->breaks > 0) { + q->breaks--; + equeue_mutex_unlock(&q->queuelock); + return; + } + equeue_mutex_unlock(&q->queuelock); + } + + // update tick for next iteration + tick = equeue_tick(); + } +} + + +// event functions +void equeue_event_delay(void *p, int ms) { + struct equeue_event *e = (struct equeue_event*)p - 1; + e->target = ms; +} + +void equeue_event_period(void *p, int ms) { + struct equeue_event *e = (struct equeue_event*)p - 1; + e->period = ms; +} + +void equeue_event_dtor(void *p, void (*dtor)(void *)) { + struct equeue_event *e = (struct equeue_event*)p - 1; + e->dtor = dtor; +} + + +// simple callbacks +struct ecallback { + void (*cb)(void*); + void *data; +}; + +static void ecallback_dispatch(void *p) { + struct ecallback *e = (struct ecallback*)p; + e->cb(e->data); +} + +int equeue_call(equeue_t *q, void (*cb)(void*), void *data) { + struct ecallback *e = equeue_alloc(q, sizeof(struct ecallback)); + if (!e) { + return 0; + } + + e->cb = cb; + e->data = data; + return equeue_post(q, ecallback_dispatch, e); +} + +int equeue_call_in(equeue_t *q, int ms, void (*cb)(void*), void *data) { + struct ecallback *e = equeue_alloc(q, sizeof(struct ecallback)); + if (!e) { + return 0; + } + + equeue_event_delay(e, ms); + e->cb = cb; + e->data = data; + return equeue_post(q, ecallback_dispatch, e); +} + +int equeue_call_every(equeue_t *q, int ms, void (*cb)(void*), void *data) { + struct ecallback *e = equeue_alloc(q, sizeof(struct ecallback)); + if (!e) { + return 0; + } + + equeue_event_delay(e, ms); + equeue_event_period(e, ms); + e->cb = cb; + e->data = data; + return equeue_post(q, ecallback_dispatch, e); +} + + +// backgrounding +void equeue_background(equeue_t *q, + void (*update)(void *timer, int ms), void *timer) { + equeue_mutex_lock(&q->queuelock); + if (q->background.update) { + q->background.update(q->background.timer, -1); + } + + q->background.update = update; + q->background.timer = timer; + + if (q->background.update && q->queue) { + q->background.update(q->background.timer, + equeue_clampdiff(q->queue->target, equeue_tick())); + } + q->background.active = true; + equeue_mutex_unlock(&q->queuelock); +} + +struct equeue_chain_context { + equeue_t *q; + equeue_t *target; + int id; +}; + +static void equeue_chain_dispatch(void *p) { + equeue_dispatch((equeue_t *)p, 0); +} + +static void equeue_chain_update(void *p, int ms) { + struct equeue_chain_context *c = (struct equeue_chain_context *)p; + equeue_cancel(c->target, c->id); + + if (ms >= 0) { + c->id = equeue_call_in(c->target, ms, equeue_chain_dispatch, c->q); + } else { + equeue_dealloc(c->target, c); + } +} + +void equeue_chain(equeue_t *q, equeue_t *target) { + struct equeue_chain_context *c = equeue_alloc(q, + sizeof(struct equeue_chain_context)); + + c->q = q; + c->target = target; + c->id = 0; + + equeue_background(q, equeue_chain_update, c); +} diff --git a/events/equeue/equeue.h b/events/equeue/equeue.h new file mode 100644 index 0000000..e3e91d7 --- /dev/null +++ b/events/equeue/equeue.h @@ -0,0 +1,218 @@ +/* + * Flexible event queue for dispatching events + * + * Copyright (c) 2016 Christopher Haster + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef EQUEUE_H +#define EQUEUE_H + +#ifdef __cplusplus +extern "C" { +#endif + +// Platform specific files +#include "equeue_platform.h" + +#include +#include + + +// The minimum size of an event +// This size is guaranteed to fit events created by event_call +#define EQUEUE_EVENT_SIZE (sizeof(struct equeue_event) + 2*sizeof(void*)) + +// Internal event structure +struct equeue_event { + unsigned size; + uint8_t id; + uint8_t generation; + + struct equeue_event *next; + struct equeue_event *sibling; + struct equeue_event **ref; + + unsigned target; + int period; + void (*dtor)(void *); + + void (*cb)(void *); + // data follows +}; + +// Event queue structure +typedef struct equeue { + struct equeue_event *queue; + unsigned tick; + unsigned breaks; + uint8_t generation; + + unsigned char *buffer; + unsigned npw2; + void *allocated; + + struct equeue_event *chunks; + struct equeue_slab { + size_t size; + unsigned char *data; + } slab; + + struct equeue_background { + bool active; + void (*update)(void *timer, int ms); + void *timer; + } background; + + equeue_sema_t eventsema; + equeue_mutex_t queuelock; + equeue_mutex_t memlock; +} equeue_t; + + +// Queue lifetime operations +// +// Creates and destroys an event queue. The event queue either allocates a +// buffer of the specified size with malloc or uses a user provided buffer +// if constructed with equeue_create_inplace. +// +// If the event queue creation fails, equeue_create returns a negative, +// platform-specific error code. +int equeue_create(equeue_t *queue, size_t size); +int equeue_create_inplace(equeue_t *queue, size_t size, void *buffer); +void equeue_destroy(equeue_t *queue); + +// Dispatch events +// +// Executes events until the specified milliseconds have passed. If ms is +// negative, equeue_dispatch will dispatch events indefinitely or until +// equeue_break is called on this queue. +// +// When called with a finite timeout, the equeue_dispatch function is +// guaranteed to terminate. When called with a timeout of 0, the +// equeue_dispatch does not wait and is irq safe. +void equeue_dispatch(equeue_t *queue, int ms); + +// Break out of a running event loop +// +// Forces the specified event queue's dispatch loop to terminate. Pending +// events may finish executing, but no new events will be executed. +void equeue_break(equeue_t *queue); + +// Simple event calls +// +// The specified callback will be executed in the context of the event queue's +// dispatch loop. When the callback is executed depends on the call function. +// +// equeue_call - Immediately post an event to the queue +// equeue_call_in - Post an event after a specified time in milliseconds +// equeue_call_every - Post an event periodically every milliseconds +// +// All equeue_call functions are irq safe and can act as a mechanism for +// moving events out of irq contexts. +// +// The return value is a unique id that represents the posted event and can +// be passed to equeue_cancel. If there is not enough memory to allocate the +// event, equeue_call returns an id of 0. +int equeue_call(equeue_t *queue, void (*cb)(void *), void *data); +int equeue_call_in(equeue_t *queue, int ms, void (*cb)(void *), void *data); +int equeue_call_every(equeue_t *queue, int ms, void (*cb)(void *), void *data); + +// Allocate memory for events +// +// The equeue_alloc function allocates an event that can be manually dispatched +// with equeue_post. The equeue_dealloc function may be used to free an event +// that has not been posted. Once posted, an event's memory is managed by the +// event queue and should not be deallocated. +// +// Both equeue_alloc and equeue_dealloc are irq safe. +// +// The equeue allocator is designed to minimize jitter in interrupt contexts as +// well as avoid memory fragmentation on small devices. The allocator achieves +// both constant-runtime and zero-fragmentation for fixed-size events, however +// grows linearly as the quantity of different sized allocations increases. +// +// The equeue_alloc function returns a pointer to the event's allocated memory +// and acts as a handle to the underlying event. If there is not enough memory +// to allocate the event, equeue_alloc returns null. +void *equeue_alloc(equeue_t *queue, size_t size); +void equeue_dealloc(equeue_t *queue, void *event); + +// Configure an allocated event +// +// equeue_event_delay - Millisecond delay before dispatching an event +// equeue_event_period - Millisecond period for repeating dispatching an event +// equeue_event_dtor - Destructor to run when the event is deallocated +void equeue_event_delay(void *event, int ms); +void equeue_event_period(void *event, int ms); +void equeue_event_dtor(void *event, void (*dtor)(void *)); + +// Post an event onto the event queue +// +// The equeue_post function takes a callback and a pointer to an event +// allocated by equeue_alloc. The specified callback will be executed in the +// context of the event queue's dispatch loop with the allocated event +// as its argument. +// +// The equeue_post function is irq safe and can act as a mechanism for +// moving events out of irq contexts. +// +// The return value is a unique id that represents the posted event and can +// be passed to equeue_cancel. +int equeue_post(equeue_t *queue, void (*cb)(void *), void *event); + +// Cancel an in-flight event +// +// Attempts to cancel an event referenced by the unique id returned from +// equeue_call or equeue_post. It is safe to call equeue_cancel after an event +// has already been dispatched. +// +// The equeue_cancel function is irq safe. +// +// If called while the event queue's dispatch loop is active, equeue_cancel +// does not guarantee that the event will not not execute after it returns as +// the event may have already begun executing. +void equeue_cancel(equeue_t *queue, 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. +// +// Passing a null update function disables the existing timer. +// +// The equeue_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. +void equeue_background(equeue_t *queue, + void (*update)(void *timer, int ms), void *timer); + +// Chain an event queue onto another event queue +// +// After chaining a queue to a target, calling equeue_dispatch on the +// target queue will also dispatch events from this queue. The queues +// use their own buffers and events must be managed independently. +// +// Passing a null queue as the target will unchain the existing queue. +// +// The equeue_chain function allows multiple equeues to be composed, sharing +// the context of a dispatch loop while still being managed independently. +void equeue_chain(equeue_t *queue, equeue_t *target); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/events/equeue/equeue_mbed.cpp b/events/equeue/equeue_mbed.cpp new file mode 100644 index 0000000..e6bfc8e --- /dev/null +++ b/events/equeue/equeue_mbed.cpp @@ -0,0 +1,142 @@ +/* + * Implementation for the mbed library + * https://github.com/mbedmicro/mbed + * + * Copyright (c) 2016 Christopher Haster + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "equeue_platform.h" + +#if defined(EQUEUE_PLATFORM_MBED) + +#include +#include "mbed.h" + + +// Ticker operations +static bool equeue_tick_inited = false; +static unsigned equeue_minutes = 0; +static unsigned equeue_timer[ + (sizeof(Timer)+sizeof(unsigned)-1)/sizeof(unsigned)]; +static unsigned equeue_ticker[ + (sizeof(Ticker)+sizeof(unsigned)-1)/sizeof(unsigned)]; + +static void equeue_tick_update() { + reinterpret_cast(equeue_timer)->reset(); + equeue_minutes += 1; +} + +static void equeue_tick_init() { + MBED_ASSERT(sizeof(equeue_timer) >= sizeof(Timer)); + MBED_ASSERT(sizeof(equeue_ticker) >= sizeof(Ticker)); + new (equeue_timer) Timer; + new (equeue_ticker) Ticker; + + equeue_minutes = 0; + reinterpret_cast(equeue_timer)->start(); + reinterpret_cast(equeue_ticker) + ->attach_us(equeue_tick_update, (1 << 16)*1000); + + equeue_tick_inited = true; +} + +unsigned equeue_tick() { + if (!equeue_tick_inited) { + equeue_tick_init(); + } + + unsigned equeue_ms = reinterpret_cast(equeue_timer)->read_ms(); + return (equeue_minutes << 16) + equeue_ms; +} + + +// Mutex operations +int equeue_mutex_create(equeue_mutex_t *m) { return 0; } +void equeue_mutex_destroy(equeue_mutex_t *m) { } + +void equeue_mutex_lock(equeue_mutex_t *m) { + core_util_critical_section_enter(); +} + +void equeue_mutex_unlock(equeue_mutex_t *m) { + core_util_critical_section_exit(); +} + + +// Semaphore operations +#ifdef MBED_CONF_RTOS_PRESENT + +int equeue_sema_create(equeue_sema_t *s) { + MBED_ASSERT(sizeof(equeue_sema_t) >= sizeof(Semaphore)); + new (s) Semaphore(0); + return 0; +} + +void equeue_sema_destroy(equeue_sema_t *s) { + reinterpret_cast(s)->~Semaphore(); +} + +void equeue_sema_signal(equeue_sema_t *s) { + reinterpret_cast(s)->release(); +} + +bool equeue_sema_wait(equeue_sema_t *s, int ms) { + if (ms < 0) { + ms = osWaitForever; + } + + return (reinterpret_cast(s)->wait(ms) > 0); +} + +#else + +// Semaphore operations +int equeue_sema_create(equeue_sema_t *s) { + *s = false; + return 0; +} + +void equeue_sema_destroy(equeue_sema_t *s) { +} + +void equeue_sema_signal(equeue_sema_t *s) { + *s = 1; +} + +static void equeue_sema_timeout(equeue_sema_t *s) { + *s = -1; +} + +bool equeue_sema_wait(equeue_sema_t *s, int ms) { + int signal = 0; + Timeout timeout; + timeout.attach_us(s, equeue_sema_timeout, ms*1000); + + core_util_critical_section_enter(); + while (!*s) { + sleep(); + core_util_critical_section_exit(); + core_util_critical_section_enter(); + } + + signal = *s; + *s = false; + core_util_critical_section_exit(); + + return (signal > 0); +} + +#endif + +#endif diff --git a/events/equeue/equeue_platform.h b/events/equeue/equeue_platform.h new file mode 100644 index 0000000..5eee477 --- /dev/null +++ b/events/equeue/equeue_platform.h @@ -0,0 +1,140 @@ +/* + * System specific implementation + * + * Copyright (c) 2016 Christopher Haster + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef EQUEUE_PLATFORM_H +#define EQUEUE_PLATFORM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +// Currently supported platforms +// +// Uncomment to select a supported platform or reimplement this file +// for a specific target. +//#define EQUEUE_PLATFORM_POSIX +//#define EQUEUE_PLATFORM_MBED + +// Try to infer a platform if none was manually selected +#if !defined(EQUEUE_PLATFORM_POSIX) \ + && !defined(EQUEUE_PLATFORM_MBED) +#if defined(__unix__) +#define EQUEUE_PLATFORM_POSIX +#elif defined(__MBED__) +#define EQUEUE_PLATFORM_MBED +#else +#warning "Unknown platform! Please update equeue_platform.h" +#endif +#endif + +// Platform includes +#if defined(EQUEUE_PLATFORM_POSIX) +#include +#endif + + +// Platform millisecond counter +// +// Return a tick that represents the number of milliseconds that have passed +// since an arbitrary point in time. The granularity does not need to be at +// the millisecond level, however the accuracy of the equeue library is +// limited by the accuracy of this tick. +// +// Must intentionally overflow to 0 after 2^32-1 +unsigned equeue_tick(void); + + +// Platform mutex type +// +// The equeue library requires at minimum a non-recursive mutex that is +// safe in interrupt contexts. The mutex section is help for a bounded +// amount of time, so simply disabling interrupts is acceptable +// +// If irq safety is not required, a regular blocking mutex can be used. +#if defined(EQUEUE_PLATFORM_POSIX) +typedef pthread_mutex_t equeue_mutex_t; +#elif defined(EQUEUE_PLATFORM_WINDOWS) +typedef CRITICAL_SECTION equeue_mutex_t; +#elif defined(EQUEUE_PLATFORM_MBED) +typedef unsigned equeue_mutex_t; +#elif defined(EQUEUE_PLATFORM_FREERTOS) +typedef UBaseType_t equeue_mutex_t; +#endif + +// Platform mutex operations +// +// The equeue_mutex_create and equeue_mutex_destroy manage the lifetime +// of the mutex. On error, equeue_mutex_create should return a negative +// error code. +// +// The equeue_mutex_lock and equeue_mutex_unlock lock and unlock the +// underlying mutex. +int equeue_mutex_create(equeue_mutex_t *mutex); +void equeue_mutex_destroy(equeue_mutex_t *mutex); +void equeue_mutex_lock(equeue_mutex_t *mutex); +void equeue_mutex_unlock(equeue_mutex_t *mutex); + + +// Platform semaphore type +// +// The equeue library requires a binary semaphore type that can be safely +// signaled from interrupt contexts and from inside a equeue_mutex section. +// +// The equeue_signal_wait is relied upon by the equeue library to sleep the +// processor between events. Spurious wakeups have no negative-effects. +// +// A counting semaphore will also work, however may cause the event queue +// dispatch loop to run unnecessarily. For that matter, equeue_signal_wait +// may even be implemented as a single return statement. +#if defined(EQUEUE_PLATFORM_POSIX) +typedef struct equeue_sema { + pthread_mutex_t mutex; + pthread_cond_t cond; + bool signal; +} equeue_sema_t; +#elif defined(EQUEUE_PLATFORM_MBED) && defined(MBED_CONF_RTOS_PRESENT) +typedef unsigned equeue_sema_t[8]; +#elif defined(EQUEUE_PLATFORM_MBED) +typedef volatile int equeue_sema_t; +#endif + +// Platform semaphore operations +// +// The equeue_sema_create and equeue_sema_destroy manage the lifetime +// of the semaphore. On error, equeue_sema_create should return a negative +// error code. +// +// The equeue_sema_signal marks a semaphore as signalled such that the next +// equeue_sema_wait will return true. +// +// The equeue_sema_wait waits for a semaphore to be signalled or returns +// immediately if equeue_sema_signal had been called since the last +// equeue_sema_wait. The equeue_sema_wait returns true if it detected that +// equeue_sema_signal had been called. +int equeue_sema_create(equeue_sema_t *sema); +void equeue_sema_destroy(equeue_sema_t *sema); +void equeue_sema_signal(equeue_sema_t *sema); +bool equeue_sema_wait(equeue_sema_t *sema, int ms); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/events/equeue/equeue_posix.c b/events/equeue/equeue_posix.c new file mode 100644 index 0000000..e13007a --- /dev/null +++ b/events/equeue/equeue_posix.c @@ -0,0 +1,106 @@ +/* + * Implementation for Posix compliant platforms + * + * Copyright (c) 2016 Christopher Haster + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "equeue_platform.h" + +#if defined(EQUEUE_PLATFORM_POSIX) + +#include +#include +#include + + +// Tick operations +unsigned equeue_tick(void) { + struct timeval tv; + gettimeofday(&tv, 0); + return (unsigned)(tv.tv_sec*1000 + tv.tv_usec/1000); +} + + +// Mutex operations +int equeue_mutex_create(equeue_mutex_t *m) { + return pthread_mutex_init(m, 0); +} + +void equeue_mutex_destroy(equeue_mutex_t *m) { + pthread_mutex_destroy(m); +} + +void equeue_mutex_lock(equeue_mutex_t *m) { + pthread_mutex_lock(m); +} + +void equeue_mutex_unlock(equeue_mutex_t *m) { + pthread_mutex_unlock(m); +} + + +// Semaphore operations +int equeue_sema_create(equeue_sema_t *s) { + int err = pthread_mutex_init(&s->mutex, 0); + if (err) { + return err; + } + + err = pthread_cond_init(&s->cond, 0); + if (err) { + return err; + } + + s->signal = false; + return 0; +} + +void equeue_sema_destroy(equeue_sema_t *s) { + pthread_cond_destroy(&s->cond); + pthread_mutex_destroy(&s->mutex); +} + +void equeue_sema_signal(equeue_sema_t *s) { + pthread_mutex_lock(&s->mutex); + s->signal = true; + pthread_cond_signal(&s->cond); + pthread_mutex_unlock(&s->mutex); +} + +bool equeue_sema_wait(equeue_sema_t *s, int ms) { + pthread_mutex_lock(&s->mutex); + if (!s->signal) { + if (ms < 0) { + pthread_cond_wait(&s->cond, &s->mutex); + } else { + struct timeval tv; + gettimeofday(&tv, 0); + + struct timespec ts = { + .tv_sec = ms/1000 + tv.tv_sec, + .tv_nsec = ms*1000000 + tv.tv_usec*1000, + }; + + pthread_cond_timedwait(&s->cond, &s->mutex, &ts); + } + } + + bool signal = s->signal; + s->signal = false; + pthread_mutex_unlock(&s->mutex); + + return signal; +} + +#endif diff --git a/events/equeue/tests/prof.c b/events/equeue/tests/prof.c new file mode 100644 index 0000000..20d5ac5 --- /dev/null +++ b/events/equeue/tests/prof.c @@ -0,0 +1,407 @@ +/* + * Profiling framework for the events library + * + * Copyright (c) 2016 Christopher Haster + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "equeue.h" +#include +#include +#include +#include +#include +#include +#include + + +// Performance measurement utils +#define PROF_RUNS 5 +#define PROF_INTERVAL 100000000 + +#define prof_volatile(t) __attribute__((unused)) volatile t + +typedef uint64_t prof_cycle_t; + +static volatile prof_cycle_t prof_start_cycle; +static volatile prof_cycle_t prof_stop_cycle; +static prof_cycle_t prof_accum_cycle; +static prof_cycle_t prof_baseline_cycle; +static prof_cycle_t prof_iterations; +static const char *prof_units; + +#define prof_cycle() ({ \ + uint32_t a, b; \ + __asm__ volatile ("rdtsc" : "=a" (a), "=d" (b)); \ + ((uint64_t)b << 32) | (uint64_t)a; \ +}) + +#define prof_loop() \ + for (prof_iterations = 0; \ + prof_accum_cycle < PROF_INTERVAL; \ + prof_iterations++) + +#define prof_start() ({ \ + prof_start_cycle = prof_cycle(); \ +}) + +#define prof_stop() ({ \ + prof_stop_cycle = prof_cycle(); \ + prof_accum_cycle += prof_stop_cycle - prof_start_cycle; \ +}) + +#define prof_result(value, units) ({ \ + prof_accum_cycle = value+prof_baseline_cycle; \ + prof_iterations = 1; \ + prof_units = units; \ +}) + +#define prof_measure(func, ...) ({ \ + printf("%s: ...", #func); \ + fflush(stdout); \ + \ + prof_units = "cycles"; \ + prof_cycle_t runs[PROF_RUNS]; \ + for (int i = 0; i < PROF_RUNS; i++) { \ + prof_accum_cycle = 0; \ + prof_iterations = 0; \ + func(__VA_ARGS__); \ + runs[i] = prof_accum_cycle / prof_iterations; \ + } \ + \ + prof_cycle_t res = runs[0]; \ + for (int i = 0; i < PROF_RUNS; i++) { \ + if (runs[i] < res) { \ + res = runs[i]; \ + } \ + } \ + res -= prof_baseline_cycle; \ + printf("\r%s: %"PRIu64" %s", #func, res, prof_units); \ + \ + if (!isatty(0)) { \ + prof_cycle_t prev; \ + while (scanf("%*[^0-9]%"PRIu64, &prev) == 0); \ + int64_t perc = 100*((int64_t)prev - (int64_t)res) / (int64_t)prev; \ + \ + if (perc > 10) { \ + printf(" (\e[32m%+"PRId64"%%\e[0m)", perc); \ + } else if (perc < -10) { \ + printf(" (\e[31m%+"PRId64"%%\e[0m)", perc); \ + } else { \ + printf(" (%+"PRId64"%%)", perc); \ + } \ + } \ + \ + printf("\n"); \ + res; \ +}) + +#define prof_baseline(func, ...) ({ \ + prof_baseline_cycle = 0; \ + prof_baseline_cycle = prof_measure(func, __VA_ARGS__); \ +}) + + +// Various test functions +void no_func(void *eh) { +} + + +// Actual performance tests +void baseline_prof(void) { + prof_loop() { + prof_start(); + __asm__ volatile (""); + prof_stop(); + } +} + +void equeue_tick_prof(void) { + prof_volatile(unsigned) res; + prof_loop() { + prof_start(); + res = equeue_tick(); + prof_stop(); + } +} + +void equeue_alloc_prof(void) { + struct equeue q; + equeue_create(&q, 32*EQUEUE_EVENT_SIZE); + + prof_loop() { + prof_start(); + void *e = equeue_alloc(&q, 8 * sizeof(int)); + prof_stop(); + + equeue_dealloc(&q, e); + } + + equeue_destroy(&q); +} + +void equeue_alloc_many_prof(int count) { + struct equeue q; + equeue_create(&q, count*EQUEUE_EVENT_SIZE); + + void *es[count]; + + for (int i = 0; i < count; i++) { + es[i] = equeue_alloc(&q, (i % 4) * sizeof(int)); + } + + for (int i = 0; i < count; i++) { + equeue_dealloc(&q, es[i]); + } + + prof_loop() { + prof_start(); + void *e = equeue_alloc(&q, 8 * sizeof(int)); + prof_stop(); + + equeue_dealloc(&q, e); + } + + equeue_destroy(&q); +} + +void equeue_post_prof(void) { + struct equeue q; + equeue_create(&q, EQUEUE_EVENT_SIZE); + + prof_loop() { + void *e = equeue_alloc(&q, 0); + + prof_start(); + int id = equeue_post(&q, no_func, e); + prof_stop(); + + equeue_cancel(&q, id); + } + + equeue_destroy(&q); +} + +void equeue_post_many_prof(int count) { + struct equeue q; + equeue_create(&q, count*EQUEUE_EVENT_SIZE); + + for (int i = 0; i < count-1; i++) { + equeue_call(&q, no_func, 0); + } + + prof_loop() { + void *e = equeue_alloc(&q, 0); + + prof_start(); + int id = equeue_post(&q, no_func, e); + prof_stop(); + + equeue_cancel(&q, id); + } + + equeue_destroy(&q); +} + +void equeue_post_future_prof(void) { + struct equeue q; + equeue_create(&q, EQUEUE_EVENT_SIZE); + + prof_loop() { + void *e = equeue_alloc(&q, 0); + equeue_event_delay(e, 1000); + + prof_start(); + int id = equeue_post(&q, no_func, e); + prof_stop(); + + equeue_cancel(&q, id); + } + + equeue_destroy(&q); +} + +void equeue_post_future_many_prof(int count) { + struct equeue q; + equeue_create(&q, count*EQUEUE_EVENT_SIZE); + + for (int i = 0; i < count-1; i++) { + equeue_call(&q, no_func, 0); + } + + prof_loop() { + void *e = equeue_alloc(&q, 0); + equeue_event_delay(e, 1000); + + prof_start(); + int id = equeue_post(&q, no_func, e); + prof_stop(); + + equeue_cancel(&q, id); + } + + equeue_destroy(&q); +} + +void equeue_dispatch_prof(void) { + struct equeue q; + equeue_create(&q, EQUEUE_EVENT_SIZE); + + prof_loop() { + equeue_call(&q, no_func, 0); + + prof_start(); + equeue_dispatch(&q, 0); + prof_stop(); + } + + equeue_destroy(&q); +} + +void equeue_dispatch_many_prof(int count) { + struct equeue q; + equeue_create(&q, count*EQUEUE_EVENT_SIZE); + + prof_loop() { + for (int i = 0; i < count; i++) { + equeue_call(&q, no_func, 0); + } + + prof_start(); + equeue_dispatch(&q, 0); + prof_stop(); + } + + equeue_destroy(&q); +} + +void equeue_cancel_prof(void) { + struct equeue q; + equeue_create(&q, EQUEUE_EVENT_SIZE); + + prof_loop() { + int id = equeue_call(&q, no_func, 0); + + prof_start(); + equeue_cancel(&q, id); + prof_stop(); + } + + equeue_destroy(&q); +} + +void equeue_cancel_many_prof(int count) { + struct equeue q; + equeue_create(&q, count*EQUEUE_EVENT_SIZE); + + for (int i = 0; i < count-1; i++) { + equeue_call(&q, no_func, 0); + } + + prof_loop() { + int id = equeue_call(&q, no_func, 0); + + prof_start(); + equeue_cancel(&q, id); + prof_stop(); + } + + equeue_destroy(&q); +} + +void equeue_alloc_size_prof(void) { + size_t size = 32*EQUEUE_EVENT_SIZE; + + struct equeue q; + equeue_create(&q, size); + equeue_alloc(&q, 0); + + prof_result(size - q.slab.size, "bytes"); + + equeue_destroy(&q); +} + +void equeue_alloc_many_size_prof(int count) { + size_t size = count*EQUEUE_EVENT_SIZE; + + struct equeue q; + equeue_create(&q, size); + + for (int i = 0; i < count; i++) { + equeue_alloc(&q, (i % 4) * sizeof(int)); + } + + prof_result(size - q.slab.size, "bytes"); + + equeue_destroy(&q); +} + +void equeue_alloc_fragmented_size_prof(int count) { + size_t size = count*EQUEUE_EVENT_SIZE; + + struct equeue q; + equeue_create(&q, size); + + void *es[count]; + + for (int i = 0; i < count; i++) { + es[i] = equeue_alloc(&q, (i % 4) * sizeof(int)); + } + + for (int i = 0; i < count; i++) { + equeue_dealloc(&q, es[i]); + } + + for (int i = count-1; i >= 0; i--) { + es[i] = equeue_alloc(&q, (i % 4) * sizeof(int)); + } + + for (int i = count-1; i >= 0; i--) { + equeue_dealloc(&q, es[i]); + } + + for (int i = 0; i < count; i++) { + equeue_alloc(&q, (i % 4) * sizeof(int)); + } + + prof_result(size - q.slab.size, "bytes"); + + equeue_destroy(&q); +} + + +// Entry point +int main() { + printf("beginning profiling...\n"); + + prof_baseline(baseline_prof); + + prof_measure(equeue_tick_prof); + prof_measure(equeue_alloc_prof); + prof_measure(equeue_post_prof); + prof_measure(equeue_post_future_prof); + prof_measure(equeue_dispatch_prof); + prof_measure(equeue_cancel_prof); + + prof_measure(equeue_alloc_many_prof, 1000); + prof_measure(equeue_post_many_prof, 1000); + prof_measure(equeue_post_future_many_prof, 1000); + prof_measure(equeue_dispatch_many_prof, 100); + prof_measure(equeue_cancel_many_prof, 100); + + prof_measure(equeue_alloc_size_prof); + prof_measure(equeue_alloc_many_size_prof, 1000); + prof_measure(equeue_alloc_fragmented_size_prof, 1000); + + printf("done!\n"); +} diff --git a/events/equeue/tests/tests.c b/events/equeue/tests/tests.c new file mode 100644 index 0000000..fc7ad81 --- /dev/null +++ b/events/equeue/tests/tests.c @@ -0,0 +1,681 @@ +/* + * Testing framework for the events library + * + * Copyright (c) 2016 Christopher Haster + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "equeue.h" +#include +#include +#include +#include +#include +#include + + +// Testing setup +static jmp_buf test_buf; +static int test_line; +static int test_failure; + +#define test_assert(test) ({ \ + if (!(test)) { \ + test_line = __LINE__; \ + longjmp(test_buf, 1); \ + } \ +}) + +#define test_run(func, ...) ({ \ + printf("%s: ...", #func); \ + fflush(stdout); \ + \ + if (!setjmp(test_buf)) { \ + func(__VA_ARGS__); \ + printf("\r%s: \e[32mpassed\e[0m\n", #func); \ + } else { \ + printf("\r%s: \e[31mfailed\e[0m at line %d\n", #func, test_line); \ + test_failure = true; \ + } \ +}) + + +// Test functions +void pass_func(void *eh) { +} + +void simple_func(void *p) { + (*(int *)p)++; +} + +void sloth_func(void *p) { + usleep(10000); + (*(int *)p)++; +} + +struct indirect { + int *touched; + uint8_t buffer[7]; +}; + +void indirect_func(void *p) { + struct indirect *i = (struct indirect*)p; + (*i->touched)++; +} + +struct timing { + unsigned tick; + unsigned delay; +}; + +void timing_func(void *p) { + struct timing *timing = (struct timing*)p; + unsigned tick = equeue_tick(); + + unsigned t1 = timing->delay; + unsigned t2 = tick - timing->tick; + test_assert(t1 > t2 - 10 && t1 < t2 + 10); + + timing->tick = tick; +} + +struct fragment { + equeue_t *q; + size_t size; + struct timing timing; +}; + +void fragment_func(void *p) { + struct fragment *fragment = (struct fragment*)p; + timing_func(&fragment->timing); + + struct fragment *nfragment = equeue_alloc(fragment->q, fragment->size); + test_assert(nfragment); + + *nfragment = *fragment; + equeue_event_delay(nfragment, fragment->timing.delay); + + int id = equeue_post(nfragment->q, fragment_func, nfragment); + test_assert(id); +} + +struct cancel { + equeue_t *q; + int id; +}; + +void cancel_func(void *p) { + struct cancel *cancel = (struct cancel *)p; + equeue_cancel(cancel->q, cancel->id); +} + +struct nest { + equeue_t *q; + void (*cb)(void *); + void *data; +}; + +void nest_func(void *p) { + struct nest *nest = (struct nest *)p; + equeue_call(nest->q, nest->cb, nest->data); + + usleep(10000); +} + + +// Simple call tests +void simple_call_test(void) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + bool touched = false; + equeue_call(&q, simple_func, &touched); + equeue_dispatch(&q, 0); + test_assert(touched); + + equeue_destroy(&q); +} + +void simple_call_in_test(void) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + bool touched = false; + int id = equeue_call_in(&q, 10, simple_func, &touched); + test_assert(id); + + equeue_dispatch(&q, 15); + test_assert(touched); + + equeue_destroy(&q); +} + +void simple_call_every_test(void) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + bool touched = false; + int id = equeue_call_every(&q, 10, simple_func, &touched); + test_assert(id); + + equeue_dispatch(&q, 15); + test_assert(touched); + + equeue_destroy(&q); +} + +void simple_post_test(void) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + int touched = false; + struct indirect *i = equeue_alloc(&q, sizeof(struct indirect)); + test_assert(i); + + i->touched = &touched; + int id = equeue_post(&q, indirect_func, i); + test_assert(id); + + equeue_dispatch(&q, 0); + test_assert(*i->touched); + + equeue_destroy(&q); +} + +// Misc tests +void destructor_test(void) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + int touched; + struct indirect *e; + int ids[3]; + + touched = 0; + for (int i = 0; i < 3; i++) { + e = equeue_alloc(&q, sizeof(struct indirect)); + test_assert(e); + + e->touched = &touched; + equeue_event_dtor(e, indirect_func); + int id = equeue_post(&q, pass_func, e); + test_assert(id); + } + + equeue_dispatch(&q, 0); + test_assert(touched == 3); + + touched = 0; + for (int i = 0; i < 3; i++) { + e = equeue_alloc(&q, sizeof(struct indirect)); + test_assert(e); + + e->touched = &touched; + equeue_event_dtor(e, indirect_func); + ids[i] = equeue_post(&q, pass_func, e); + test_assert(ids[i]); + } + + for (int i = 0; i < 3; i++) { + equeue_cancel(&q, ids[i]); + } + + equeue_dispatch(&q, 0); + test_assert(touched == 3); + + touched = 0; + for (int i = 0; i < 3; i++) { + e = equeue_alloc(&q, sizeof(struct indirect)); + test_assert(e); + + e->touched = &touched; + equeue_event_dtor(e, indirect_func); + int id = equeue_post(&q, pass_func, e); + test_assert(id); + } + + equeue_destroy(&q); + test_assert(touched == 3); +} + +void allocation_failure_test(void) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + void *p = equeue_alloc(&q, 4096); + test_assert(!p); + + for (int i = 0; i < 100; i++) { + p = equeue_alloc(&q, 0); + } + test_assert(!p); + + equeue_destroy(&q); +} + +void cancel_test(int N) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + bool touched = false; + int *ids = malloc(N*sizeof(int)); + + for (int i = 0; i < N; i++) { + ids[i] = equeue_call(&q, simple_func, &touched); + } + + for (int i = N-1; i >= 0; i--) { + equeue_cancel(&q, ids[i]); + } + + free(ids); + + equeue_dispatch(&q, 0); + test_assert(!touched); + + equeue_destroy(&q); +} + +void cancel_inflight_test(void) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + bool touched = false; + + int id = equeue_call(&q, simple_func, &touched); + equeue_cancel(&q, id); + + equeue_dispatch(&q, 0); + test_assert(!touched); + + id = equeue_call(&q, simple_func, &touched); + equeue_cancel(&q, id); + + equeue_dispatch(&q, 0); + test_assert(!touched); + + struct cancel *cancel = equeue_alloc(&q, sizeof(struct cancel)); + test_assert(cancel); + cancel->q = &q; + cancel->id = 0; + + id = equeue_post(&q, cancel_func, cancel); + test_assert(id); + + cancel->id = equeue_call(&q, simple_func, &touched); + + equeue_dispatch(&q, 0); + test_assert(!touched); + + equeue_destroy(&q); +} + +void cancel_unnecessarily_test(void) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + int id = equeue_call(&q, pass_func, 0); + for (int i = 0; i < 5; i++) { + equeue_cancel(&q, id); + } + + id = equeue_call(&q, pass_func, 0); + equeue_dispatch(&q, 0); + for (int i = 0; i < 5; i++) { + equeue_cancel(&q, id); + } + + bool touched = false; + equeue_call(&q, simple_func, &touched); + for (int i = 0; i < 5; i++) { + equeue_cancel(&q, id); + } + + equeue_dispatch(&q, 0); + test_assert(touched); + + equeue_destroy(&q); +} + +void loop_protect_test(void) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + bool touched = false; + equeue_call_every(&q, 0, simple_func, &touched); + + equeue_dispatch(&q, 0); + test_assert(touched); + + touched = false; + equeue_call_every(&q, 1, simple_func, &touched); + + equeue_dispatch(&q, 0); + test_assert(touched); + + equeue_destroy(&q); +} + +void break_test(void) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + bool touched = false; + equeue_call_every(&q, 0, simple_func, &touched); + + equeue_break(&q); + equeue_dispatch(&q, -1); + test_assert(touched); + + equeue_destroy(&q); +} + +void period_test(void) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + int count = 0; + equeue_call_every(&q, 10, simple_func, &count); + + equeue_dispatch(&q, 55); + test_assert(count == 5); + + equeue_destroy(&q); +} + +void nested_test(void) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + int touched = 0; + struct nest *nest = equeue_alloc(&q, sizeof(struct nest)); + test_assert(nest); + nest->q = &q; + nest->cb = simple_func; + nest->data = &touched; + + int id = equeue_post(&q, nest_func, nest); + test_assert(id); + + equeue_dispatch(&q, 5); + test_assert(touched == 0); + + equeue_dispatch(&q, 5); + test_assert(touched == 1); + + touched = 0; + nest = equeue_alloc(&q, sizeof(struct nest)); + test_assert(nest); + nest->q = &q; + nest->cb = simple_func; + nest->data = &touched; + + id = equeue_post(&q, nest_func, nest); + test_assert(id); + + equeue_dispatch(&q, 20); + test_assert(touched == 1); + + equeue_destroy(&q); +} + +void sloth_test(void) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + int touched = 0; + int id = equeue_call(&q, sloth_func, &touched); + test_assert(id); + + id = equeue_call_in(&q, 5, simple_func, &touched); + test_assert(id); + + id = equeue_call_in(&q, 15, simple_func, &touched); + test_assert(id); + + equeue_dispatch(&q, 20); + test_assert(touched == 3); + + equeue_destroy(&q); +} + +void *multithread_thread(void *p) { + equeue_t *q = (equeue_t *)p; + equeue_dispatch(q, -1); + return 0; +} + +void multithread_test(void) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + int touched = 0; + equeue_call_every(&q, 1, simple_func, &touched); + + pthread_t thread; + err = pthread_create(&thread, 0, multithread_thread, &q); + test_assert(!err); + + usleep(10000); + equeue_break(&q); + err = pthread_join(thread, 0); + test_assert(!err); + + test_assert(touched); + + equeue_destroy(&q); +} + +void background_func(void *p, int ms) { + *(unsigned *)p = ms; +} + +void background_test(void) { + equeue_t q; + int err = equeue_create(&q, 2048); + test_assert(!err); + + int id = equeue_call_in(&q, 20, pass_func, 0); + test_assert(id); + + unsigned ms; + equeue_background(&q, background_func, &ms); + test_assert(ms == 20); + + id = equeue_call_in(&q, 10, pass_func, 0); + test_assert(id); + test_assert(ms == 10); + + id = equeue_call(&q, pass_func, 0); + test_assert(id); + test_assert(ms == 0); + + equeue_dispatch(&q, 0); + test_assert(ms == 10); + + equeue_destroy(&q); + test_assert(ms == -1); +} + +void chain_test(void) { + equeue_t q1; + int err = equeue_create(&q1, 2048); + test_assert(!err); + + equeue_t q2; + err = equeue_create(&q2, 2048); + test_assert(!err); + + equeue_chain(&q2, &q1); + + int touched = 0; + + int id1 = equeue_call_in(&q1, 20, simple_func, &touched); + int id2 = equeue_call_in(&q2, 20, simple_func, &touched); + test_assert(id1 && id2); + + id1 = equeue_call(&q1, simple_func, &touched); + id2 = equeue_call(&q2, simple_func, &touched); + test_assert(id1 && id2); + + id1 = equeue_call_in(&q1, 5, simple_func, &touched); + id2 = equeue_call_in(&q2, 5, simple_func, &touched); + test_assert(id1 && id2); + + equeue_cancel(&q1, id1); + equeue_cancel(&q2, id2); + + id1 = equeue_call_in(&q1, 10, simple_func, &touched); + id2 = equeue_call_in(&q2, 10, simple_func, &touched); + test_assert(id1 && id2); + + equeue_dispatch(&q1, 30); + + test_assert(touched == 6); +} + +// Barrage tests +void simple_barrage_test(int N) { + equeue_t q; + int err = equeue_create(&q, N*(EQUEUE_EVENT_SIZE+sizeof(struct timing))); + test_assert(!err); + + for (int i = 0; i < N; i++) { + struct timing *timing = equeue_alloc(&q, sizeof(struct timing)); + test_assert(timing); + + timing->tick = equeue_tick(); + timing->delay = (i+1)*100; + equeue_event_delay(timing, timing->delay); + equeue_event_period(timing, timing->delay); + + int id = equeue_post(&q, timing_func, timing); + test_assert(id); + } + + equeue_dispatch(&q, N*100); + + equeue_destroy(&q); +} + +void fragmenting_barrage_test(int N) { + equeue_t q; + int err = equeue_create(&q, + 2*N*(EQUEUE_EVENT_SIZE+sizeof(struct fragment)+N*sizeof(int))); + test_assert(!err); + + for (int i = 0; i < N; i++) { + size_t size = sizeof(struct fragment) + i*sizeof(int); + struct fragment *fragment = equeue_alloc(&q, size); + test_assert(fragment); + + fragment->q = &q; + fragment->size = size; + fragment->timing.tick = equeue_tick(); + fragment->timing.delay = (i+1)*100; + equeue_event_delay(fragment, fragment->timing.delay); + + int id = equeue_post(&q, fragment_func, fragment); + test_assert(id); + } + + equeue_dispatch(&q, N*100); + + equeue_destroy(&q); +} + +struct ethread { + pthread_t thread; + equeue_t *q; + int ms; +}; + +static void *ethread_dispatch(void *p) { + struct ethread *t = (struct ethread*)p; + equeue_dispatch(t->q, t->ms); + return 0; +} + +void multithreaded_barrage_test(int N) { + equeue_t q; + int err = equeue_create(&q, N*(EQUEUE_EVENT_SIZE+sizeof(struct timing))); + test_assert(!err); + + struct ethread t; + t.q = &q; + t.ms = N*100; + err = pthread_create(&t.thread, 0, ethread_dispatch, &t); + test_assert(!err); + + for (int i = 0; i < N; i++) { + struct timing *timing = equeue_alloc(&q, sizeof(struct timing)); + test_assert(timing); + + timing->tick = equeue_tick(); + timing->delay = (i+1)*100; + equeue_event_delay(timing, timing->delay); + equeue_event_period(timing, timing->delay); + + int id = equeue_post(&q, timing_func, timing); + test_assert(id); + } + + err = pthread_join(t.thread, 0); + test_assert(!err); + + equeue_destroy(&q); +} + + +int main() { + printf("beginning tests...\n"); + + test_run(simple_call_test); + test_run(simple_call_in_test); + test_run(simple_call_every_test); + test_run(simple_post_test); + test_run(destructor_test); + test_run(allocation_failure_test); + test_run(cancel_test, 20); + test_run(cancel_inflight_test); + test_run(cancel_unnecessarily_test); + test_run(loop_protect_test); + test_run(break_test); + test_run(period_test); + test_run(nested_test); + test_run(sloth_test); + test_run(background_test); + test_run(chain_test); + test_run(multithread_test); + test_run(simple_barrage_test, 20); + test_run(fragmenting_barrage_test, 20); + test_run(multithreaded_barrage_test, 20); + + printf("done!\n"); + return test_failure; +} diff --git a/events/mbed_events.h b/events/mbed_events.h new file mode 100644 index 0000000..a631723 --- /dev/null +++ b/events/mbed_events.h @@ -0,0 +1,33 @@ +/* events + * Copyright (c) 2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_EVENTS_H +#define MBED_EVENTS_H + + +#include "equeue/equeue.h" + + +#ifdef __cplusplus + +#include "EventQueue.h" +#include "Event.h" + +using namespace events; + +#endif + + +#endif