-
Notifications
You must be signed in to change notification settings - Fork 2.1k
sys: add shared event threads #12474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| SRC := event.c | ||
|
|
||
| SUBMODULES = 1 | ||
| SUBMODULES := 1 | ||
| SUBMODULES_NOFORCE := 1 | ||
|
|
||
| include $(RIOTBASE)/Makefile.base |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| /* | ||
| * Copyright (C) 2019 Kaspar Schleiser <kaspar@schleiser.de> | ||
| * 2018 Freie Universität Berlin | ||
| * 2020 Inria | ||
| * | ||
| * 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 Thread implementation | ||
| * | ||
| * @author Hauke Petersen <hauke.petersen@fu-berlin.de> | ||
| * @author Kaspar Schleiser <kaspar@schleiser.de> | ||
| * | ||
| * @} | ||
| */ | ||
|
|
||
| #include "thread.h" | ||
| #include "event.h" | ||
| #include "event/thread.h" | ||
|
|
||
| static void *_handler(void *event_queue) | ||
| { | ||
| event_queue_claim(event_queue); | ||
| event_loop(event_queue); | ||
|
|
||
| /* should be never reached */ | ||
| return NULL; | ||
| } | ||
|
|
||
| void event_thread_init(event_queue_t *queue, char *stack, size_t stack_size, | ||
| unsigned priority) | ||
| { | ||
| /* For the auto_init use case, this will be called before main gets | ||
| * started. main might already use the queues, so they need to be | ||
| * initialized at that point. | ||
| * | ||
| * They will be claimed within the handler thread. | ||
| */ | ||
| event_queue_init_detached(queue); | ||
|
|
||
| thread_create(stack, stack_size, priority, 0, _handler, queue, "event"); | ||
| } | ||
|
|
||
| #ifndef EVENT_THREAD_STACKSIZE_DEFAULT | ||
| # ifdef ISR_STACKSIZE | ||
| # define EVENT_THREAD_STACKSIZE_DEFAULT ISR_STACKSIZE | ||
| # else | ||
| # define EVENT_THREAD_STACKSIZE_DEFAULT THREAD_STACKSIZE_SMALL | ||
| # endif | ||
| #endif | ||
|
|
||
| #ifndef EVENT_THREAD_HIGHEST_STACKSIZE | ||
| #define EVENT_THREAD_HIGHEST_STACKSIZE EVENT_THREAD_STACKSIZE_DEFAULT | ||
| #endif | ||
|
|
||
| #ifndef EVENT_THREAD_HIGHEST_PRIO | ||
| #define EVENT_THREAD_HIGHEST_PRIO (0) | ||
| #endif | ||
|
|
||
| #ifndef EVENT_THREAD_MEDIUM_STACKSIZE | ||
| #define EVENT_THREAD_MEDIUM_STACKSIZE EVENT_THREAD_STACKSIZE_DEFAULT | ||
| #endif | ||
| #ifndef EVENT_THREAD_MEDIUM_PRIO | ||
| #define EVENT_THREAD_MEDIUM_PRIO (THREAD_PRIORITY_MAIN - 1) | ||
| #endif | ||
|
|
||
| #ifndef EVENT_THREAD_LOWEST_STACKSIZE | ||
| #define EVENT_THREAD_LOWEST_STACKSIZE EVENT_THREAD_STACKSIZE_DEFAULT | ||
| #endif | ||
| #ifndef EVENT_THREAD_LOWEST_PRIO | ||
| #define EVENT_THREAD_LOWEST_PRIO (THREAD_PRIORITY_IDLE - 1) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We would have at most exactly two priorities and two threads, right? Shouldn't the lowest thread priority be
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Maybe they want to, as in, "do this when there is time". That's why I've made it just one higher than idle. How about I add a third priority ("medium"), which is just one higher than main? Or does the current very-low one make sense at all? I mean, this is just the auto configuration, cpus / boards / applications can freely launch more handler threads...
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
What priority should a thread have that is used by a driver to handle an interrupt from the hardware? IMHO, its priority should be at least higher than the priority of the main thread. A medium priority thread seems to be more important than a very low priority thread.
Yes of course, but drivers can only use threads that are known from the auto configuration. Otherwise, they would need an additional thread parameter for the initializtion. This in turn would prevent the auto initialization.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I guess that depends... It is easy to add more priorities, so I propose I add one more middle priority (one higher than main) and see how far we go with that.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 The three priorities high (0), medium (main-1) and low (idle-1) probably meet the requirements of most use cases.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added medium priority |
||
| #endif | ||
|
|
||
| #ifdef MODULE_EVENT_THREAD_HIGHEST | ||
| event_queue_t event_queue_highest; | ||
| static char _evq_highest_stack[EVENT_THREAD_HIGHEST_STACKSIZE]; | ||
| #endif | ||
|
|
||
| #ifdef MODULE_EVENT_THREAD_MEDIUM | ||
| event_queue_t event_queue_medium; | ||
| static char _evq_medium_stack[EVENT_THREAD_MEDIUM_STACKSIZE]; | ||
| #endif | ||
|
|
||
| #ifdef MODULE_EVENT_THREAD_LOWEST | ||
| event_queue_t event_queue_lowest; | ||
| static char _evq_lowest_stack[EVENT_THREAD_LOWEST_STACKSIZE]; | ||
| #endif | ||
|
|
||
| typedef struct { | ||
| event_queue_t *queue; | ||
| char *stack; | ||
| size_t stack_size; | ||
| unsigned priority; | ||
| } event_threads_t; | ||
|
|
||
| const event_threads_t _event_threads[] = { | ||
| #ifdef MODULE_EVENT_THREAD_HIGHEST | ||
| { &event_queue_highest, _evq_highest_stack, sizeof(_evq_highest_stack), | ||
| EVENT_THREAD_HIGHEST_PRIO }, | ||
| #endif | ||
| #ifdef MODULE_EVENT_THREAD_MEDIUM | ||
| { &event_queue_medium, _evq_medium_stack, sizeof(_evq_medium_stack), | ||
| EVENT_THREAD_MEDIUM_PRIO }, | ||
| #endif | ||
| #ifdef MODULE_EVENT_THREAD_LOWEST | ||
| { &event_queue_lowest, _evq_lowest_stack, sizeof(_evq_lowest_stack), | ||
| EVENT_THREAD_LOWEST_PRIO }, | ||
| #endif | ||
| }; | ||
|
|
||
| void auto_init_event_thread(void) | ||
| { | ||
| for (unsigned i = 0; i < ARRAY_SIZE(_event_threads); i++) { | ||
| event_thread_init(_event_threads[i].queue, | ||
| _event_threads[i].stack, _event_threads[i].stack_size, | ||
| _event_threads[i].priority); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| /* | ||
| * Copyright (C) 2020 Kaspar Schleiser <kaspar@schleiser.de> | ||
| * 2020 Freie Universität Berlin | ||
| * 2020 Inria | ||
| * | ||
| * 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 | ||
| * @brief Provides utility functions for event handler threads | ||
| * | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief Event Thread API | ||
| * | ||
| * @author Kaspar Schleiser <kaspar@schleiser.de> | ||
| */ | ||
|
|
||
| #ifndef EVENT_THREAD_H | ||
| #define EVENT_THREAD_H | ||
|
|
||
| #include <stddef.h> | ||
|
|
||
| #include "event.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| /** | ||
| * @brief Convenience function for initializing an event queue thread | ||
| * | ||
| * @param[in] queue ptr to preallocated queue object | ||
| * @param[in] stack ptr to stack space | ||
| * @param[in] stack_size size of stack | ||
| * @param[in] priority priority to use | ||
| */ | ||
| void event_thread_init(event_queue_t *queue, char *stack, size_t stack_size, | ||
| unsigned priority); | ||
|
|
||
| #ifdef MODULE_EVENT_THREAD_HIGHEST | ||
| extern event_queue_t event_queue_highest; | ||
| #define EVENT_PRIO_HIGHEST (&event_queue_highest) | ||
| #endif | ||
|
|
||
| #ifdef MODULE_EVENT_THREAD_MEDIUM | ||
| extern event_queue_t event_queue_medium; | ||
| #define EVENT_PRIO_MEDIUM (&event_queue_medium) | ||
| #endif | ||
|
|
||
| #ifdef MODULE_EVENT_THREAD_LOWEST | ||
| extern event_queue_t event_queue_lowest; | ||
| #define EVENT_PRIO_LOWEST (&event_queue_lowest) | ||
| #endif | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
| #endif /* EVENT_THREAD_H */ | ||
| /** @} */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| include ../Makefile.tests_common | ||
|
|
||
| USEMODULE += event_thread_highest event_thread_medium event_thread_lowest | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we define these as configuration values (CFLAGS) that depend on the module "event_thread"? Otherwise it's hard to configure it using Kconfig.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how hard? |
||
|
|
||
| # arm7 has an issue with it's ISR_STACKSIZE define | ||
| FEATURES_BLACKLIST += arch_arm7 | ||
|
|
||
| include $(RIOTBASE)/Makefile.include | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| BOARD_INSUFFICIENT_MEMORY := \ | ||
| arduino-duemilanove \ | ||
| arduino-nano \ | ||
| arduino-uno \ | ||
| atmega328p \ | ||
| nucleo-f031k6 \ | ||
| stm32f030f4-demo \ | ||
| # |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| /* | ||
| * Copyright (C) 2020 Kaspar Schleiser <kaspar@schleiser.de> | ||
| * 2020 Freie Universität Berlin | ||
| * 2020 Inria | ||
| * | ||
| * 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 Event threads test application | ||
| * | ||
| * @author Kaspar Schleiser <kaspar@schleiser.de> | ||
| * | ||
| * @} | ||
| */ | ||
|
|
||
| #include <stdio.h> | ||
|
|
||
| #include "thread.h" | ||
| #include "event/thread.h" | ||
|
|
||
| static void _handler_high(event_t *event) { | ||
| (void)event; | ||
| puts("high"); | ||
| } | ||
|
|
||
| static event_t event_high = { .handler=_handler_high }; | ||
|
|
||
| static void _handler_medium(event_t *event) { | ||
| (void)event; | ||
| puts("medium"); | ||
| } | ||
|
|
||
| static event_t event_medium = { .handler=_handler_medium }; | ||
|
|
||
| static void _handler_low(event_t *event) { | ||
| (void)event; | ||
| puts("low"); | ||
| } | ||
|
|
||
| static event_t event_low = { .handler=_handler_low }; | ||
|
|
||
| int main(void) | ||
| { | ||
| event_post(EVENT_PRIO_LOWEST, &event_low); | ||
| event_post(EVENT_PRIO_MEDIUM, &event_medium); | ||
| event_post(EVENT_PRIO_HIGHEST, &event_high); | ||
|
|
||
| puts("main done"); | ||
|
|
||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| #!/usr/bin/env python3 | ||
|
|
||
| import sys | ||
| from testrunner import run | ||
|
|
||
|
|
||
| def testfunc(child): | ||
| child.expect_exact('medium\r\n') | ||
| child.expect_exact('high\r\n') | ||
| child.expect_exact('main done\r\n') | ||
| child.expect_exact('low\r\n') | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| sys.exit(run(testfunc)) |
Uh oh!
There was an error while loading. Please reload this page.