From 9996909b653ddc6f497a5b5950af75b99f4e63fa Mon Sep 17 00:00:00 2001 From: Mihai Renea Date: Thu, 17 Oct 2024 11:03:25 +0200 Subject: [PATCH] sys/event: add event_sync() --- sys/event/event.c | 25 +++++++++++++++++++++++++ sys/include/event.h | 21 +++++++++++++++++++++ tests/sys/events/main.c | 12 +++++++++--- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/sys/event/event.c b/sys/event/event.c index c9a615de51aa..2a73ebe3495b 100644 --- a/sys/event/event.c +++ b/sys/event/event.c @@ -27,6 +27,7 @@ #include "event.h" #include "clist.h" +#include "mutex.h" #include "thread.h" #if IS_USED(MODULE_XTIMER) @@ -174,3 +175,27 @@ event_t *event_wait_timeout_ztimer(event_queue_t *queue, return result; } #endif + +typedef struct { + event_t ev; + mutex_t synced; +} sync_ev_t; + +static void sync_ev_handler(event_t *ev) +{ + sync_ev_t *sync_ev = (sync_ev_t *)ev; + mutex_unlock(&sync_ev->synced); +} + +void event_sync(event_queue_t *queue) +{ + /* if we're on the queue, this would block forever */ + assert(!queue->waiter || queue->waiter->pid != thread_getpid()); + + sync_ev_t sync_ev = { + .ev.handler = sync_ev_handler, + .synced = MUTEX_INIT_LOCKED, + }; + event_post(queue, &sync_ev.ev); + mutex_lock(&sync_ev.synced); +} diff --git a/sys/include/event.h b/sys/include/event.h index 02543ceeb986..19daf5c2091b 100644 --- a/sys/include/event.h +++ b/sys/include/event.h @@ -465,6 +465,27 @@ static inline void event_loop(event_queue_t *queue) event_loop_multi(queue, 1); } +/** + * @brief Synchronize with the last event on the queue + * + * Blocks until the last event on the queue at the moment of calling this is + * processed. + * + * @warning May not be called from the event queue, as it would block forever. + * @warning If the queue has no waiter, this will block until the queue is + * claimed. See @ref event_queue_claim() + * + * @param[in] queue event queue to sync with + * + * Usage example: + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c} + * event_post(queue, my_event); + * // When event_sync() returns, my_event will have been processed. + * event_sync(queue); + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +void event_sync(event_queue_t *queue); + #ifdef __cplusplus } #endif diff --git a/tests/sys/events/main.c b/tests/sys/events/main.c index ed7f4442bb09..d0413e02217d 100644 --- a/tests/sys/events/main.c +++ b/tests/sys/events/main.c @@ -35,7 +35,9 @@ #endif #define STACKSIZE THREAD_STACKSIZE_DEFAULT -#define PRIO (THREAD_PRIORITY_MAIN - 1) +/* in order to actually test @ref event_sync(), the waiter's prio should be lower + * than main s.t. it doesn't start executing right after events are enqueued */ +#define PRIO (THREAD_PRIORITY_MAIN + 1) #define DELAYED_QUEUES_NUMOF 2 static char stack[STACKSIZE]; @@ -164,6 +166,9 @@ int main(void) event_queue_init_detached(&dqs[0]); event_queue_init_detached(&dqs[1]); + printf("running thread that will claim event queues %p\n", (void *)&dqs); + thread_create(stack, sizeof(stack), PRIO, 0, claiming_thread, dqs, "ct"); + printf("posting %p to delayed queue at index 1\n", (void *)&delayed_event1); event_post(&dqs[1], &delayed_event1); printf("posting %p to delayed queue at index 1\n", (void *)&delayed_event2); @@ -171,8 +176,9 @@ int main(void) printf("posting %p to delayed queue at index 0\n", (void *)&delayed_event3); event_post(&dqs[0], &delayed_event3); - printf("running thread that will claim event queues %p\n", (void *)&dqs); - thread_create(stack, sizeof(stack), PRIO, 0, claiming_thread, dqs, "ct"); + event_sync(&dqs[1]); + expect(order == 3); + printf("synced with %p\n", (void *)&delayed_event3); /* test posting different kind of events in order to a statically * initialized queue */