Skip to content

Commit

Permalink
Fixed underflow issue in deadline calculation
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
geky committed Aug 5, 2016
1 parent 599964f commit 90f2b7d
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 1 deletion.
4 changes: 3 additions & 1 deletion equeue.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,9 @@ void equeue_dispatch(equeue_t *q, int ms) {
equeue_mutex_lock(&q->queuelock);
if (q->queue) {
int diff = equeue_tickdiff(q->queue->target, tick);
if (deadline < 0 || diff < deadline) {
if (diff <= 0) {
deadline = 0;
} else if (deadline < 0 || diff < deadline) {
deadline = diff;
}
}
Expand Down
107 changes: 107 additions & 0 deletions tests/tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ void simple_func(void *p) {
(*(int *)p)++;
}

void sloth_func(void *p) {
usleep(10000);
(*(int *)p)++;
}

struct indirect {
int *touched;
uint8_t buffer[7];
Expand Down Expand Up @@ -102,6 +107,19 @@ void cancel_func(void *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) {
Expand Down Expand Up @@ -375,6 +393,92 @@ void period_test(void) {
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);

bool touched = false;
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);
}

// Barrage tests
void simple_barrage_test(int N) {
equeue_t q;
Expand Down Expand Up @@ -483,6 +587,9 @@ int main() {
test_run(loop_protect_test);
test_run(break_test);
test_run(period_test);
test_run(nested_test);
test_run(sloth_test);
test_run(multithread_test);
test_run(simple_barrage_test, 20);
test_run(fragmenting_barrage_test, 20);
test_run(multithreaded_barrage_test, 20);
Expand Down

0 comments on commit 90f2b7d

Please sign in to comment.