diff --git a/sys/event/event.c b/sys/event/event.c index 8acd98a062..96579d0a7d 100644 --- a/sys/event/event.c +++ b/sys/event/event.c @@ -29,6 +29,10 @@ #include "clist.h" #include "thread.h" +#ifdef MODULE_XTIMER +#include "xtimer.h" +#endif + void event_queue_init_detached(event_queue_t *queue) { assert(queue); @@ -110,6 +114,30 @@ event_t *event_wait(event_queue_t *queue) return result; } +#ifdef MODULE_XTIMER +event_t *event_wait_timeout(event_queue_t *queue, uint32_t timeout) +{ + assert(queue); + event_t *result; + xtimer_t timer; + thread_flags_t flags = 0; + + xtimer_set_timeout_flag(&timer, timeout); + do { + result = event_get(queue); + if (result == NULL) { + flags = thread_flags_wait_any(THREAD_FLAG_EVENT | THREAD_FLAG_TIMEOUT); + } + } while ((result == NULL) && (flags & THREAD_FLAG_EVENT)); + + if (result) { + xtimer_remove(&timer); + } + + return result; +} +#endif + void event_loop(event_queue_t *queue) { event_t *event; diff --git a/sys/include/event.h b/sys/include/event.h index 096c3870bc..dcea3c23a9 100644 --- a/sys/include/event.h +++ b/sys/include/event.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2017 Inria * 2017 Kaspar Schleiser - * 2018 Freie Universität Berlin + * 2018-2019 Freie Universität Berlin * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -231,6 +231,19 @@ event_t *event_get(event_queue_t *queue); */ event_t *event_wait(event_queue_t *queue); +#if defined(MODULE_XTIMER) || defined(DOXYGEN) +/** + * @brief Get next event from event queue, blocking until timeout expires + * + * @param[in] queue queue to query for an event + * @param[in] timeout maximum time to wait for an event to be posted in us + * + * @return pointer to next event if event was taken from the queue + * @return NULL if timeout expired before an event was posted + */ +event_t *event_wait_timeout(event_queue_t *queue, uint32_t timeout); +#endif + /** * @brief Simple event loop * diff --git a/tests/event_wait_timeout/Makefile b/tests/event_wait_timeout/Makefile new file mode 100644 index 0000000000..61b43a26eb --- /dev/null +++ b/tests/event_wait_timeout/Makefile @@ -0,0 +1,12 @@ +include ../Makefile.tests_common + +BOARD_INSUFFICIENT_MEMORY := arduino-duemilanove arduino-nano arduino-uno + +FORCE_ASSERTS = 1 +USEMODULE += event +USEMODULE += xtimer +USEMODULE += core_thread_flags + +TEST_ON_CI_WHITELIST += all + +include $(RIOTBASE)/Makefile.include diff --git a/tests/event_wait_timeout/main.c b/tests/event_wait_timeout/main.c new file mode 100644 index 0000000000..00b76bcb4d --- /dev/null +++ b/tests/event_wait_timeout/main.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2019 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test application to test event wait timeout + * + * @author Hauke Petersen + * + * @} + */ + +#include + +#include "event.h" +#include "thread.h" +#include "xtimer.h" +#include "thread_flags.h" + +#define TIMEOUT (50U * US_PER_MS) /* 50ms */ +#define PRIO (THREAD_PRIORITY_MAIN - 5) +#define STACKSIZE (THREAD_STACKSIZE_DEFAULT) + +#define FLAG_SYNC (0x0040) + +static void _on_evt(event_t *evt); + +static event_queue_t _evtq; +static event_t _evt = { .handler = _on_evt }; + +static char _stack[STACKSIZE]; +static thread_t *_thread_main; + +static unsigned _wakeup_evt = 0; +static unsigned _wakeup_timeout = 0; + +static void _on_evt(event_t *evt) +{ + (void)evt; + ++_wakeup_evt; +} + +static void *_cnt_thread(void *arg) +{ + (void)arg; + event_queue_init(&_evtq); + + while (1) { + event_t *evt = event_wait_timeout(&_evtq, TIMEOUT); + if (evt) { + evt->handler(evt); + } + else { + ++_wakeup_timeout; + } + } + + return NULL; +} + +int main(void) +{ + /* setup */ + _thread_main = (thread_t *)thread_get(thread_getpid()); + + puts("[START] event_wait_timeout test application.\n"); + + /* test 'instant' return */ + event_queue_t tmp_eq = EVENT_QUEUE_INIT; + event_t *tmp_evt = event_wait_timeout(&tmp_eq, 0); + if (tmp_evt != NULL) { + puts("[FAILED]"); + return 1; + } + + thread_create(_stack, sizeof(_stack), PRIO, 0, _cnt_thread, NULL, "cnt"); + /* first, wait 155ms -> should lead to 3 timeout wakeups */ + xtimer_usleep(155U * US_PER_MS); + /* post event 3 times -> should lead to 3 event wakeups */ + for (unsigned i = 0; i < 3; i++) { + event_post(&_evtq, &_evt); + xtimer_usleep(5U * US_PER_MS); + } + /* wait for 35ms and post another event -> +1 event wakeup */ + xtimer_usleep(35U * US_PER_MS); + event_post(&_evtq, &_evt); + /* finally, wait 60ms and collect results -> +1 timeout wakeup */ + xtimer_usleep(60U * US_PER_MS); + + unsigned events = _wakeup_evt; + unsigned timeouts = _wakeup_timeout; + + /* rate results */ + printf("finished: %u/4 events and %u/4 timeouts recorded\n", + events, timeouts); + if ((events == 4) && (timeouts == 4)) { + puts("[SUCCESS]"); + } + else { + puts("[FAILED]"); + } + + return 0; +} diff --git a/tests/event_wait_timeout/tests/01-run.py b/tests/event_wait_timeout/tests/01-run.py new file mode 100755 index 0000000000..a8c5d9b211 --- /dev/null +++ b/tests/event_wait_timeout/tests/01-run.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2016 Kaspar Schleiser +# 2017 Sebastian Meiling +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +import sys +from testrunner import run + + +def testfunc(child): + child.expect_exact(u"[SUCCESS]") + + +if __name__ == "__main__": + sys.exit(run(testfunc))