From a2dd6f90e51ca9edef643ba72bd1fd18113cf0d2 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Thu, 5 Nov 2020 09:12:32 +0100 Subject: [PATCH 1/2] sys/irq_handler: Remove deprecated module --- sys/include/irq_handler.h | 253 ------------------------------ sys/irq_handler/Makefile | 1 - sys/irq_handler/irq_handler.c | 94 ----------- tests/sys_irq_handler/Makefile | 8 - tests/sys_irq_handler/Makefile.ci | 10 -- tests/sys_irq_handler/main.c | 170 -------------------- 6 files changed, 536 deletions(-) delete mode 100644 sys/include/irq_handler.h delete mode 100644 sys/irq_handler/Makefile delete mode 100644 sys/irq_handler/irq_handler.c delete mode 100644 tests/sys_irq_handler/Makefile delete mode 100644 tests/sys_irq_handler/Makefile.ci delete mode 100644 tests/sys_irq_handler/main.c diff --git a/sys/include/irq_handler.h b/sys/include/irq_handler.h deleted file mode 100644 index db0af4c25002..000000000000 --- a/sys/include/irq_handler.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2019 Gunar Schorcht - * - * 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. - */ - -/** - * @defgroup sys_irq_handler Interrupt handler thread - * @ingroup sys - * @brief Single thread for handling interrupts that may trigger blocking - * functions and therefore may only be called in thread context. - * - * @author Gunar Schorcht - * - * ## Interrupt Context Problem - * - * There are many devices connected to the host CPU via a bus system such as - * I2C or SPI. Such devices are, for example, sensors and actuators. Since - * these devices share the bus system, their access to the bus system has - * to be synchronized. - * - * In addition, such devices often use interrupts to trigger the execution - * of certain functions, such as reading the sensor values. That is, when an - * interrupt occurs, the driver requires often access to the bus system, for - * example, to read the status registers. - * - * The access to SPI and I2C interfaces is synchronized by mutual exclusion - * using mutexes. If one thread tries to access such an interface that is - * already being used by another thread, it will be blocked until the interface - * becomes available. Although this synchronization works in the thread - * context, it does not work in the interrupt context. Accessing such an - * interface within an ISR would interfere with an already existing interface - * access. This problem is called [interrupt context problem] - * (http://api.riot-os.org/group__drivers__netdev__api.html). - * - * The only solution to this problem is *not to call any function that - * interacts with a device directly from interrupt context*. Rather, the ISR - * should only indicate the occurrence of the interrupt. The interrupt is - * then handled asynchronously by a normal function within a thread context. - * - * The problem now is that driver modules usually do not use their own thread, - * but run in the context of the calling thread. However, it can not be left - * to the application thread to handle the interrupts of driver modules. The - * only solution would be to have a separate interrupt handler thread for each - * driver module that uses interrupts along with SPI or I2C interfaces. - * However, as the number of such modules increases, many resources (thread - * contexts, including their thread stacks) are allocated only for interrupt - * handling. - * - * ## Solution - * - * The solution is to have a single interrupt handler thread which serializes - * the interrupts of such driver modules and calls the functions of the driver - * modules to handle the interrupts from its thread context. - * - * For this purpose, each driver module that wants to use this interrupt - * handler thread has to define an interrupt event of type #irq_event_t - * for each of its interrupt sources. The interrupt event contains a - * reference to the function to be called to handle the interrupt. - * - * When an interrupt of the corresponding source occurs, the ISR of the - * driver module registers only the interrupt event associated with the - * interrupt source with the #irq_event_add function on the handler. The - * handler places the interrupt event in an pending interrupt queue. - * - * Each interrupt event can be registered on the handler only once. That is, - * if the same interrupt occurs multiple times, only its first occurrence is - * placed to the pending interrupt queue and is handled. - * - * When the interrupt handler thread gets the CPU, it processes all pending - * interrupt events in the order of their occurrence before it yields. - * - * ## Usage - * - * The single-interrupt handler thread can be used not only for driver - * modules with bus access, but for any interrupt handling that may - * trigger a blocking function and therefore cannot be called in an - * interrupt context. - * - * @note All interrupts handled by the single interrupt handler thread are - * serialized. - * - * To use the interrupt handler thread, using modules have to define a static - * interrupt event of type #irq_event_t for each of their interrupt sources. - * These static interrupt events have to be initialized with the static - * initializer #IRQ_EVENT_INIT. Furthermore, the interrupt handling function - * and optionally an argument, the context, have to be set. - * - * Once the interrupt events have been initialized, they can be added to the - * pending interrupts queue of the interrupt handler thread by an ISR using - * the #irq_event_add function which indicates that an interrupt has occurred - * and needs to be handled. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~ {.c} - * #include "foo_device.h" - * #include "irq_handler.h" - * - * // interrupt event structure with static initializer - * static irq_event_t _int_event = IRQ_EVENT_INIT; - * - * ... - * - * // non blocking ISR just adds the event and returns - * static void _int_request(void *arg) - * { - * irq_event_add(&_int_event); - * } - * - * // example handler for the interrupt including blocking functions - * static void _int_handler(void *ctx) - * { - * foo_device_t dev = (foo_device_t*)ctx; - * uint8_t status; - * - * // blocking access to the I2C - * i2c_aquire(dev->i2c_device); - * i2c_read_reg(dev->i2c_device, FOO_DEVICE_REG_STATUS, &status, 1); - * i2c_release(dev->i2c_device); - * - * // application thread callbacks - * switch (status) { - * case FOO_INT_TYPE1: dev->int_type1.isr(dev->int_type1.arg); - * break; - * case FOO_INT_TYPE2: dev->int_type2.isr(dev->int_type2.arg); - * break; - * ... - * } - * ... - * } - * - * ... - * - * int foo_device_init(foo_device_t *dev, foo_device_params_t *params) - * { - * // set the handler for the interrupt - * _int_event.isr = _int_handler; - * _int_event.ctx = (void*)dev; - * - * // initialize the GPIO with ISR - * gpio_init_int(GPIO_PIN(0, 1), GPIO_IN, GPIO_BOTH, int_request, 0); - * ... - * } - * - * ~~~~~~~~~~~~~~~~~~~~~~~~ - * - * @{ - * @file - */ - -#ifndef IRQ_HANDLER_H -#define IRQ_HANDLER_H - -#include - -#include "assert.h" -#include "event.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Default priority of the interrupt handler thread - * - * The priority of the interrupt handler thread has to be high enough that all - * pending interrupts are handled before other threads are executed. - */ -#ifndef IRQ_HANDLER_PRIO -#define IRQ_HANDLER_PRIO 0 -#endif - -/** - * @brief Interrupt handling function prototype - * - * Defines the prototype of the function that is registered together - * with an interrupt event and to be called when the interrupt is handled. - */ -typedef void (*irq_isr_t)(void *ctx); - -/** - * @brief Interrupt event structure - * - * Using modules have to define a structure of this type for each interrupt - * source used by the modules. Structures of this type are used to put - * them in a pending interrupt queue indicating that an interrupt of the - * corresponding source has occurred and needs to be handled. Each interrupt - * event can only be pending once. - * - * Interrupt event structures have to be pre-allocated to use them. - */ -typedef struct { - event_t event; /**< Event structure */ - bool pending; /**< Indicates whether the same interrupt request event - is already pending */ - irq_isr_t isr; /**< Function to be called to handle the interrupt */ - void *ctx; /**< Context used by the function */ -} irq_event_t; - -/** - * @brief Static initializer for #irq_event_t. - */ -#define IRQ_EVENT_INIT { \ - .event.handler = NULL, \ - .event.list_node.next = NULL, \ - .pending = false, \ - .isr = NULL, \ - .ctx = NULL, \ - } - -/** - * @brief Initialize an interrupt event - * - * Initializes the given interrupt event structure. - * - * Only use this function for dynamically allocated interrupt event - * structures. For the initialization of static interrupt event structures - * use #IRQ_EVENT_INIT instead. - * - * @param[out] irq Pre-allocated #irq_event_t structure, must not be NULL - */ - -static inline void irq_event_init(irq_event_t *irq) -{ - assert(irq != NULL); - irq_event_t tmp = IRQ_EVENT_INIT; - *irq = tmp; -} - -/** - * @brief Add an interrupt event to the pending interrupt queue - * - * The interrupt event given by parameter \p irq will be placed at the end of - * the pending interrupt queue. - * - * Each interrupt event can be added only once to the pending interrupt queue. - * That is, if the same interrupt occurs multiple times, only its first - * occurrence is placed to the pending interrupt queue and is handled. - * - * @param[in] irq Preallocated interrupt event - * - * @retval 0 on success - * @retval -EALREADY if the given interrupt event is already pending - */ -int irq_event_add(irq_event_t *irq); - -#ifdef __cplusplus -} -#endif - -#endif /* IRQ_HANDLER_H */ -/** @} */ diff --git a/sys/irq_handler/Makefile b/sys/irq_handler/Makefile deleted file mode 100644 index 48422e909a47..000000000000 --- a/sys/irq_handler/Makefile +++ /dev/null @@ -1 +0,0 @@ -include $(RIOTBASE)/Makefile.base diff --git a/sys/irq_handler/irq_handler.c b/sys/irq_handler/irq_handler.c deleted file mode 100644 index c303273b89c0..000000000000 --- a/sys/irq_handler/irq_handler.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2019 Gunar Schorcht - * - * 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. - */ - -#include -#include -#include - -#include "irq_handler.h" - -#define ENABLE_DEBUG 0 -#include "debug.h" - -/* Stack for the interrupt event handler thread */ -static char _irq_handler_stack[THREAD_STACKSIZE_DEFAULT]; - -/* PID of the interrupt handler thread, KERNEL_PID_UNDEF if not created yet */ -static kernel_pid_t _irq_handler_thread = KERNEL_PID_UNDEF; - -/* Interrupt event queue */ -static event_queue_t irq_queue = EVENT_QUEUE_INIT_DETACHED; - -static void _irq_handler(event_t *event) -{ - irq_event_t *irq = (irq_event_t *)event; - assert(irq != NULL); - - /* handle the pending interrupt */ - irq->pending = false; - irq->isr(irq->ctx); -} - -static void *_irq_loop(void *arg) -{ - (void)arg; - - DEBUG("[%s] starts\n", __func__); - - /* bind the queue */ - event_queue_claim(&irq_queue); - - /* doesn't return */ - event_loop(&irq_queue); - - return NULL; -} - -int irq_event_add(irq_event_t * irq) -{ - assert(irq != NULL); - assert(irq->isr != NULL); - - DEBUG("[%s] irq %p\n", __func__, (void *)irq); - - if (irq->pending) { - DEBUG("[%s] interrupt event %p is already pending\n", - __func__, (void *)irq); - return -EALREADY; - } - - /* disable interrupts */ - unsigned state = irq_disable(); - - /* create the handler thread if not created yet */ - if (_irq_handler_thread == KERNEL_PID_UNDEF) { - DEBUG("[%s] create irq_handler thread\n", __func__); - _irq_handler_thread = thread_create(_irq_handler_stack, - sizeof(_irq_handler_stack), - IRQ_HANDLER_PRIO, - THREAD_CREATE_WOUT_YIELD | - THREAD_CREATE_STACKTEST, - _irq_loop, NULL, "irq_handler"); - assert(_irq_handler_thread != KERNEL_PID_UNDEF); - - /* initialize the queue unbind */ - event_queue_init_detached(&irq_queue); - } - - /* initialize the interrupt event */ - irq->event.handler = _irq_handler; - irq->pending = true; - - /* restore previous interrupt state */ - irq_restore(state); - - /* queue the interrupt event */ - event_post(&irq_queue, (event_t *)irq); - - return 0; -} diff --git a/tests/sys_irq_handler/Makefile b/tests/sys_irq_handler/Makefile deleted file mode 100644 index ceb668edb4ff..000000000000 --- a/tests/sys_irq_handler/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -include ../Makefile.tests_common - -CFLAGS += -DIRQ_HANDLER_PRIO=THREAD_PRIORITY_MAIN+1 - -USEMODULE += irq_handler -USEMODULE += xtimer - -include $(RIOTBASE)/Makefile.include diff --git a/tests/sys_irq_handler/Makefile.ci b/tests/sys_irq_handler/Makefile.ci deleted file mode 100644 index ffa12570d151..000000000000 --- a/tests/sys_irq_handler/Makefile.ci +++ /dev/null @@ -1,10 +0,0 @@ -BOARD_INSUFFICIENT_MEMORY := \ - arduino-duemilanove \ - arduino-leonardo \ - arduino-nano \ - arduino-uno \ - atmega328p \ - nucleo-f031k6 \ - nucleo-l011k4 \ - stm32f030f4-demo \ - # diff --git a/tests/sys_irq_handler/main.c b/tests/sys_irq_handler/main.c deleted file mode 100644 index ee0f0428df65..000000000000 --- a/tests/sys_irq_handler/main.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2019 Gunar Schorcht - * - * 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 Interrupt handler test application - * - * @author Gunar Schorcht - * - * This application demonstrates how to use the interrupt handler thread - * module `irq_handler`. For that purpose the main thread simulates interrupts - * from 2 interrupt sources with different priorities with a period - * of a half second. One interrupt source triggers a second interrupt before - * the interrupts can be handled by the interrupt handler. - * - * To be able to simulate the interrupts by the main thread, the interrupt - * handler thread has to have a lower priority as the main thread for this - * example. Otherwise, the interrupts would be handled immediately when they - * are generated by the main thread. Therefore the interrupt handler thread - * priority is set to THREAD_PRIORITY_MAIN+1 for this example. - * @} - */ - -#include -#include - -#include "irq_handler.h" -#include "mutex.h" -#include "thread.h" -#include "xtimer.h" - -#define TEST_TIME (100 * US_PER_MS) -#define TEST_REPETITIONS (10) - -static void _int1_service (void *arg); -static void _int2_service (void *arg); - -static char some_stack[THREAD_STACKSIZE_MAIN]; -static int i = 0; -static int n_int1_handled = 0; -static int n_int2_handled = 0; -static int n_already_pending = 0; -static mutex_t mutex = MUTEX_INIT; -xtimer_t timer1a = { - .callback = _int1_service, - .arg = &timer1a -}; -xtimer_t timer1b = { - .callback = _int1_service, - .arg = &timer1b -}; -xtimer_t timer2 = { - .callback = _int2_service, - .arg = &timer2 -}; - -/* preallocated and initialized interrupt event objects */ -static irq_event_t _int1_event = IRQ_EVENT_INIT; -static irq_event_t _int2_event = IRQ_EVENT_INIT; - -/* interrupt service routine for a simulated interrupt from source 1 */ -static void _int1_service (void *arg) -{ - (void)arg; - puts("int1 triggered"); - /* registers just the interrupt event and returns */ - if (irq_event_add(&_int1_event) == -EALREADY) { - puts("int1 is already pending"); - n_already_pending++; - } -} - -/* interrupt handler for interrupts from source 1 */ -static void _int1_handler(void *ctx) -{ - xtimer_t *timer = ctx; - xtimer_set(timer, TEST_TIME); - puts("int1 handled"); - mutex_lock(&mutex); - n_int1_handled++; - mutex_unlock(&mutex); -} - -/* interrupt service routine for a simulated interrupt from source 2 */ -static void _int2_service (void *arg) -{ - (void)arg; - puts("int2 triggered"); - /* registers just the interrupt event and returns */ - if (irq_event_add(&_int2_event) == -EALREADY) { - puts("int2 is already pending"); - n_already_pending++; - } -} - -/* interrupt handler for interrupts from source 2 */ -static void _int2_handler(void *ctx) -{ - xtimer_t *timer = ctx; - xtimer_set(timer, TEST_TIME); - puts("int2 handled"); - mutex_lock(&mutex); - n_int2_handled++; - mutex_unlock(&mutex); -} - -static void *some_thread(void *arg) -{ - (void)arg; - - puts("some_thread is starting"); - - while (1) { - mutex_lock(&mutex); - i++; - mutex_unlock(&mutex); - xtimer_usleep(US_PER_MS); - } - return NULL; -} - -int main(void) -{ - _int1_event.isr = _int1_handler; - _int1_event.ctx = &timer1a; - - _int2_event.isr = _int2_handler; - _int2_event.ctx = &timer2; - - puts("START"); - - thread_create(some_stack, sizeof(some_stack), - THREAD_PRIORITY_MAIN + 2, THREAD_CREATE_WOUT_YIELD, - some_thread, NULL, "some_thread"); - puts("some_thread created"); - - /* wait to let some_thread to start */ - xtimer_usleep(US_PER_SEC); - - i = 0; - - xtimer_set(&timer1a, TEST_TIME); - xtimer_set(&timer1b, TEST_TIME); - xtimer_set(&timer2, TEST_TIME); - - xtimer_usleep(TEST_TIME * TEST_REPETITIONS + TEST_TIME/2); - - xtimer_remove(&timer1a); - xtimer_remove(&timer1b); - xtimer_remove(&timer2); - - mutex_lock(&mutex); - if ((i > 0) && - (n_int1_handled == TEST_REPETITIONS) && - (n_int2_handled == TEST_REPETITIONS) && - (n_already_pending == 1)) { - puts("[SUCCESS]"); - } - mutex_unlock(&mutex); - - return 0; -} From 73fefb764201d6c18eb35e904b9382c061c1993d Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Thu, 5 Nov 2020 09:16:54 +0100 Subject: [PATCH 2/2] LOSTANDFOUND.md: Add sys/irq_handler --- LOSTANDFOUND.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/LOSTANDFOUND.md b/LOSTANDFOUND.md index d408ec5f151a..ddd88f16ae02 100644 --- a/LOSTANDFOUND.md +++ b/LOSTANDFOUND.md @@ -270,3 +270,11 @@ Reason for removal: [9fb2f541baca469e34fa01b004d6f19385700ce9]: https://github.com/RIOT-OS/RIOT/commit/9fb2f541baca469e34fa01b004d6f19385700ce9 [35b6ccedf31f10a5f8e4f97609ad5b10c28bdc34]: https://github.com/RIOT-OS/RIOT/commit/35b6ccedf31f10a5f8e4f97609ad5b10c28bdc34 [72821a502f073006643cb4ef7815fc8c42563ce6]: https://github.com/RIOT-OS/RIOT/commit/72821a502f073006643cb4ef7815fc8c42563ce6 + +### sys/irq_handler [a2dd6f90e51ca9edef643ba72bd1fd18113cf0d2] +Author(s): +- Gunar Schorcht + +Reason for removal: +- Provides some feature as `sys/event_thread` +- Has been deprecated directly in the first release it was provided