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

Commit 3a55c74

Browse files
committed
Added function for chaining event queues together
The equeue_chain function chains one queue onto a target queue. Calling equeue_dispatch on the target queue will also dispatch events on the target, however each queue uses their own buffers and events are handled independently. The equeue_chain adds a very powerful level of composability for equeues freely built on the equeue_background function. This allows multiple modules to own their own event queues while maintaining composability on threadless systems.
1 parent bac1fb6 commit 3a55c74

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

equeue.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,3 +484,35 @@ void equeue_background(equeue_t *q,
484484
q->background.active = true;
485485
equeue_mutex_unlock(&q->queuelock);
486486
}
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.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,19 @@ void equeue_cancel(equeue_t *queue, int event);
146146
//
147147
// The provided update function will be called to indicate when the queue
148148
// should be dispatched. A negative timeout will be passed to the update
149-
// function when the timer is no longer needed.
149+
// function when the timer is no longer needed. A null update function
150+
// will disable the existing timer.
150151
void equeue_background(equeue_t *queue,
151152
void (*update)(void *timer, int ms), void *timer);
152153

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+
153162

154163
#ifdef __cplusplus
155164
}

tests/tests.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,43 @@ void background_test(void) {
510510
test_assert(ms == -1);
511511
}
512512

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+
513550
// Barrage tests
514551
void simple_barrage_test(int N) {
515552
equeue_t q;
@@ -621,6 +658,7 @@ int main() {
621658
test_run(nested_test);
622659
test_run(sloth_test);
623660
test_run(background_test);
661+
test_run(chain_test);
624662
test_run(multithread_test);
625663
test_run(simple_barrage_test, 20);
626664
test_run(fragmenting_barrage_test, 20);

0 commit comments

Comments
 (0)