Changeset 10670a5 in rtems


Ignore:
Timestamp:
Jun 13, 2016, 8:30:42 AM (3 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
master
Children:
a0cd238d
Parents:
3bf9fdb
Message:

bsp/irq-server: Fix install/remove

Do not wait for the interrupt server while owning the allocator lock.
This could lead to deadlock in case one of interrupt service routines or
user extensions want to obtain the allocator mutex as well. Instead let
the interrupt server do the install/remove job entirely on behalf of the
requesting task.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • c/src/lib/libbsp/shared/src/irq-server.c

    r3bf9fdb r10670a5  
    8383
    8484typedef struct {
    85   bsp_interrupt_server_action *action;
    86   bsp_interrupt_server_action **link;
    87   rtems_id task;
    88 } bsp_interrupt_server_helper_data;
    89 
    90 static void bsp_interrupt_server_helper(void *arg)
    91 {
    92   bsp_interrupt_server_helper_data *hd = arg;
    93 
    94   *hd->link = hd->action;
    95   rtems_event_transient_send(hd->task);
    96 }
    97 
    98 static void bsp_interrupt_server_call_helper(
    99   bsp_interrupt_server_action *action,
    100   bsp_interrupt_server_action **link
    101 )
    102 {
    103   bsp_interrupt_server_helper_data hd = {
    104     .action = action,
    105     .link = link,
    106     .task = rtems_task_self()
    107   };
    108   bsp_interrupt_server_action a = {
    109     .handler = bsp_interrupt_server_helper,
    110     .arg = &hd
    111   };
    112   bsp_interrupt_server_entry e = {
    113     .vector = BSP_INTERRUPT_VECTOR_MAX + 1,
    114     .actions = &a
    115   };
    116 
    117   bsp_interrupt_server_trigger(&e);
    118   rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    119 }
    120 
    121 static bsp_interrupt_server_entry *bsp_interrupt_server_get_entry(void)
    122 {
    123   rtems_interrupt_lock_context lock_context;
    124   bsp_interrupt_server_entry *e;
    125   rtems_chain_control *chain;
    126 
    127   rtems_interrupt_lock_acquire(&bsp_interrupt_server_lock, &lock_context);
    128   chain = &bsp_interrupt_server_chain;
    129 
    130   if (!rtems_chain_is_empty(chain)) {
    131     e = (bsp_interrupt_server_entry *)
    132       rtems_chain_get_first_unprotected(chain);
    133     rtems_chain_set_off_chain(&e->node);
    134   } else {
    135     e = NULL;
    136   }
    137 
    138   rtems_interrupt_lock_release(&bsp_interrupt_server_lock, &lock_context);
    139 
    140   return e;
    141 }
    142 
    143 static void bsp_interrupt_server_task(rtems_task_argument arg)
    144 {
    145   while (true) {
    146     rtems_event_set events;
    147     bsp_interrupt_server_entry *e;
    148 
    149     rtems_event_system_receive(
    150       RTEMS_EVENT_SYSTEM_SERVER,
    151       RTEMS_EVENT_ALL | RTEMS_WAIT,
    152       RTEMS_NO_TIMEOUT,
    153       &events
    154     );
    155 
    156     while ((e = bsp_interrupt_server_get_entry()) != NULL) {
    157       bsp_interrupt_server_action *action = e->actions;
    158       rtems_vector_number vector = e->vector;
    159 
    160       do {
    161         bsp_interrupt_server_action *current = action;
    162         action = action->next;
    163         (*current->handler)(current->arg);
    164       } while (action != NULL);
    165 
    166       bsp_interrupt_vector_enable(vector);
    167     }
    168   }
    169 }
    170 
    171 typedef struct {
    17285  bsp_interrupt_server_entry *entry;
    17386  rtems_option *options;
     
    209122}
    210123
    211 rtems_status_code rtems_interrupt_server_handler_install(
    212   rtems_id server,
    213   rtems_vector_number vector,
    214   const char *info,
    215   rtems_option options,
    216   rtems_interrupt_handler handler,
    217   void *arg
    218 )
    219 {
     124typedef struct {
     125  rtems_vector_number vector;
     126  rtems_option options;
     127  rtems_interrupt_handler handler;
     128  void *arg;
     129  rtems_id task;
     130  rtems_status_code sc;
     131} bsp_interrupt_server_helper_data;
     132
     133static void bsp_interrupt_server_install_helper(void *arg)
     134{
     135  bsp_interrupt_server_helper_data *hd = arg;
    220136  rtems_status_code sc;
    221137  bsp_interrupt_server_entry *e;
     
    223139  rtems_option trigger_options;
    224140
    225   sc = bsp_interrupt_server_is_initialized();
    226   if (sc != RTEMS_SUCCESSFUL) {
    227     return sc;
    228   }
    229 
    230   if (server != RTEMS_ID_NONE) {
    231     return RTEMS_NOT_IMPLEMENTED;
    232   }
    233 
    234141  a = calloc(1, sizeof(*a));
    235142  if (a == NULL) {
    236     return RTEMS_NO_MEMORY;
    237   }
    238 
    239   a->handler = handler;
    240   a->arg = arg;
     143    hd->sc = RTEMS_NO_MEMORY;
     144    rtems_event_transient_send(hd->task);
     145    return;
     146  }
     147
     148  a->handler = hd->handler;
     149  a->arg = hd->arg;
    241150
    242151  bsp_interrupt_lock();
    243152
    244   e = bsp_interrupt_server_query_entry(vector, &trigger_options);
     153  e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
    245154  if (e == NULL) {
    246155    e = calloc(1, sizeof(*e));
    247156    if (e != NULL) {
    248       e->vector = vector;
     157      e->vector = hd->vector;
    249158      e->actions = a;
    250159
    251160      sc = rtems_interrupt_handler_install(
    252         vector,
     161        hd->vector,
    253162        "IRQS",
    254         options & RTEMS_INTERRUPT_UNIQUE,
     163        hd->options & RTEMS_INTERRUPT_UNIQUE,
    255164        bsp_interrupt_server_trigger,
    256165        e
     
    263172    }
    264173  } else if (
    265     RTEMS_INTERRUPT_IS_UNIQUE(options)
     174    RTEMS_INTERRUPT_IS_UNIQUE(hd->options)
    266175      || RTEMS_INTERRUPT_IS_UNIQUE(trigger_options)
    267176  ) {
     
    271180    bsp_interrupt_server_action *c;
    272181
     182    sc = RTEMS_SUCCESSFUL;
     183
    273184    while ((c = *link) != NULL) {
    274       if (c->handler == handler && c->arg == arg) {
     185      if (c->handler == hd->handler && c->arg == hd->arg) {
    275186        sc = RTEMS_TOO_MANY;
    276187        break;
     
    281192
    282193    if (sc == RTEMS_SUCCESSFUL) {
    283       bsp_interrupt_server_call_helper(a, link);
     194      *link = a;
    284195    }
    285196  }
     
    291202  }
    292203
    293   return sc;
     204  hd->sc = sc;
     205  rtems_event_transient_send(hd->task);
     206}
     207
     208static void bsp_interrupt_server_remove_helper(void *arg)
     209{
     210  bsp_interrupt_server_helper_data *hd = arg;
     211  rtems_status_code sc;
     212  bsp_interrupt_server_entry *e;
     213  rtems_option trigger_options;
     214
     215  bsp_interrupt_lock();
     216
     217  e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
     218  if (e != NULL) {
     219    bsp_interrupt_server_action **link = &e->actions;
     220    bsp_interrupt_server_action *c;
     221
     222    while ((c = *link) != NULL) {
     223      if (c->handler == hd->handler && c->arg == hd->arg) {
     224        break;
     225      }
     226
     227      link = &c->next;
     228    }
     229
     230    if (c != NULL) {
     231      bool remove_last = e->actions->next == NULL;
     232
     233      if (remove_last) {
     234        rtems_interrupt_handler_remove(
     235          hd->vector,
     236          bsp_interrupt_server_trigger,
     237          e
     238        );
     239      }
     240
     241      *link = c->next;
     242      free(c);
     243
     244      if (remove_last) {
     245        free(e);
     246      }
     247
     248      sc = RTEMS_SUCCESSFUL;
     249    } else {
     250      sc = RTEMS_UNSATISFIED;
     251    }
     252  } else {
     253    sc = RTEMS_INVALID_ID;
     254  }
     255
     256  bsp_interrupt_unlock();
     257
     258  hd->sc = sc;
     259  rtems_event_transient_send(hd->task);
     260}
     261
     262static rtems_status_code bsp_interrupt_server_call_helper(
     263  rtems_vector_number vector,
     264  rtems_option options,
     265  rtems_interrupt_handler handler,
     266  void *arg,
     267  void (*helper)(void *)
     268)
     269{
     270  bsp_interrupt_server_helper_data hd = {
     271    .vector = vector,
     272    .options = options,
     273    .handler = handler,
     274    .arg = arg,
     275    .task = rtems_task_self()
     276  };
     277  bsp_interrupt_server_action a = {
     278    .handler = helper,
     279    .arg = &hd
     280  };
     281  bsp_interrupt_server_entry e = {
     282    .vector = BSP_INTERRUPT_VECTOR_MAX + 1,
     283    .actions = &a
     284  };
     285
     286  bsp_interrupt_server_trigger(&e);
     287  rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     288
     289  return hd.sc;
     290}
     291
     292static bsp_interrupt_server_entry *bsp_interrupt_server_get_entry(void)
     293{
     294  rtems_interrupt_lock_context lock_context;
     295  bsp_interrupt_server_entry *e;
     296  rtems_chain_control *chain;
     297
     298  rtems_interrupt_lock_acquire(&bsp_interrupt_server_lock, &lock_context);
     299  chain = &bsp_interrupt_server_chain;
     300
     301  if (!rtems_chain_is_empty(chain)) {
     302    e = (bsp_interrupt_server_entry *)
     303      rtems_chain_get_first_unprotected(chain);
     304    rtems_chain_set_off_chain(&e->node);
     305  } else {
     306    e = NULL;
     307  }
     308
     309  rtems_interrupt_lock_release(&bsp_interrupt_server_lock, &lock_context);
     310
     311  return e;
     312}
     313
     314static void bsp_interrupt_server_task(rtems_task_argument arg)
     315{
     316  while (true) {
     317    rtems_event_set events;
     318    bsp_interrupt_server_entry *e;
     319
     320    rtems_event_system_receive(
     321      RTEMS_EVENT_SYSTEM_SERVER,
     322      RTEMS_EVENT_ALL | RTEMS_WAIT,
     323      RTEMS_NO_TIMEOUT,
     324      &events
     325    );
     326
     327    while ((e = bsp_interrupt_server_get_entry()) != NULL) {
     328      bsp_interrupt_server_action *action = e->actions;
     329      rtems_vector_number vector = e->vector;
     330
     331      do {
     332        bsp_interrupt_server_action *current = action;
     333        action = action->next;
     334        (*current->handler)(current->arg);
     335      } while (action != NULL);
     336
     337      bsp_interrupt_vector_enable(vector);
     338    }
     339  }
     340}
     341
     342rtems_status_code rtems_interrupt_server_handler_install(
     343  rtems_id server,
     344  rtems_vector_number vector,
     345  const char *info,
     346  rtems_option options,
     347  rtems_interrupt_handler handler,
     348  void *arg
     349)
     350{
     351  rtems_status_code sc;
     352
     353  sc = bsp_interrupt_server_is_initialized();
     354  if (sc != RTEMS_SUCCESSFUL) {
     355    return sc;
     356  }
     357
     358  if (server != RTEMS_ID_NONE) {
     359    return RTEMS_NOT_IMPLEMENTED;
     360  }
     361
     362  return bsp_interrupt_server_call_helper(
     363    vector,
     364    options,
     365    handler,
     366    arg,
     367    bsp_interrupt_server_install_helper
     368  );
    294369}
    295370
     
    302377{
    303378  rtems_status_code sc;
    304   bsp_interrupt_server_entry *e;
    305   rtems_option trigger_options;
    306379
    307380  sc = bsp_interrupt_server_is_initialized();
     
    314387  }
    315388
    316   bsp_interrupt_lock();
    317 
    318   e = bsp_interrupt_server_query_entry(vector, &trigger_options);
    319   if (e != NULL) {
    320     bsp_interrupt_server_action **link = &e->actions;
    321     bsp_interrupt_server_action *c;
    322 
    323     while ((c = *link) != NULL) {
    324       if (c->handler == handler && c->arg == arg) {
    325         break;
    326       }
    327 
    328       link = &c->next;
    329     }
    330 
    331     if (c != NULL) {
    332       bool remove_last = e->actions->next == NULL;
    333 
    334       if (remove_last) {
    335         rtems_interrupt_handler_remove(
    336           vector,
    337           bsp_interrupt_server_trigger,
    338           e
    339         );
    340       }
    341 
    342       bsp_interrupt_server_call_helper(c->next, link);
    343       free(c);
    344 
    345       if (remove_last) {
    346         free(e);
    347       }
    348     } else {
    349       sc = RTEMS_UNSATISFIED;
    350     }
    351   } else {
    352     sc = RTEMS_INVALID_ID;
    353   }
    354 
    355   bsp_interrupt_unlock();
    356 
    357   return sc;
     389  return bsp_interrupt_server_call_helper(
     390    vector,
     391    0,
     392    handler,
     393    arg,
     394    bsp_interrupt_server_remove_helper
     395  );
    358396}
    359397
Note: See TracChangeset for help on using the changeset viewer.