Changeset 5eb07731 in rtems


Ignore:
Timestamp:
Jul 30, 2020, 8:30:15 AM (8 weeks ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
5
Children:
4a2ac5e
Parents:
849d7418
git-author:
Sebastian Huber <sebastian.huber@…> (07/30/20 08:30:15)
git-committer:
Sebastian Huber <sebastian.huber@…> (08/03/20 06:43:45)
Message:

rtems: Add rtems_interrupt_server_create()

Add rtems_interrupt_server_destroy().

Before this patch, the only way to create interrupt servers was
rtems_interrupt_server_initialize(). This function creates the default
interrupt server and in SMP configurations additional interrupt servers
for the additional processors. The interrupt server is heavily used by
libbsd. This includes the epoch based reclamation which performs time
consuming resource and memory deallocation work. This does not work well
with time critical services, for example an UART over SPI or I2C. One
approach to address this problem is to allow the application to create
custom interrupt servers with the right priority and task properties.
The interrupt server API accounted for this, however, it was not
implemented before this patch.

Close #4033.

Files:
2 edited

Legend:

Unmodified
Added
Removed
  • bsps/shared/irq/irq-server.c

    r849d7418 r5eb07731  
    88
    99/*
    10  * Copyright (c) 2009, 2019 embedded brains GmbH.  All rights reserved.
    11  *
    12  *  embedded brains GmbH
    13  *  Dornierstr. 4
    14  *  82178 Puchheim
    15  *  Germany
    16  *  <rtems@embedded-brains.de>
     10 * Copyright (C) 2009, 2020 embedded brains GmbH (http://www.embedded-brains.de)
    1711 *
    1812 * The license and distribution terms for this file may be
     
    2216
    2317#include <stdlib.h>
     18#include <string.h>
    2419
    2520#include <rtems.h>
     
    3126#define BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR (BSP_INTERRUPT_VECTOR_MAX + 1)
    3227
    33 typedef struct {
    34   RTEMS_INTERRUPT_LOCK_MEMBER(lock);
    35   rtems_chain_control entries;
    36   rtems_id server;
    37   unsigned errors;
    38 } bsp_interrupt_server_context;
    39 
    40 #if defined(RTEMS_SMP)
    41 static bsp_interrupt_server_context *bsp_interrupt_server_instances;
    42 #else
    43 static bsp_interrupt_server_context bsp_interrupt_server_instance;
    44 #endif
    45 
    46 static bsp_interrupt_server_context *bsp_interrupt_server_get_context(
     28static rtems_interrupt_server_control bsp_interrupt_server_default;
     29
     30static rtems_chain_control bsp_interrupt_server_chain =
     31  RTEMS_CHAIN_INITIALIZER_EMPTY(bsp_interrupt_server_chain);
     32
     33static rtems_interrupt_server_control *bsp_interrupt_server_get_context(
    4734  uint32_t server_index,
    4835  rtems_status_code *sc
    4936)
    5037{
    51 #if defined(RTEMS_SMP)
    52   if (bsp_interrupt_server_instances == NULL) {
    53     *sc = RTEMS_INCORRECT_STATE;
    54     return NULL;
    55   }
    56 #else
    57   if (bsp_interrupt_server_instance.server == RTEMS_ID_NONE) {
    58     *sc = RTEMS_INCORRECT_STATE;
    59     return NULL;
    60   }
    61 #endif
    62 
    63   if (server_index >= rtems_scheduler_get_processor_maximum()) {
    64     *sc = RTEMS_INVALID_ID;
    65     return NULL;
    66   }
    67 
    68   *sc = RTEMS_SUCCESSFUL;
    69 #if defined(RTEMS_SMP)
    70   return &bsp_interrupt_server_instances[server_index];
    71 #else
    72   return &bsp_interrupt_server_instance;
    73 #endif
     38  rtems_chain_node *node;
     39
     40  bsp_interrupt_lock();
     41  node = rtems_chain_first(&bsp_interrupt_server_chain);
     42
     43  while (node != rtems_chain_tail(&bsp_interrupt_server_chain)) {
     44    rtems_interrupt_server_control *s;
     45
     46    s = RTEMS_CONTAINER_OF(node, rtems_interrupt_server_control, node);
     47    if (s->index == server_index) {
     48      bsp_interrupt_unlock();
     49      return s;
     50    }
     51
     52    node = rtems_chain_next(node);
     53  }
     54
     55  bsp_interrupt_unlock();
     56  *sc = RTEMS_INVALID_ID;
     57  return NULL;
    7458}
    7559
     
    7862  rtems_interrupt_lock_context lock_context;
    7963  rtems_interrupt_server_entry *e = arg;
    80   bsp_interrupt_server_context *s = e->server;
     64  rtems_interrupt_server_control *s = e->server;
    8165
    8266  if (bsp_interrupt_is_valid_vector(e->vector)) {
     
    138122
    139123typedef struct {
    140   bsp_interrupt_server_context *server;
     124  rtems_interrupt_server_control *server;
    141125  rtems_vector_number vector;
    142126  rtems_option options;
     
    282266
    283267static rtems_status_code bsp_interrupt_server_call_helper(
    284   bsp_interrupt_server_context *s,
     268  rtems_interrupt_server_control *s,
    285269  rtems_vector_number vector,
    286270  rtems_option options,
     
    315299
    316300static rtems_interrupt_server_entry *bsp_interrupt_server_get_entry(
    317   bsp_interrupt_server_context *s
     301  rtems_interrupt_server_control *s
    318302)
    319303{
     
    338322static void bsp_interrupt_server_task(rtems_task_argument arg)
    339323{
    340   bsp_interrupt_server_context *s = (bsp_interrupt_server_context *) arg;
     324  rtems_interrupt_server_control *s = (rtems_interrupt_server_control *) arg;
    341325
    342326  while (true) {
     
    378362{
    379363  rtems_status_code sc;
    380   bsp_interrupt_server_context *s;
     364  rtems_interrupt_server_control *s;
    381365
    382366  s = bsp_interrupt_server_get_context(server_index, &sc);
     
    403387{
    404388  rtems_status_code sc;
    405   bsp_interrupt_server_context *s;
     389  rtems_interrupt_server_control *s;
    406390
    407391  s = bsp_interrupt_server_get_context(server_index, &sc);
     
    465449  rtems_status_code sc;
    466450  bsp_interrupt_server_handler_iterate_helper_data hihd;
    467   bsp_interrupt_server_context *s;
     451  rtems_interrupt_server_control *s;
    468452
    469453  s = bsp_interrupt_server_get_context(server_index, &sc);
     
    488472}
    489473
     474/*
     475 * The default server is statically allocated.  Just clear the structure so
     476 * that it can be re-initialized.
     477 */
     478static void bsp_interrupt_server_destroy_default(
     479  rtems_interrupt_server_control *s
     480)
     481{
     482  memset(s, 0, sizeof(*s));
     483}
     484
     485#if defined(RTEMS_SMP)
     486static void bsp_interrupt_server_destroy_secondary(
     487  rtems_interrupt_server_control *s
     488)
     489{
     490  free(s);
     491}
     492#endif
     493
     494static rtems_status_code bsp_interrupt_server_create(
     495  rtems_interrupt_server_control *s,
     496  rtems_task_priority priority,
     497  size_t stack_size,
     498  rtems_mode modes,
     499  rtems_attribute attributes,
     500  uint32_t cpu_index
     501)
     502{
     503  rtems_status_code sc;
     504#if defined(RTEMS_SMP)
     505  rtems_id scheduler;
     506  cpu_set_t cpu;
     507#endif
     508
     509  rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
     510  rtems_chain_initialize_empty(&s->entries);
     511
     512  sc = rtems_task_create(
     513    rtems_build_name('I', 'R', 'Q', 'S'),
     514    priority,
     515    stack_size,
     516    modes,
     517    attributes,
     518    &s->server
     519  );
     520  if (sc != RTEMS_SUCCESSFUL) {
     521    return sc;
     522  }
     523
     524#if defined(RTEMS_SMP)
     525  sc = rtems_scheduler_ident_by_processor(cpu_index, &scheduler);
     526  if (sc != RTEMS_SUCCESSFUL) {
     527    /* Do not start an interrupt server on a processor without a scheduler */
     528    return RTEMS_SUCCESSFUL;
     529  }
     530
     531  sc = rtems_task_set_scheduler(s->server, scheduler, priority);
     532  _Assert(sc == RTEMS_SUCCESSFUL);
     533
     534  /* Set the task to processor affinity on a best-effort basis */
     535  CPU_ZERO(&cpu);
     536  CPU_SET(cpu_index, &cpu);
     537  (void) rtems_task_set_affinity(s->server, sizeof(cpu), &cpu);
     538#else
     539  (void) cpu_index;
     540#endif
     541
     542  rtems_chain_append_unprotected(&bsp_interrupt_server_chain, &s->node);
     543
     544  sc = rtems_task_start(
     545    s->server,
     546    bsp_interrupt_server_task,
     547    (rtems_task_argument) s
     548  );
     549  _Assert(sc == RTEMS_SUCCESSFUL);
     550
     551  return sc;
     552}
     553
    490554rtems_status_code rtems_interrupt_server_initialize(
    491555  rtems_task_priority priority,
     
    496560)
    497561{
     562  rtems_status_code sc;
     563  rtems_interrupt_server_control *s;
    498564  uint32_t cpu_index;
     565#if defined(RTEMS_SMP)
    499566  uint32_t cpu_count;
    500   uint32_t dummy;
    501   bsp_interrupt_server_context *instances;
    502 
    503   if (server_count == NULL) {
    504     server_count = &dummy;
    505   }
    506 
     567#endif
     568
     569  cpu_index = 0;
     570  s = &bsp_interrupt_server_default;
     571
     572  bsp_interrupt_lock();
     573
     574  if (s->server != 0) {
     575    sc = RTEMS_INCORRECT_STATE;
     576    goto done;
     577  }
     578
     579  s->destroy = bsp_interrupt_server_destroy_default;
     580  sc = bsp_interrupt_server_create(
     581    s,
     582    priority,
     583    stack_size,
     584    modes,
     585    attributes,
     586    cpu_index
     587  );
     588  if (sc != RTEMS_SUCCESSFUL) {
     589    goto done;
     590  }
     591
     592  cpu_index = 1;
     593
     594#if defined(RTEMS_SMP)
    507595  cpu_count = rtems_scheduler_get_processor_maximum();
    508596
    509 #if defined(RTEMS_SMP)
    510   instances = calloc(cpu_count, sizeof(*instances));
    511   if (instances == NULL) {
    512     return RTEMS_NO_MEMORY;
    513   }
    514 #else
    515   instances = &bsp_interrupt_server_instance;
    516 #endif
    517 
    518   for (cpu_index = 0; cpu_index < cpu_count; ++cpu_index) {
    519     bsp_interrupt_server_context *s = &instances[cpu_index];
    520     rtems_status_code sc;
    521 #if defined(RTEMS_SMP)
    522     rtems_id scheduler;
    523     cpu_set_t cpu;
    524 #endif
    525 
    526     rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
    527     rtems_chain_initialize_empty(&s->entries);
    528 
    529     sc = rtems_task_create(
    530       rtems_build_name('I', 'R', 'Q', 'S'),
     597  while (cpu_index < cpu_count) {
     598    s = calloc(1, sizeof(*s));
     599
     600    if (s == NULL) {
     601      sc = RTEMS_NO_MEMORY;
     602      goto done;
     603    }
     604
     605    s->destroy = bsp_interrupt_server_destroy_secondary;
     606    s->index = cpu_index;
     607    sc = bsp_interrupt_server_create(
     608      s,
    531609      priority,
    532610      stack_size,
    533611      modes,
    534612      attributes,
    535       &s->server
     613      cpu_index
    536614    );
    537615    if (sc != RTEMS_SUCCESSFUL) {
    538       *server_count = cpu_index;
    539 
    540 #if defined(RTEMS_SMP)
    541       if (cpu_index > 0) {
    542         bsp_interrupt_server_instances = instances;
    543         return RTEMS_SUCCESSFUL;
    544       }
    545 
    546       free(instances);
     616      goto done;
     617    }
     618
     619    ++cpu_index;
     620  }
    547621#endif
    548622
    549       return RTEMS_TOO_MANY;
    550     }
    551 
    552 #if defined(RTEMS_SMP)
    553     sc = rtems_scheduler_ident_by_processor(cpu_index, &scheduler);
    554     if (sc != RTEMS_SUCCESSFUL) {
    555       /* Do not start an interrupt server on a processor without a scheduler */
    556       continue;
    557     }
    558 
    559     sc = rtems_task_set_scheduler(s->server, scheduler, priority);
    560     _Assert(sc == RTEMS_SUCCESSFUL);
    561 
    562     /* Set the task to processor affinity on a best-effort basis */
    563     CPU_ZERO(&cpu);
    564     CPU_SET(cpu_index, &cpu);
    565     (void) rtems_task_set_affinity(s->server, sizeof(cpu), &cpu);
    566 #endif
    567 
    568     sc = rtems_task_start(
    569       s->server,
    570       bsp_interrupt_server_task,
    571       (rtems_task_argument) s
    572     );
    573     _Assert(sc == RTEMS_SUCCESSFUL);
    574   }
    575 
    576 #if defined(RTEMS_SMP)
    577   bsp_interrupt_server_instances = instances;
    578 #endif
    579   *server_count = cpu_index;
    580 
     623done:
     624  bsp_interrupt_unlock();
     625
     626  if (server_count != NULL) {
     627    *server_count = cpu_index;
     628  }
     629
     630  return sc;
     631}
     632
     633rtems_status_code rtems_interrupt_server_create(
     634  rtems_interrupt_server_control      *s,
     635  const rtems_interrupt_server_config *config,
     636  uint32_t                            *server_index
     637)
     638{
     639  rtems_status_code sc;
     640
     641  sc = rtems_task_create(
     642    config->name,
     643    config->priority,
     644    config->storage_size,
     645    config->modes,
     646    config->attributes,
     647    &s->server
     648  );
     649  if (sc != RTEMS_SUCCESSFUL) {
     650    return sc;
     651  }
     652
     653  rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
     654  rtems_chain_initialize_empty(&s->entries);
     655  s->destroy = config->destroy;
     656  s->index = rtems_object_id_get_index(s->server)
     657    + rtems_scheduler_get_processor_maximum();
     658  *server_index = s->index;
     659
     660  bsp_interrupt_lock();
     661  rtems_chain_initialize_node(&s->node);
     662  rtems_chain_append_unprotected(&bsp_interrupt_server_chain, &s->node);
     663  bsp_interrupt_unlock();
     664
     665  sc = rtems_task_start(
     666    s->server,
     667    bsp_interrupt_server_task,
     668    (rtems_task_argument) s
     669  );
     670  _Assert(sc == RTEMS_SUCCESSFUL);
     671
     672  return sc;
     673}
     674
     675static void bsp_interrupt_server_destroy_helper(void *arg)
     676{
     677  bsp_interrupt_server_helper_data *hd = arg;
     678  rtems_interrupt_server_control *s = hd->server;
     679  rtems_status_code sc;
     680
     681  bsp_interrupt_lock();
     682  rtems_chain_extract_unprotected(&s->node);
     683  bsp_interrupt_unlock();
     684
     685  if (s->destroy != NULL) {
     686    (*s->destroy)(s);
     687  }
     688
     689  sc = rtems_event_transient_send(hd->task);
     690  _Assert(sc == RTEMS_SUCCESSFUL);
     691  (void) sc;
     692
     693  rtems_task_exit();
     694}
     695
     696rtems_status_code rtems_interrupt_server_delete(uint32_t server_index)
     697{
     698  rtems_status_code sc;
     699  rtems_interrupt_server_control *s;
     700
     701  s = bsp_interrupt_server_get_context(server_index, &sc);
     702  if (s == NULL) {
     703    return sc;
     704  }
     705
     706  bsp_interrupt_server_call_helper(
     707    s,
     708    BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
     709    0,
     710    NULL,
     711    NULL,
     712    bsp_interrupt_server_destroy_helper
     713  );
    581714  return RTEMS_SUCCESSFUL;
    582715}
     
    584717static void bsp_interrupt_server_entry_initialize(
    585718  rtems_interrupt_server_entry *entry,
    586   bsp_interrupt_server_context *s
     719  rtems_interrupt_server_control *s
    587720)
    588721{
     
    612745{
    613746  rtems_status_code sc;
    614   bsp_interrupt_server_context *s;
     747  rtems_interrupt_server_control *s;
    615748
    616749  s = bsp_interrupt_server_get_context(server_index, &sc);
     
    646779{
    647780  rtems_status_code sc;
    648   bsp_interrupt_server_context *s;
     781  rtems_interrupt_server_control *s;
    649782
    650783  s = bsp_interrupt_server_get_context(destination_server_index, &sc);
     
    668801)
    669802{
    670   bsp_interrupt_server_context *s;
     803  rtems_interrupt_server_control *s;
    671804  rtems_interrupt_lock_context lock_context;
    672805
     
    699832{
    700833  rtems_status_code sc;
    701   bsp_interrupt_server_context *s;
     834  rtems_interrupt_server_control *s;
    702835
    703836  s = bsp_interrupt_server_get_context(server_index, &sc);
     
    728861  if (e != NULL) {
    729862    rtems_interrupt_lock_context lock_context;
    730     bsp_interrupt_server_context *src = e->server;
    731     bsp_interrupt_server_context *dst = hihd->arg;
     863    rtems_interrupt_server_control *src = e->server;
     864    rtems_interrupt_server_control *dst = hihd->arg;
    732865    bool pending;
    733866
     
    764897{
    765898  rtems_status_code sc;
    766   bsp_interrupt_server_context *src;
    767   bsp_interrupt_server_context *dst;
     899  rtems_interrupt_server_control *src;
     900  rtems_interrupt_server_control *dst;
    768901  bsp_interrupt_server_handler_iterate_helper_data hihd;
    769902
     
    811944{
    812945  rtems_status_code sc;
    813   bsp_interrupt_server_context *s;
     946  rtems_interrupt_server_control *s;
    814947
    815948  s = bsp_interrupt_server_get_context(server_index, &sc);
     
    832965{
    833966  rtems_status_code sc;
    834   bsp_interrupt_server_context *s;
     967  rtems_interrupt_server_control *s;
    835968
    836969  s = bsp_interrupt_server_get_context(server_index, &sc);
     
    859992{
    860993  rtems_status_code sc;
    861   bsp_interrupt_server_context *s;
     994  rtems_interrupt_server_control *s;
    862995  rtems_id scheduler;
    863996
  • cpukit/include/rtems/irq-extension.h

    r849d7418 r5eb07731  
    1010 * Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
    1111 *
    12  * Copyright (C) 2008, 2019 embedded brains GmbH
    13  *
    14  *  embedded brains GmbH
    15  *  Dornierstr. 4
    16  *  82178 Puchheim
    17  *  Germany
    18  *  <rtems@embedded-brains.de>
     12 * Copyright (C) 2008, 2020 embedded brains GmbH (http://www.embedded-brains.de)
    1913 *
    2014 * The license and distribution terms for this file may be
     
    261255
    262256/**
     257 * @brief An interrupt server control.
     258 *
     259 * This structure must be treated as an opaque data type.  Members must not be
     260 * accessed directly.
     261 *
     262 * @see rtems_interrupt_server_create()
     263 */
     264typedef struct rtems_interrupt_server_control {
     265  RTEMS_INTERRUPT_LOCK_MEMBER( lock )
     266  rtems_chain_control          entries;
     267  rtems_id                     server;
     268  unsigned long                errors;
     269  uint32_t                     index;
     270  rtems_chain_node             node;
     271  void ( *destroy )( struct rtems_interrupt_server_control * );
     272} rtems_interrupt_server_control;
     273
     274/**
     275 * @brief An interrupt server configuration.
     276 *
     277 * @see rtems_interrupt_server_create()
     278 */
     279typedef struct {
     280  /**
     281   * @brief The task name of the interrupt server.
     282   */
     283  rtems_name name;
     284
     285  /**
     286   * @brief The initial task priority of the interrupt server.
     287   */
     288  rtems_task_priority priority;
     289
     290  /**
     291   * @brief The task storage area of the interrupt server.
     292   *
     293   * It shall be NULL for interrupt servers created by
     294   * rtems_interrupt_server_create().
     295   */
     296  void *storage_area;
     297
     298  /**
     299   * @brief The task storage size of the interrupt server.
     300   *
     301   * For interrupt servers created by rtems_interrupt_server_create() this is
     302   * the task stack size.
     303   */
     304  size_t storage_size;
     305
     306  /**
     307   * @brief The initial task modes of the interrupt server.
     308   */
     309  rtems_mode modes;
     310
     311  /**
     312   * @brief The task attributes of the interrupt server.
     313   */
     314  rtems_attribute attributes;
     315
     316  /**
     317   * @brief An optional handler to destroy the interrupt server control handed
     318   *   over to rtems_interrupt_server_create().
     319   *
     320   * This handler is called in the context of the interrupt server to be
     321   * deleted, see also rtems_interrupt_server_delete().
     322   */
     323  void ( *destroy )( rtems_interrupt_server_control * );
     324} rtems_interrupt_server_config;
     325
     326/**
    263327 * @brief An interrupt server entry.
    264328 *
     
    310374 * The server count pointer @a server_count may be @a NULL.
    311375 *
     376 * The task name of interrupt servers created by this function is
     377 * rtems_build_name( 'I', 'R', 'Q', 'S' ).
     378 *
    312379 * This function may block.
    313380 *
    314  * @see rtems_task_create().
    315  *
    316  * @retval RTEMS_SUCCESSFUL Successful operation.
    317  * @retval RTEMS_INCORRECT_STATE The interrupt servers are not initialized.
    318  * @retval RTEMS_NO_MEMORY Not enough memory.
    319  * @retval RTEMS_TOO_MANY No free task available to create at least one server task.
    320  * @retval RTEMS_UNSATISFIED Task stack size too large.
    321  * @retval RTEMS_INVALID_PRIORITY Invalid task priority.
     381 * @retval RTEMS_SUCCESSFUL The operation was successful.
     382 *
     383 * @retval RTEMS_INCORRECT_STATE The interrupt servers were already initialized.
     384 *
     385 * @return The function uses rtems_task_create().  If this operation is not
     386 *   successful, then its status code is returned.
     387 *
     388 * @see rtems_interrupt_server_create() and rtems_interrupt_server_delete().
    322389 */
    323390rtems_status_code rtems_interrupt_server_initialize(
     
    328395  uint32_t *server_count
    329396);
     397
     398/**
     399 * @brief Creates an interrupt server.
     400 *
     401 * This function may block.
     402 *
     403 * @param[out] control is the interrupt server control.  The ownership of this
     404 *   structure is transferred from the caller of this function to the interrupt
     405 *   server management.
     406 *
     407 * @param config is the interrupt server configuration.
     408 *
     409 * @param[out] server_index is the pointer to a server index variable.  The
     410 *   index of the built interrupt server will be stored in the referenced
     411 *   variable if the operation was successful.
     412 *
     413 * @retval RTEMS_SUCCESSFUL The operation was successful.
     414 *
     415 * @return The function uses rtems_task_create().  If this operation is not
     416 *   successful, then its status code is returned.
     417 *
     418 * @see rtems_interrupt_server_initialize() and
     419 *   rtems_interrupt_server_delete().
     420 */
     421rtems_status_code rtems_interrupt_server_create(
     422  rtems_interrupt_server_control      *control,
     423  const rtems_interrupt_server_config *config,
     424  uint32_t                            *server_index
     425);
     426
     427/**
     428 * @brief Destroys the interrupt server.
     429 *
     430 * This function may block.
     431 *
     432 * The interrupt server deletes itself, so after the return of the function the
     433 * interrupt server may be still in the termination process depending on the
     434 * task priorities of the system.
     435 *
     436 * @param server_index is the index of the interrupt server to destroy.  Use
     437 *   ::RTEMS_INTERRUPT_SERVER_DEFAULT to specify the default server.
     438 *
     439 * @retval RTEMS_SUCCESSFUL The operation was successful.
     440 * @retval RTEMS_INVALID_ID The interrupt server index was invalid.
     441 *
     442 * @see rtems_interrupt_server_create()
     443 */
     444rtems_status_code rtems_interrupt_server_delete( uint32_t server_index );
    330445
    331446/**
Note: See TracChangeset for help on using the changeset viewer.