mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
sys/event: decouple event_queue from thread
This commit is contained in:
parent
795699fed3
commit
b9aeaa7418
@ -1,11 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* 2018 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 sys_event
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Event loop implementation
|
||||
*
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <string.h>
|
||||
@ -14,6 +28,12 @@
|
||||
#include "clist.h"
|
||||
#include "thread.h"
|
||||
|
||||
void event_queue_init_detached(event_queue_t *queue)
|
||||
{
|
||||
assert(queue);
|
||||
memset(queue, '\0', sizeof(*queue));
|
||||
}
|
||||
|
||||
void event_queue_init(event_queue_t *queue)
|
||||
{
|
||||
assert(queue);
|
||||
@ -21,17 +41,31 @@ void event_queue_init(event_queue_t *queue)
|
||||
queue->waiter = (thread_t *)sched_active_thread;
|
||||
}
|
||||
|
||||
void event_queue_claim(event_queue_t *queue)
|
||||
{
|
||||
assert(queue && (queue->waiter == NULL));
|
||||
queue->waiter = (thread_t *)sched_active_thread;
|
||||
}
|
||||
|
||||
void event_post(event_queue_t *queue, event_t *event)
|
||||
{
|
||||
assert(queue && queue->waiter && event);
|
||||
assert(queue && event);
|
||||
|
||||
unsigned state = irq_disable();
|
||||
if (!event->list_node.next) {
|
||||
clist_rpush(&queue->event_list, &event->list_node);
|
||||
}
|
||||
thread_t *waiter = queue->waiter;
|
||||
irq_restore(state);
|
||||
|
||||
thread_flags_set(queue->waiter, THREAD_FLAG_EVENT);
|
||||
/* WARNING: there is a minimal chance, that a waiter claims a formerly
|
||||
* detached queue between the end of the critical section above and
|
||||
* the block below. In that case, the new waiter will not be woken
|
||||
* up. This should be fixed at some point once it is safe to call
|
||||
* thread_flags_set() inside a critical section on all platforms. */
|
||||
if (waiter) {
|
||||
thread_flags_set(waiter, THREAD_FLAG_EVENT);
|
||||
}
|
||||
}
|
||||
|
||||
void event_cancel(event_queue_t *queue, event_t *event)
|
||||
@ -49,8 +83,8 @@ event_t *event_get(event_queue_t *queue)
|
||||
{
|
||||
unsigned state = irq_disable();
|
||||
event_t *result = (event_t *) clist_lpop(&queue->event_list);
|
||||
|
||||
irq_restore(state);
|
||||
|
||||
if (result) {
|
||||
result->list_node.next = NULL;
|
||||
}
|
||||
@ -59,13 +93,18 @@ event_t *event_get(event_queue_t *queue)
|
||||
|
||||
event_t *event_wait(event_queue_t *queue)
|
||||
{
|
||||
thread_flags_wait_any(THREAD_FLAG_EVENT);
|
||||
unsigned state = irq_disable();
|
||||
event_t *result = (event_t *) clist_lpop(&queue->event_list);
|
||||
if (clist_rpeek(&queue->event_list)) {
|
||||
queue->waiter->flags |= THREAD_FLAG_EVENT;
|
||||
}
|
||||
irq_restore(state);
|
||||
assert(queue);
|
||||
event_t *result;
|
||||
|
||||
do {
|
||||
unsigned state = irq_disable();
|
||||
result = (event_t *)clist_lpop(&queue->event_list);
|
||||
irq_restore(state);
|
||||
if (result == NULL) {
|
||||
thread_flags_wait_any(THREAD_FLAG_EVENT);
|
||||
}
|
||||
} while (result == NULL);
|
||||
|
||||
result->list_node.next = NULL;
|
||||
return result;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* 2018 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
|
||||
@ -16,8 +17,12 @@
|
||||
* An event queue is basically a FIFO queue of events, with some functions to
|
||||
* efficiently and safely handle adding and getting events to / from such a
|
||||
* queue.
|
||||
*
|
||||
* An event queue is bound to a thread, but any thread or ISR can put events
|
||||
* into a queue.
|
||||
* into a queue. In most cases, the owning thread of a queue is set during the
|
||||
* queue's initialization. But it is also possible to initialize a queue in a
|
||||
* detached state from a different context and to set the owning thread
|
||||
* at a later point of time using the event_queue_claim() function.
|
||||
*
|
||||
* An event is a structure containing a pointer to an event handler. It can be
|
||||
* extended to provide context or arguments to the handler. It can also be
|
||||
@ -84,6 +89,7 @@
|
||||
* @brief Event API
|
||||
*
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef EVENT_H
|
||||
@ -111,6 +117,11 @@ extern "C" {
|
||||
*/
|
||||
#define EVENT_QUEUE_INIT { .waiter = (thread_t *)sched_active_thread }
|
||||
|
||||
/**
|
||||
* @brief static initializer for detached event queues
|
||||
*/
|
||||
#define EVENT_QUEUE_INIT_DETACHED { 0 }
|
||||
|
||||
/**
|
||||
* @brief event structure forward declaration
|
||||
*/
|
||||
@ -146,6 +157,25 @@ typedef struct {
|
||||
*/
|
||||
void event_queue_init(event_queue_t *queue);
|
||||
|
||||
/**
|
||||
* @brief Initialize an event queue not binding it to a thread
|
||||
*
|
||||
* @param[out] queue event queue object to initialize
|
||||
*/
|
||||
void event_queue_init_detached(event_queue_t *queue);
|
||||
|
||||
/**
|
||||
* @brief Bind an event queue to the calling thread
|
||||
*
|
||||
* This function must only be called once and only if the given queue is not
|
||||
* yet bound to a thread.
|
||||
*
|
||||
* @pre (queue->waiter == NULL)
|
||||
*
|
||||
* @param[out] queue event queue object to bind to a thread
|
||||
*/
|
||||
void event_queue_claim(event_queue_t *queue);
|
||||
|
||||
/**
|
||||
* @brief Queue an event
|
||||
*
|
||||
@ -192,6 +222,8 @@ event_t *event_get(event_queue_t *queue);
|
||||
* In order to handle an event retrieved using this function,
|
||||
* call event->handler(event).
|
||||
*
|
||||
* @note There can only be a single waiter on a queue!
|
||||
*
|
||||
* @param[in] queue event queue to get event from
|
||||
*
|
||||
* @returns pointer to next event
|
||||
|
Loading…
Reference in New Issue
Block a user