From 33986022af8f5389370cb012ba0e73e032774cab Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 21 Feb 2017 15:25:03 +0100 Subject: Add rtems_interrupt_server_request_submit() This function may be used to do a two-step interrupt processing. The first step is done in interrupt context which calls this function. The second step is then done in the context of the interrupt server. --- c/src/lib/libbsp/shared/src/irq-server.c | 148 +++++++++++++++++++------ cpukit/include/rtems/irq-extension.h | 182 ++++++++++++++++++++++++++++++- 2 files changed, 297 insertions(+), 33 deletions(-) diff --git a/c/src/lib/libbsp/shared/src/irq-server.c b/c/src/lib/libbsp/shared/src/irq-server.c index 4f127af7ba..905c26198b 100644 --- a/c/src/lib/libbsp/shared/src/irq-server.c +++ b/c/src/lib/libbsp/shared/src/irq-server.c @@ -7,7 +7,7 @@ */ /* - * Copyright (c) 2009, 2016 embedded brains GmbH. All rights reserved. + * Copyright (c) 2009, 2017 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Dornierstr. 4 @@ -28,24 +28,14 @@ #include +#define BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR (BSP_INTERRUPT_VECTOR_MAX + 1) + RTEMS_INTERRUPT_LOCK_DEFINE( static, bsp_interrupt_server_lock, "Interrupt Server" ) -typedef struct bsp_interrupt_server_action { - struct bsp_interrupt_server_action *next; - rtems_interrupt_handler handler; - void *arg; -} bsp_interrupt_server_action; - -typedef struct { - rtems_chain_node node; - rtems_vector_number vector; - bsp_interrupt_server_action *actions; -} bsp_interrupt_server_entry; - static rtems_id bsp_interrupt_server_id = RTEMS_ID_NONE; static RTEMS_CHAIN_DEFINE_EMPTY(bsp_interrupt_server_chain); @@ -64,7 +54,7 @@ static unsigned bsp_interrupt_server_errors; static void bsp_interrupt_server_trigger(void *arg) { rtems_interrupt_lock_context lock_context; - bsp_interrupt_server_entry *e = arg; + rtems_interrupt_server_entry *e = arg; bsp_interrupt_vector_disable(e->vector); @@ -82,7 +72,7 @@ static void bsp_interrupt_server_trigger(void *arg) } typedef struct { - bsp_interrupt_server_entry *entry; + rtems_interrupt_server_entry *entry; rtems_option *options; } bsp_interrupt_server_iterate_entry; @@ -102,7 +92,7 @@ static void bsp_interrupt_server_per_handler_routine( } } -static bsp_interrupt_server_entry *bsp_interrupt_server_query_entry( +static rtems_interrupt_server_entry *bsp_interrupt_server_query_entry( rtems_vector_number vector, rtems_option *trigger_options ) @@ -134,8 +124,8 @@ static void bsp_interrupt_server_install_helper(void *arg) { bsp_interrupt_server_helper_data *hd = arg; rtems_status_code sc; - bsp_interrupt_server_entry *e; - bsp_interrupt_server_action *a; + rtems_interrupt_server_entry *e; + rtems_interrupt_server_action *a; rtems_option trigger_options; a = calloc(1, sizeof(*a)); @@ -176,8 +166,8 @@ static void bsp_interrupt_server_install_helper(void *arg) ) { sc = RTEMS_RESOURCE_IN_USE; } else { - bsp_interrupt_server_action **link = &e->actions; - bsp_interrupt_server_action *c; + rtems_interrupt_server_action **link = &e->actions; + rtems_interrupt_server_action *c; sc = RTEMS_SUCCESSFUL; @@ -209,15 +199,15 @@ static void bsp_interrupt_server_remove_helper(void *arg) { bsp_interrupt_server_helper_data *hd = arg; rtems_status_code sc; - bsp_interrupt_server_entry *e; + rtems_interrupt_server_entry *e; rtems_option trigger_options; bsp_interrupt_lock(); e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options); if (e != NULL) { - bsp_interrupt_server_action **link = &e->actions; - bsp_interrupt_server_action *c; + rtems_interrupt_server_action **link = &e->actions; + rtems_interrupt_server_action *c; while ((c = *link) != NULL) { if (c->handler == hd->handler && c->arg == hd->arg) { @@ -274,12 +264,12 @@ static rtems_status_code bsp_interrupt_server_call_helper( .arg = arg, .task = rtems_task_self() }; - bsp_interrupt_server_action a = { + rtems_interrupt_server_action a = { .handler = helper, .arg = &hd }; - bsp_interrupt_server_entry e = { - .vector = BSP_INTERRUPT_VECTOR_MAX + 1, + rtems_interrupt_server_entry e = { + .vector = BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR, .actions = &a }; @@ -289,17 +279,17 @@ static rtems_status_code bsp_interrupt_server_call_helper( return hd.sc; } -static bsp_interrupt_server_entry *bsp_interrupt_server_get_entry(void) +static rtems_interrupt_server_entry *bsp_interrupt_server_get_entry(void) { rtems_interrupt_lock_context lock_context; - bsp_interrupt_server_entry *e; + rtems_interrupt_server_entry *e; rtems_chain_control *chain; rtems_interrupt_lock_acquire(&bsp_interrupt_server_lock, &lock_context); chain = &bsp_interrupt_server_chain; if (!rtems_chain_is_empty(chain)) { - e = (bsp_interrupt_server_entry *) + e = (rtems_interrupt_server_entry *) rtems_chain_get_first_unprotected(chain); rtems_chain_set_off_chain(&e->node); } else { @@ -315,7 +305,7 @@ static void bsp_interrupt_server_task(rtems_task_argument arg) { while (true) { rtems_event_set events; - bsp_interrupt_server_entry *e; + rtems_interrupt_server_entry *e; rtems_event_system_receive( RTEMS_EVENT_SYSTEM_SERVER, @@ -325,11 +315,11 @@ static void bsp_interrupt_server_task(rtems_task_argument arg) ); while ((e = bsp_interrupt_server_get_entry()) != NULL) { - bsp_interrupt_server_action *action = e->actions; + rtems_interrupt_server_action *action = e->actions; rtems_vector_number vector = e->vector; do { - bsp_interrupt_server_action *current = action; + rtems_interrupt_server_action *current = action; action = action->next; (*current->handler)(current->arg); } while (action != NULL); @@ -430,3 +420,97 @@ rtems_status_code rtems_interrupt_server_initialize( return RTEMS_SUCCESSFUL; } + +static void bsp_interrupt_server_entry_initialize( + rtems_interrupt_server_entry *entry +) +{ + rtems_chain_set_off_chain(&entry->node); + entry->vector = BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR; + entry->actions = NULL; +} + +static void bsp_interrupt_server_action_prepend( + rtems_interrupt_server_entry *entry, + rtems_interrupt_server_action *action, + rtems_interrupt_handler handler, + void *arg +) +{ + action->handler = handler; + action->arg = arg; + action->next = entry->actions; + entry->actions = action; +} + +void rtems_interrupt_server_entry_initialize( + rtems_interrupt_server_entry *entry +) +{ + bsp_interrupt_server_entry_initialize(entry); +} + +void rtems_interrupt_server_action_prepend( + rtems_interrupt_server_entry *entry, + rtems_interrupt_server_action *action, + rtems_interrupt_handler handler, + void *arg +) +{ + bsp_interrupt_server_action_prepend(entry, action, handler, arg); +} + +void rtems_interrupt_server_entry_submit( + rtems_id server, + rtems_interrupt_server_entry *entry +) +{ + bsp_interrupt_server_trigger(entry); +} + +static void bsp_interrupt_server_entry_destroy_helper(void *arg) +{ + bsp_interrupt_server_helper_data *hd = arg; + + rtems_event_transient_send(hd->task); +} + +void rtems_interrupt_server_entry_destroy( + rtems_id server, + rtems_interrupt_server_entry *entry +) +{ + rtems_interrupt_lock_context lock_context; + + rtems_interrupt_lock_acquire(&bsp_interrupt_server_lock, &lock_context); + + if (!rtems_chain_is_node_off_chain(&entry->node)) { + rtems_chain_extract_unprotected(&entry->node); + rtems_chain_set_off_chain(&entry->node); + } + + rtems_interrupt_lock_release(&bsp_interrupt_server_lock, &lock_context); + + bsp_interrupt_server_call_helper( + BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR, + 0, + NULL, + NULL, + bsp_interrupt_server_entry_destroy_helper + ); +} + +void rtems_interrupt_server_request_initialize( + rtems_interrupt_server_request *request, + rtems_interrupt_handler handler, + void *arg +) +{ + bsp_interrupt_server_entry_initialize(&request->entry); + bsp_interrupt_server_action_prepend( + &request->entry, + &request->action, + handler, + arg + ); +} diff --git a/cpukit/include/rtems/irq-extension.h b/cpukit/include/rtems/irq-extension.h index fc8c125e1b..71ff800881 100644 --- a/cpukit/include/rtems/irq-extension.h +++ b/cpukit/include/rtems/irq-extension.h @@ -9,7 +9,7 @@ /* * Based on concepts of Pavel Pisa, Till Straumann and Eric Valette. * - * Copyright (c) 2008, 2016 embedded brains GmbH. + * Copyright (c) 2008, 2017 embedded brains GmbH. * * embedded brains GmbH * Dornierstr. 4 @@ -26,6 +26,7 @@ #define RTEMS_IRQ_EXTENSION_H #include +#include #ifdef __cplusplus extern "C" { @@ -202,6 +203,52 @@ rtems_status_code rtems_interrupt_handler_iterate( void *arg ); +/** + * @brief An interrupt server action. + * + * This structure must be treated as an opaque data type. Members must not be + * accessed directly. + * + * @see rtems_interrupt_server_action_prepend(). + */ +typedef struct rtems_interrupt_server_action { + struct rtems_interrupt_server_action *next; + rtems_interrupt_handler handler; + void *arg; +} rtems_interrupt_server_action; + +/** + * @brief An interrupt server entry. + * + * This structure must be treated as an opaque data type. Members must not be + * accessed directly. + * + * @see rtems_interrupt_server_entry_initialize(), + * rtems_interrupt_server_action_prepend(), + * rtems_interrupt_server_entry_submit(), and + * rtems_interrupt_server_entry_destroy(). + */ +typedef struct { + rtems_chain_node node; + rtems_vector_number vector; + rtems_interrupt_server_action *actions; +} rtems_interrupt_server_entry; + +/** + * @brief An interrupt server request. + * + * This structure must be treated as an opaque data type. Members must not be + * accessed directly. + * + * @see rtems_interrupt_server_request_initialize(), + * rtems_interrupt_server_request_submit(), and + * rtems_interrupt_server_request_destroy(). + */ +typedef struct { + rtems_interrupt_server_entry entry; + rtems_interrupt_server_action action; +} rtems_interrupt_server_request; + /** * @brief Initializes an interrupt server task. * @@ -285,6 +332,139 @@ rtems_status_code rtems_interrupt_server_handler_remove( void *arg ); +/** + * @brief Initializes the specified interrupt server entry. + * + * @param[in] entry The interrupt server entry to initialize. + * + * @see rtems_interrupt_server_action_prepend(). + */ +void rtems_interrupt_server_entry_initialize( + rtems_interrupt_server_entry *entry +); + +/** + * @brief Prepends the specified interrupt server action to the list of actions + * of the specified interrupt server entry. + * + * No error checking is performed. + * + * @param[in] entry The interrupt server entry to prepend the interrupt server + * action. It must have been initialized via + * rtems_interrupt_server_entry_initialize(). + * @param[in] action The interrupt server action to prepend the list of actions + * of the entry. + * @param[in] handler The interrupt handler for the action. + * @param[in] arg The interrupt handler argument for the action. + */ +void rtems_interrupt_server_action_prepend( + rtems_interrupt_server_entry *entry, + rtems_interrupt_server_action *action, + rtems_interrupt_handler handler, + void *arg +); + +/** + * @brief Submits the specified interrupt server entry so that its interrupt + * server actions can be invoked by the specified interrupt server. + * + * This function may be used to do a two-step interrupt processing. The first + * step is done in interrupt context which calls this function. The second + * step is then done in the context of the interrupt server. + * + * This function may be called from thread or interrupt context. It does not + * block. No error checking is performed. + * + * @param[in] server The server identifier. Use @c RTEMS_ID_NONE to specify + * the default server. + * @param[in] entry The interrupt server entry must be initialized before the + * first call to this function via rtems_interrupt_server_entry_initialize() + * and rtems_interrupt_server_action_prepend(). The entry and its actions + * must not be modified between calls to this function. Use + * rtems_interrupt_server_entry_destroy() to destroy an entry in use. + */ +void rtems_interrupt_server_entry_submit( + rtems_id server, + rtems_interrupt_server_entry *entry +); + +/** + * @brief Destroys the specified interrupt server entry. + * + * This function must be called from thread context. It may block. No error + * checking is performed. + * + * @param[in] server The server identifier. Use @c RTEMS_ID_NONE to specify + * the default server. + * @param[in] entry The interrupt server entry to destroy. It must have been + * initialized via rtems_interrupt_server_entry_initialize(). + */ +void rtems_interrupt_server_entry_destroy( + rtems_id server, + rtems_interrupt_server_entry *entry +); + +/** + * @brief Initializes the specified interrupt server request. + * + * No error checking is performed. + * + * @param[in] request The interrupt server request to initialize. + * @param[in] handler The interrupt handler for the request action. + * @param[in] arg The interrupt handler argument for the request action. + */ +void rtems_interrupt_server_request_initialize( + rtems_interrupt_server_request *request, + rtems_interrupt_handler handler, + void *arg +); + +/** + * @brief Submits the specified interrupt server request so that its interrupt + * server action can be invoked by the specified interrupt server. + * + * This function may be used to do a two-step interrupt processing. The first + * step is done in interrupt context which calls this function. The second + * step is then done in the context of the interrupt server. + * + * This function may be called from thread or interrupt context. It does not + * block. No error checking is performed. + * + * @param[in] server The server identifier. Use @c RTEMS_ID_NONE to specify + * the default server. + * @param[in] request The interrupt server request must be initialized before the + * first call to this function via + * rtems_interrupt_server_request_initialize(). The request must not be + * modified between calls to this function. Use + * rtems_interrupt_server_request_destroy() to destroy a request in use. + */ +RTEMS_INLINE_ROUTINE void rtems_interrupt_server_request_submit( + rtems_id server, + rtems_interrupt_server_request *request +) +{ + rtems_interrupt_server_entry_submit( server, &request->entry ); +} + +/** + * @brief Destroys the specified interrupt server request. + * + * This function must be called from thread context. It may block. No error + * checking is performed. + * + * @param[in] server The server identifier. Use @c RTEMS_ID_NONE to specify + * the default server. + * @param[in] request The interrupt server request to destroy. It must have + * been initialized via rtems_interrupt_server_request_initialize(). + */ +RTEMS_INLINE_ROUTINE void rtems_interrupt_server_request_destroy( + rtems_id server, + rtems_interrupt_server_request *request +) +{ + rtems_interrupt_server_entry_destroy( server, &request->entry ); +} + /** @} */ #ifdef __cplusplus -- cgit v1.2.3