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

Commit 90f2b7d

Browse files
committed
Fixed underflow issue in deadline calculation
Before this fix, it was possible to create a negative deadline in the dispatch function. Other than the fact that this is questionably defined behaviour, very specific circumstances could cause the semaphore to wait indefinitely despite pending events.
1 parent 599964f commit 90f2b7d

File tree

2 files changed

+110
-1
lines changed

2 files changed

+110
-1
lines changed

equeue.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,9 @@ void equeue_dispatch(equeue_t *q, int ms) {
352352
equeue_mutex_lock(&q->queuelock);
353353
if (q->queue) {
354354
int diff = equeue_tickdiff(q->queue->target, tick);
355-
if (deadline < 0 || diff < deadline) {
355+
if (diff <= 0) {
356+
deadline = 0;
357+
} else if (deadline < 0 || diff < deadline) {
356358
deadline = diff;
357359
}
358360
}

tests/tests.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ void simple_func(void *p) {
4646
(*(int *)p)++;
4747
}
4848

49+
void sloth_func(void *p) {
50+
usleep(10000);
51+
(*(int *)p)++;
52+
}
53+
4954
struct indirect {
5055
int *touched;
5156
uint8_t buffer[7];
@@ -102,6 +107,19 @@ void cancel_func(void *p) {
102107
equeue_cancel(cancel->q, cancel->id);
103108
}
104109

110+
struct nest {
111+
equeue_t *q;
112+
void (*cb)(void *);
113+
void *data;
114+
};
115+
116+
void nest_func(void *p) {
117+
struct nest *nest = (struct nest *)p;
118+
equeue_call(nest->q, nest->cb, nest->data);
119+
120+
usleep(10000);
121+
}
122+
105123

106124
// Simple call tests
107125
void simple_call_test(void) {
@@ -375,6 +393,92 @@ void period_test(void) {
375393
equeue_destroy(&q);
376394
}
377395

396+
void nested_test(void) {
397+
equeue_t q;
398+
int err = equeue_create(&q, 2048);
399+
test_assert(!err);
400+
401+
int touched = 0;
402+
struct nest *nest = equeue_alloc(&q, sizeof(struct nest));
403+
test_assert(nest);
404+
nest->q = &q;
405+
nest->cb = simple_func;
406+
nest->data = &touched;
407+
408+
int id = equeue_post(&q, nest_func, nest);
409+
test_assert(id);
410+
411+
equeue_dispatch(&q, 5);
412+
test_assert(touched == 0);
413+
414+
equeue_dispatch(&q, 5);
415+
test_assert(touched == 1);
416+
417+
touched = 0;
418+
nest = equeue_alloc(&q, sizeof(struct nest));
419+
test_assert(nest);
420+
nest->q = &q;
421+
nest->cb = simple_func;
422+
nest->data = &touched;
423+
424+
id = equeue_post(&q, nest_func, nest);
425+
test_assert(id);
426+
427+
equeue_dispatch(&q, 20);
428+
test_assert(touched == 1);
429+
430+
equeue_destroy(&q);
431+
}
432+
433+
void sloth_test(void) {
434+
equeue_t q;
435+
int err = equeue_create(&q, 2048);
436+
test_assert(!err);
437+
438+
int touched = 0;
439+
int id = equeue_call(&q, sloth_func, &touched);
440+
test_assert(id);
441+
442+
id = equeue_call_in(&q, 5, simple_func, &touched);
443+
test_assert(id);
444+
445+
id = equeue_call_in(&q, 15, simple_func, &touched);
446+
test_assert(id);
447+
448+
equeue_dispatch(&q, 20);
449+
test_assert(touched == 3);
450+
451+
equeue_destroy(&q);
452+
}
453+
454+
void *multithread_thread(void *p) {
455+
equeue_t *q = (equeue_t *)p;
456+
equeue_dispatch(q, -1);
457+
return 0;
458+
}
459+
460+
void multithread_test(void) {
461+
equeue_t q;
462+
int err = equeue_create(&q, 2048);
463+
test_assert(!err);
464+
465+
bool touched = false;
466+
equeue_call_every(&q, 1, simple_func, &touched);
467+
468+
pthread_t thread;
469+
err = pthread_create(&thread, 0, multithread_thread, &q);
470+
test_assert(!err);
471+
472+
usleep(10000);
473+
equeue_break(&q);
474+
err = pthread_join(thread, 0);
475+
test_assert(!err);
476+
477+
test_assert(touched);
478+
479+
equeue_destroy(&q);
480+
}
481+
378482
// Barrage tests
379483
void simple_barrage_test(int N) {
380484
equeue_t q;
@@ -483,6 +587,9 @@ int main() {
483587
test_run(loop_protect_test);
484588
test_run(break_test);
485589
test_run(period_test);
590+
test_run(nested_test);
591+
test_run(sloth_test);
592+
test_run(multithread_test);
486593
test_run(simple_barrage_test, 20);
487594
test_run(fragmenting_barrage_test, 20);
488595
test_run(multithreaded_barrage_test, 20);

0 commit comments

Comments
 (0)