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

Commit 4dde583

Browse files
committed
Adopted the queue composition functions from the equeue library
Adds the following: - EventQueue::background - EventQueue::chain
2 parents 41e62fc + 7e51cd2 commit 4dde583

File tree

5 files changed

+209
-0
lines changed

5 files changed

+209
-0
lines changed

EventQueue.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,20 @@ void EventQueue::cancel(int id) {
3232
return equeue_cancel(&_equeue, id);
3333
}
3434

35+
void EventQueue::background(Callback<void(int)> update) {
36+
_update = update;
37+
38+
if (_update) {
39+
equeue_background(&_equeue, &Callback<void(int)>::thunk, &_update);
40+
} else {
41+
equeue_background(&_equeue, 0, 0);
42+
}
43+
}
44+
45+
void EventQueue::chain(EventQueue *target) {
46+
if (target) {
47+
equeue_chain(&_equeue, &target->_equeue);
48+
} else {
49+
equeue_chain(&_equeue, 0);
50+
}
51+
}

EventQueue.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,29 @@ class EventQueue {
8080
*/
8181
void cancel(int id);
8282

83+
/** Background an event queue onto a single-shot timer
84+
*
85+
* The provided update function will be called to indicate when the queue
86+
* should be dispatched. A negative timeout will be passed to the update
87+
* function when the timer is no longer needed. A null update function
88+
* will disable the existing timer.
89+
*
90+
* @param update Function called to indicate when the queue should be
91+
* dispatched
92+
*/
93+
void background(mbed::Callback<void(int)> update);
94+
95+
/** Chain an event queue onto another event queue
96+
*
97+
* After chaining a queue to a target, calling dispatch on the target
98+
* queue will also dispatch events from this queue. The queues will use
99+
* their own buffers and events are handled independently. A null queue
100+
* as the target will unchain the queue.
101+
*
102+
* @param target Queue to chain onto
103+
*/
104+
void chain(EventQueue *target);
105+
83106
/** Post an event to the queue
84107
*
85108
* @param f Function to call on event dispatch
@@ -221,6 +244,7 @@ class EventQueue {
221244
void break_();
222245

223246
struct equeue _equeue;
247+
mbed::Callback<void(int)> _update;
224248

225249
template <typename F, typename A0, typename A1, typename A2, typename A3, typename A4>
226250
struct Context5 {

equeue/equeue.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ int equeue_create_inplace(equeue_t *q, size_t size, void *buffer) {
3939
q->generation = 0;
4040
q->breaks = 0;
4141

42+
q->background.active = false;
43+
q->background.update = 0;
44+
q->background.timer = 0;
45+
4246
int err;
4347
err = equeue_sema_create(&q->eventsema);
4448
if (err < 0) {
@@ -68,6 +72,10 @@ void equeue_destroy(equeue_t *q) {
6872
}
6973
}
7074

75+
if (q->background.update) {
76+
q->background.update(q->background.timer, -1);
77+
}
78+
7179
equeue_mutex_destroy(&q->memlock);
7280
equeue_mutex_destroy(&q->queuelock);
7381
equeue_sema_destroy(&q->eventsema);
@@ -199,6 +207,11 @@ static int equeue_enqueue(equeue_t *q, struct equeue_event *e, unsigned ms) {
199207
*p = e;
200208
e->ref = p;
201209

210+
if ((q->background.update && q->background.active) &&
211+
(q->queue == e && !e->sibling)) {
212+
q->background.update(q->background.timer, ms);
213+
}
214+
202215
equeue_mutex_unlock(&q->queuelock);
203216

204217
return id;
@@ -312,6 +325,7 @@ void equeue_break(equeue_t *q) {
312325
void equeue_dispatch(equeue_t *q, int ms) {
313326
unsigned tick = equeue_tick();
314327
unsigned timeout = tick + ms;
328+
q->background.active = false;
315329

316330
while (1) {
317331
// collect all the available events and next deadline
@@ -344,6 +358,16 @@ void equeue_dispatch(equeue_t *q, int ms) {
344358
if (ms >= 0) {
345359
deadline = equeue_tickdiff(timeout, tick);
346360
if (deadline <= 0) {
361+
// update background timer if necessary
362+
if (q->background.update) {
363+
equeue_mutex_lock(&q->queuelock);
364+
if (q->background.update && q->queue) {
365+
q->background.update(q->background.timer,
366+
equeue_tickdiff(q->queue->target, tick));
367+
}
368+
q->background.active = true;
369+
equeue_mutex_unlock(&q->queuelock);
370+
}
347371
return;
348372
}
349373
}
@@ -441,3 +465,54 @@ int equeue_call_every(equeue_t *q, int ms, void (*cb)(void*), void *data) {
441465
e->data = data;
442466
return equeue_post(q, ecallback_dispatch, e);
443467
}
468+
469+
// backgrounding
470+
void equeue_background(equeue_t *q,
471+
void (*update)(void *timer, int ms), void *timer) {
472+
equeue_mutex_lock(&q->queuelock);
473+
if (q->background.update) {
474+
q->background.update(q->background.timer, -1);
475+
}
476+
477+
q->background.update = update;
478+
q->background.timer = timer;
479+
480+
if (q->background.update && q->queue) {
481+
q->background.update(q->background.timer,
482+
equeue_tickdiff(q->queue->target, equeue_tick()));
483+
}
484+
q->background.active = true;
485+
equeue_mutex_unlock(&q->queuelock);
486+
}
487+
488+
struct equeue_chain_context {
489+
equeue_t *q;
490+
equeue_t *target;
491+
int id;
492+
};
493+
494+
static void equeue_chain_dispatch(void *p) {
495+
equeue_dispatch((equeue_t *)p, 0);
496+
}
497+
498+
static void equeue_chain_update(void *p, int ms) {
499+
struct equeue_chain_context *c = (struct equeue_chain_context *)p;
500+
equeue_cancel(c->target, c->id);
501+
502+
if (ms >= 0) {
503+
c->id = equeue_call_in(c->target, ms, equeue_chain_dispatch, c->q);
504+
} else {
505+
equeue_dealloc(c->target, c);
506+
}
507+
}
508+
509+
void equeue_chain(equeue_t *q, equeue_t *target) {
510+
struct equeue_chain_context *c = equeue_alloc(q,
511+
sizeof(struct equeue_chain_context));
512+
513+
c->q = q;
514+
c->target = target;
515+
c->id = 0;
516+
517+
equeue_background(q, equeue_chain_update, c);
518+
}

equeue/equeue.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ typedef struct equeue {
5858
unsigned char *data;
5959
} slab;
6060

61+
struct equeue_background {
62+
bool active;
63+
void (*update)(void *timer, int ms);
64+
void *timer;
65+
} background;
66+
6167
equeue_sema_t eventsema;
6268
equeue_mutex_t queuelock;
6369
equeue_mutex_t memlock;
@@ -136,6 +142,23 @@ int equeue_post(equeue_t *queue, void (*cb)(void *), void *event);
136142
// stop a currently executing event
137143
void equeue_cancel(equeue_t *queue, int event);
138144

145+
// Background an event queue onto a single-shot timer
146+
//
147+
// The provided update function will be called to indicate when the queue
148+
// should be dispatched. A negative timeout will be passed to the update
149+
// function when the timer is no longer needed. A null update function
150+
// will disable the existing timer.
151+
void equeue_background(equeue_t *queue,
152+
void (*update)(void *timer, int ms), void *timer);
153+
154+
// Chain an event queue onto another event queue
155+
//
156+
// After chaining a queue to a target, calling equeue_dispatch on the
157+
// target queue will also dispatch events from this queue. The queues
158+
// will use their own buffers and events are handled independently.
159+
// A null queue as the target will unchain this queue.
160+
void equeue_chain(equeue_t *queue, equeue_t *target);
161+
139162

140163
#ifdef __cplusplus
141164
}

equeue/tests/tests.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,74 @@ void multithread_test(void) {
479479
equeue_destroy(&q);
480480
}
481481

482+
void background_func(void *p, int ms) {
483+
*(unsigned *)p = ms;
484+
}
485+
486+
void background_test(void) {
487+
equeue_t q;
488+
int err = equeue_create(&q, 2048);
489+
test_assert(!err);
490+
491+
int id = equeue_call_in(&q, 20, pass_func, 0);
492+
test_assert(id);
493+
494+
unsigned ms;
495+
equeue_background(&q, background_func, &ms);
496+
test_assert(ms == 20);
497+
498+
id = equeue_call_in(&q, 10, pass_func, 0);
499+
test_assert(id);
500+
test_assert(ms == 10);
501+
502+
id = equeue_call(&q, pass_func, 0);
503+
test_assert(id);
504+
test_assert(ms == 0);
505+
506+
equeue_dispatch(&q, 0);
507+
test_assert(ms == 10);
508+
509+
equeue_destroy(&q);
510+
test_assert(ms == -1);
511+
}
512+
513+
void chain_test(void) {
514+
equeue_t q1;
515+
int err = equeue_create(&q1, 2048);
516+
test_assert(!err);
517+
518+
equeue_t q2;
519+
err = equeue_create(&q2, 2048);
520+
test_assert(!err);
521+
522+
equeue_chain(&q2, &q1);
523+
524+
int touched = 0;
525+
526+
int id1 = equeue_call_in(&q1, 20, simple_func, &touched);
527+
int id2 = equeue_call_in(&q2, 20, simple_func, &touched);
528+
test_assert(id1 && id2);
529+
530+
id1 = equeue_call(&q1, simple_func, &touched);
531+
id2 = equeue_call(&q2, simple_func, &touched);
532+
test_assert(id1 && id2);
533+
534+
id1 = equeue_call_in(&q1, 5, simple_func, &touched);
535+
id2 = equeue_call_in(&q2, 5, simple_func, &touched);
536+
test_assert(id1 && id2);
537+
538+
equeue_cancel(&q1, id1);
539+
equeue_cancel(&q2, id2);
540+
541+
id1 = equeue_call_in(&q1, 10, simple_func, &touched);
542+
id2 = equeue_call_in(&q2, 10, simple_func, &touched);
543+
test_assert(id1 && id2);
544+
545+
equeue_dispatch(&q1, 30);
546+
547+
test_assert(touched == 6);
548+
}
549+
482550
// Barrage tests
483551
void simple_barrage_test(int N) {
484552
equeue_t q;
@@ -589,6 +657,8 @@ int main() {
589657
test_run(period_test);
590658
test_run(nested_test);
591659
test_run(sloth_test);
660+
test_run(background_test);
661+
test_run(chain_test);
592662
test_run(multithread_test);
593663
test_run(simple_barrage_test, 20);
594664
test_run(fragmenting_barrage_test, 20);

0 commit comments

Comments
 (0)