source: rtems/bsps/shared/irq/irq-server.c @ 1dbdf94e

5
Last change on this file since 1dbdf94e was 1dbdf94e, checked in by Sebastian Huber <sebastian.huber@…>, on 10/19/20 at 15:39:10

bsps: Fix rtems_interrupt_server_delete()

The ISR lock must be destroyed to prevent memory corruption if RTEMS_PROFILING
and RTEMS_SMP is enabled.

Close #4189.

  • Property mode set to 100644
File size: 22.1 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup bsp_interrupt
5 *
6 * @brief Generic BSP interrupt server implementation.
7 */
8
9/*
10 * Copyright (C) 2009, 2020 embedded brains GmbH (http://www.embedded-brains.de)
11 *
12 * The license and distribution terms for this file may be
13 * found in the file LICENSE in this distribution or at
14 * http://www.rtems.org/license/LICENSE.
15 */
16
17#include <stdlib.h>
18#include <string.h>
19
20#include <rtems.h>
21#include <rtems/chain.h>
22#include <rtems/score/assert.h>
23
24#include <bsp/irq-generic.h>
25
26#define BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR (BSP_INTERRUPT_VECTOR_MAX + 1)
27
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(
34  uint32_t server_index,
35  rtems_status_code *sc
36)
37{
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;
58}
59
60static void bsp_interrupt_server_trigger(void *arg)
61{
62  rtems_interrupt_lock_context lock_context;
63  rtems_interrupt_server_entry *e = arg;
64  rtems_interrupt_server_control *s = e->server;
65
66  if (bsp_interrupt_is_valid_vector(e->vector)) {
67    bsp_interrupt_vector_disable(e->vector);
68  }
69
70  rtems_interrupt_lock_acquire(&s->lock, &lock_context);
71
72  if (rtems_chain_is_node_off_chain(&e->node)) {
73    rtems_chain_append_unprotected(&s->entries, &e->node);
74  } else {
75    ++s->errors;
76  }
77
78  rtems_interrupt_lock_release(&s->lock, &lock_context);
79
80  rtems_event_system_send(s->server, RTEMS_EVENT_SYSTEM_SERVER);
81}
82
83typedef struct {
84  rtems_interrupt_server_entry *entry;
85  rtems_option *options;
86} bsp_interrupt_server_iterate_entry;
87
88static void bsp_interrupt_server_per_handler_routine(
89  void *iterate_arg,
90  const char *info,
91  rtems_option options,
92  rtems_interrupt_handler handler,
93  void *handler_arg
94)
95{
96  if (handler == bsp_interrupt_server_trigger) {
97    bsp_interrupt_server_iterate_entry *ie = iterate_arg;
98
99    ie->entry = handler_arg;
100    *ie->options = options;
101  }
102}
103
104static rtems_interrupt_server_entry *bsp_interrupt_server_query_entry(
105  rtems_vector_number vector,
106  rtems_option *trigger_options
107)
108{
109  bsp_interrupt_server_iterate_entry ie = {
110    .entry = NULL,
111    .options = trigger_options
112  };
113
114  rtems_interrupt_handler_iterate(
115    vector,
116    bsp_interrupt_server_per_handler_routine,
117    &ie
118  );
119
120  return ie.entry;
121}
122
123typedef struct {
124  rtems_interrupt_server_control *server;
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;
136  rtems_status_code sc;
137  rtems_interrupt_server_entry *e;
138  rtems_interrupt_server_action *a;
139  rtems_option trigger_options;
140
141  a = calloc(1, sizeof(*a));
142  if (a == NULL) {
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;
150
151  bsp_interrupt_lock();
152
153  e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
154  if (e == NULL) {
155    e = calloc(1, sizeof(*e));
156    if (e != NULL) {
157      e->server = hd->server;
158      e->vector = hd->vector;
159      e->actions = a;
160
161      sc = rtems_interrupt_handler_install(
162        hd->vector,
163        "IRQS",
164        hd->options & RTEMS_INTERRUPT_UNIQUE,
165        bsp_interrupt_server_trigger,
166        e
167      );
168      if (sc != RTEMS_SUCCESSFUL) {
169        free(e);
170      }
171    } else {
172      sc = RTEMS_NO_MEMORY;
173    }
174#if defined(RTEMS_SMP)
175  } else if (e->server != hd->server) {
176    sc = RTEMS_RESOURCE_IN_USE;
177#endif
178  } else if (
179    RTEMS_INTERRUPT_IS_UNIQUE(hd->options)
180      || RTEMS_INTERRUPT_IS_UNIQUE(trigger_options)
181  ) {
182    sc = RTEMS_RESOURCE_IN_USE;
183  } else {
184    rtems_interrupt_server_action **link = &e->actions;
185    rtems_interrupt_server_action *c;
186
187    sc = RTEMS_SUCCESSFUL;
188
189    while ((c = *link) != NULL) {
190      if (c->handler == hd->handler && c->arg == hd->arg) {
191        sc = RTEMS_TOO_MANY;
192        break;
193      }
194
195      link = &c->next;
196    }
197
198    if (sc == RTEMS_SUCCESSFUL) {
199      *link = a;
200    }
201  }
202
203  bsp_interrupt_unlock();
204
205  if (sc != RTEMS_SUCCESSFUL) {
206    free(a);
207  }
208
209  hd->sc = sc;
210  rtems_event_transient_send(hd->task);
211}
212
213static void bsp_interrupt_server_remove_helper(void *arg)
214{
215  bsp_interrupt_server_helper_data *hd = arg;
216  rtems_status_code sc;
217  rtems_interrupt_server_entry *e;
218  rtems_option trigger_options;
219
220  bsp_interrupt_lock();
221
222  e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
223  if (e != NULL) {
224    rtems_interrupt_server_action **link = &e->actions;
225    rtems_interrupt_server_action *c;
226
227    while ((c = *link) != NULL) {
228      if (c->handler == hd->handler && c->arg == hd->arg) {
229        break;
230      }
231
232      link = &c->next;
233    }
234
235    if (c != NULL) {
236      bool remove_last = e->actions->next == NULL;
237
238      if (remove_last) {
239        rtems_interrupt_handler_remove(
240          hd->vector,
241          bsp_interrupt_server_trigger,
242          e
243        );
244      }
245
246      *link = c->next;
247      free(c);
248
249      if (remove_last) {
250        free(e);
251      }
252
253      sc = RTEMS_SUCCESSFUL;
254    } else {
255      sc = RTEMS_UNSATISFIED;
256    }
257  } else {
258    sc = RTEMS_INVALID_ID;
259  }
260
261  bsp_interrupt_unlock();
262
263  hd->sc = sc;
264  rtems_event_transient_send(hd->task);
265}
266
267static rtems_status_code bsp_interrupt_server_call_helper(
268  rtems_interrupt_server_control *s,
269  rtems_vector_number vector,
270  rtems_option options,
271  rtems_interrupt_handler handler,
272  void *arg,
273  void (*helper)(void *)
274)
275{
276  bsp_interrupt_server_helper_data hd = {
277    .server = s,
278    .vector = vector,
279    .options = options,
280    .handler = handler,
281    .arg = arg,
282    .task = rtems_task_self()
283  };
284  rtems_interrupt_server_action a = {
285    .handler = helper,
286    .arg = &hd
287  };
288  rtems_interrupt_server_entry e = {
289    .server = s,
290    .vector = BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
291    .actions = &a
292  };
293
294  bsp_interrupt_server_trigger(&e);
295  rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
296
297  return hd.sc;
298}
299
300static rtems_interrupt_server_entry *bsp_interrupt_server_get_entry(
301  rtems_interrupt_server_control *s
302)
303{
304  rtems_interrupt_lock_context lock_context;
305  rtems_interrupt_server_entry *e;
306
307  rtems_interrupt_lock_acquire(&s->lock, &lock_context);
308
309  if (!rtems_chain_is_empty(&s->entries)) {
310    e = (rtems_interrupt_server_entry *)
311      rtems_chain_get_first_unprotected(&s->entries);
312    rtems_chain_set_off_chain(&e->node);
313  } else {
314    e = NULL;
315  }
316
317  rtems_interrupt_lock_release(&s->lock, &lock_context);
318
319  return e;
320}
321
322static void bsp_interrupt_server_task(rtems_task_argument arg)
323{
324  rtems_interrupt_server_control *s = (rtems_interrupt_server_control *) arg;
325
326  while (true) {
327    rtems_event_set events;
328    rtems_interrupt_server_entry *e;
329
330    rtems_event_system_receive(
331      RTEMS_EVENT_SYSTEM_SERVER,
332      RTEMS_EVENT_ALL | RTEMS_WAIT,
333      RTEMS_NO_TIMEOUT,
334      &events
335    );
336
337    while ((e = bsp_interrupt_server_get_entry(s)) != NULL) {
338      rtems_interrupt_server_action *action = e->actions;
339      rtems_vector_number vector = e->vector;
340
341      do {
342        rtems_interrupt_server_action *current = action;
343        action = action->next;
344        (*current->handler)(current->arg);
345      } while (action != NULL);
346
347      if (bsp_interrupt_is_valid_vector(vector)) {
348        bsp_interrupt_vector_enable(vector);
349      }
350    }
351  }
352}
353
354rtems_status_code rtems_interrupt_server_handler_install(
355  uint32_t server_index,
356  rtems_vector_number vector,
357  const char *info,
358  rtems_option options,
359  rtems_interrupt_handler handler,
360  void *arg
361)
362{
363  rtems_status_code sc;
364  rtems_interrupt_server_control *s;
365
366  s = bsp_interrupt_server_get_context(server_index, &sc);
367  if (s == NULL) {
368    return sc;
369  }
370
371  return bsp_interrupt_server_call_helper(
372    s,
373    vector,
374    options,
375    handler,
376    arg,
377    bsp_interrupt_server_install_helper
378  );
379}
380
381rtems_status_code rtems_interrupt_server_handler_remove(
382  uint32_t server_index,
383  rtems_vector_number vector,
384  rtems_interrupt_handler handler,
385  void *arg
386)
387{
388  rtems_status_code sc;
389  rtems_interrupt_server_control *s;
390
391  s = bsp_interrupt_server_get_context(server_index, &sc);
392  if (s == NULL) {
393    return sc;
394  }
395
396  return bsp_interrupt_server_call_helper(
397    s,
398    vector,
399    0,
400    handler,
401    arg,
402    bsp_interrupt_server_remove_helper
403  );
404}
405
406typedef struct {
407  rtems_interrupt_per_handler_routine routine;
408  void *arg;
409} bsp_interrupt_server_handler_iterate_helper_data;
410
411static void bsp_interrupt_server_handler_iterate_helper(void *arg)
412{
413  bsp_interrupt_server_helper_data *hd = arg;
414  bsp_interrupt_server_handler_iterate_helper_data *hihd = hd->arg;
415  rtems_status_code sc;
416  rtems_interrupt_server_entry *e;
417  rtems_option trigger_options;
418
419  bsp_interrupt_lock();
420
421  e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
422  if (e != NULL) {
423    rtems_interrupt_server_action **link = &e->actions;
424    rtems_interrupt_server_action *c;
425
426    while ((c = *link) != NULL) {
427      (*hihd->routine)(hihd->arg, NULL, trigger_options, c->handler, c->arg);
428      link = &c->next;
429    }
430
431    sc = RTEMS_SUCCESSFUL;
432  } else {
433    sc = RTEMS_UNSATISFIED;
434  }
435
436  bsp_interrupt_unlock();
437
438  hd->sc = sc;
439  rtems_event_transient_send(hd->task);
440}
441
442rtems_status_code rtems_interrupt_server_handler_iterate(
443  uint32_t server_index,
444  rtems_vector_number vector,
445  rtems_interrupt_per_handler_routine routine,
446  void *arg
447)
448{
449  rtems_status_code sc;
450  bsp_interrupt_server_handler_iterate_helper_data hihd;
451  rtems_interrupt_server_control *s;
452
453  s = bsp_interrupt_server_get_context(server_index, &sc);
454  if (s == NULL) {
455    return sc;
456  }
457
458  if (!bsp_interrupt_is_valid_vector(vector)) {
459    return RTEMS_INVALID_ID;
460  }
461
462  hihd.routine = routine;
463  hihd.arg = arg;
464  return bsp_interrupt_server_call_helper(
465    s,
466    vector,
467    0,
468    NULL,
469    &hihd,
470    bsp_interrupt_server_handler_iterate_helper
471  );
472}
473
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
554rtems_status_code rtems_interrupt_server_initialize(
555  rtems_task_priority priority,
556  size_t stack_size,
557  rtems_mode modes,
558  rtems_attribute attributes,
559  uint32_t *server_count
560)
561{
562  rtems_status_code sc;
563  rtems_interrupt_server_control *s;
564  uint32_t cpu_index;
565#if defined(RTEMS_SMP)
566  uint32_t cpu_count;
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)
595  cpu_count = rtems_scheduler_get_processor_maximum();
596
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,
609      priority,
610      stack_size,
611      modes,
612      attributes,
613      cpu_index
614    );
615    if (sc != RTEMS_SUCCESSFUL) {
616      goto done;
617    }
618
619    ++cpu_index;
620  }
621#endif
622
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  rtems_interrupt_lock_destroy(&s->lock);
686
687  if (s->destroy != NULL) {
688    (*s->destroy)(s);
689  }
690
691  sc = rtems_event_transient_send(hd->task);
692  _Assert(sc == RTEMS_SUCCESSFUL);
693  (void) sc;
694
695  rtems_task_exit();
696}
697
698rtems_status_code rtems_interrupt_server_delete(uint32_t server_index)
699{
700  rtems_status_code sc;
701  rtems_interrupt_server_control *s;
702
703  s = bsp_interrupt_server_get_context(server_index, &sc);
704  if (s == NULL) {
705    return sc;
706  }
707
708  bsp_interrupt_server_call_helper(
709    s,
710    BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
711    0,
712    NULL,
713    NULL,
714    bsp_interrupt_server_destroy_helper
715  );
716  return RTEMS_SUCCESSFUL;
717}
718
719static void bsp_interrupt_server_entry_initialize(
720  rtems_interrupt_server_entry *entry,
721  rtems_interrupt_server_control *s
722)
723{
724  rtems_chain_set_off_chain(&entry->node);
725  entry->server = s;
726  entry->vector = BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR;
727  entry->actions = NULL;
728}
729
730static void bsp_interrupt_server_action_prepend(
731  rtems_interrupt_server_entry  *entry,
732  rtems_interrupt_server_action *action,
733  rtems_interrupt_handler        handler,
734  void                          *arg
735)
736{
737  action->handler = handler;
738  action->arg = arg;
739  action->next = entry->actions;
740  entry->actions = action;
741}
742
743rtems_status_code rtems_interrupt_server_entry_initialize(
744  uint32_t                      server_index,
745  rtems_interrupt_server_entry *entry
746)
747{
748  rtems_status_code sc;
749  rtems_interrupt_server_control *s;
750
751  s = bsp_interrupt_server_get_context(server_index, &sc);
752  if (s == NULL) {
753    return sc;
754  }
755
756  bsp_interrupt_server_entry_initialize(entry, s);
757  return RTEMS_SUCCESSFUL;
758}
759
760void rtems_interrupt_server_action_prepend(
761  rtems_interrupt_server_entry  *entry,
762  rtems_interrupt_server_action *action,
763  rtems_interrupt_handler        handler,
764  void                          *arg
765)
766{
767  bsp_interrupt_server_action_prepend(entry, action, handler, arg);
768}
769
770void rtems_interrupt_server_entry_submit(
771  rtems_interrupt_server_entry *entry
772)
773{
774  bsp_interrupt_server_trigger(entry);
775}
776
777rtems_status_code rtems_interrupt_server_entry_move(
778  rtems_interrupt_server_entry *entry,
779  uint32_t                      destination_server_index
780)
781{
782  rtems_status_code sc;
783  rtems_interrupt_server_control *s;
784
785  s = bsp_interrupt_server_get_context(destination_server_index, &sc);
786  if (s == NULL) {
787    return sc;
788  }
789
790  entry->server = s;
791  return RTEMS_SUCCESSFUL;
792}
793
794static void bsp_interrupt_server_entry_synchronize_helper(void *arg)
795{
796  bsp_interrupt_server_helper_data *hd = arg;
797
798  rtems_event_transient_send(hd->task);
799}
800
801void rtems_interrupt_server_entry_destroy(
802  rtems_interrupt_server_entry *entry
803)
804{
805  rtems_interrupt_server_control *s;
806  rtems_interrupt_lock_context lock_context;
807
808  s = entry->server;
809  rtems_interrupt_lock_acquire(&s->lock, &lock_context);
810
811  if (!rtems_chain_is_node_off_chain(&entry->node)) {
812    rtems_chain_extract_unprotected(&entry->node);
813    rtems_chain_set_off_chain(&entry->node);
814  }
815
816  rtems_interrupt_lock_release(&s->lock, &lock_context);
817
818  bsp_interrupt_server_call_helper(
819    s,
820    BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
821    0,
822    NULL,
823    NULL,
824    bsp_interrupt_server_entry_synchronize_helper
825  );
826}
827
828rtems_status_code rtems_interrupt_server_request_initialize(
829  uint32_t                        server_index,
830  rtems_interrupt_server_request *request,
831  rtems_interrupt_handler         handler,
832  void                           *arg
833)
834{
835  rtems_status_code sc;
836  rtems_interrupt_server_control *s;
837
838  s = bsp_interrupt_server_get_context(server_index, &sc);
839  if (s == NULL) {
840    return sc;
841  }
842
843  bsp_interrupt_server_entry_initialize(&request->entry, s);
844  bsp_interrupt_server_action_prepend(
845    &request->entry,
846    &request->action,
847    handler,
848    arg
849  );
850  return RTEMS_SUCCESSFUL;
851}
852
853static void bsp_interrupt_server_handler_move_helper(void *arg)
854{
855  bsp_interrupt_server_helper_data *hd = arg;
856  bsp_interrupt_server_handler_iterate_helper_data *hihd = hd->arg;
857  rtems_interrupt_server_entry *e;
858  rtems_option trigger_options;
859
860  bsp_interrupt_lock();
861
862  e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
863  if (e != NULL) {
864    rtems_interrupt_lock_context lock_context;
865    rtems_interrupt_server_control *src = e->server;
866    rtems_interrupt_server_control *dst = hihd->arg;
867    bool pending;
868
869    /* The source server is only used in SMP configurations for the lock */
870    (void) src;
871
872    rtems_interrupt_lock_acquire(&src->lock, &lock_context);
873
874    pending = !rtems_chain_is_node_off_chain(&e->node);
875    if (pending) {
876      rtems_chain_extract_unprotected(&e->node);
877      rtems_chain_set_off_chain(&e->node);
878    }
879
880    rtems_interrupt_lock_release(&src->lock, &lock_context);
881
882    e->server = dst;
883
884    if (pending) {
885      bsp_interrupt_server_trigger(e);
886    }
887  }
888
889  bsp_interrupt_unlock();
890
891  rtems_event_transient_send(hd->task);
892}
893
894rtems_status_code rtems_interrupt_server_move(
895  uint32_t source_server_index,
896  rtems_vector_number vector,
897  uint32_t destination_server_index
898)
899{
900  rtems_status_code sc;
901  rtems_interrupt_server_control *src;
902  rtems_interrupt_server_control *dst;
903  bsp_interrupt_server_handler_iterate_helper_data hihd;
904
905  src = bsp_interrupt_server_get_context(source_server_index, &sc);
906  if (src == NULL) {
907    return sc;
908  }
909
910  dst = bsp_interrupt_server_get_context(destination_server_index, &sc);
911  if (dst == NULL) {
912    return sc;
913  }
914
915  if (!bsp_interrupt_is_valid_vector(vector)) {
916    return RTEMS_INVALID_ID;
917  }
918
919  hihd.arg = dst;
920  bsp_interrupt_server_call_helper(
921    src,
922    vector,
923    0,
924    NULL,
925    &hihd,
926    bsp_interrupt_server_handler_move_helper
927  );
928  return RTEMS_SUCCESSFUL;
929}
930
931static void bsp_interrupt_server_entry_suspend_helper(void *arg)
932{
933  bsp_interrupt_server_helper_data *hd = arg;
934  rtems_event_set events;
935
936  rtems_event_transient_send(hd->task);
937  rtems_event_system_receive(
938    RTEMS_EVENT_SYSTEM_SERVER_RESUME,
939    RTEMS_WAIT,
940    RTEMS_NO_TIMEOUT,
941    &events
942  );
943}
944
945rtems_status_code rtems_interrupt_server_suspend(uint32_t server_index)
946{
947  rtems_status_code sc;
948  rtems_interrupt_server_control *s;
949
950  s = bsp_interrupt_server_get_context(server_index, &sc);
951  if (s == NULL) {
952    return sc;
953  }
954
955  bsp_interrupt_server_call_helper(
956    s,
957    BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
958    0,
959    NULL,
960    NULL,
961    bsp_interrupt_server_entry_suspend_helper
962  );
963  return RTEMS_SUCCESSFUL;
964}
965
966rtems_status_code rtems_interrupt_server_resume(uint32_t server_index)
967{
968  rtems_status_code sc;
969  rtems_interrupt_server_control *s;
970
971  s = bsp_interrupt_server_get_context(server_index, &sc);
972  if (s == NULL) {
973    return sc;
974  }
975
976  rtems_event_system_send(s->server, RTEMS_EVENT_SYSTEM_SERVER_RESUME);
977  bsp_interrupt_server_call_helper(
978    s,
979    BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
980    0,
981    NULL,
982    NULL,
983    bsp_interrupt_server_entry_synchronize_helper
984  );
985  return RTEMS_SUCCESSFUL;
986}
987
988rtems_status_code rtems_interrupt_server_set_affinity(
989  uint32_t            server_index,
990  size_t              affinity_size,
991  const cpu_set_t    *affinity,
992  rtems_task_priority priority
993)
994{
995  rtems_status_code sc;
996  rtems_interrupt_server_control *s;
997  rtems_id scheduler;
998
999  s = bsp_interrupt_server_get_context(server_index, &sc);
1000  if (s == NULL) {
1001    return sc;
1002  }
1003
1004  sc = rtems_scheduler_ident_by_processor_set(
1005    affinity_size,
1006    affinity,
1007    &scheduler
1008  );
1009  if (sc != RTEMS_SUCCESSFUL) {
1010    return sc;
1011  }
1012
1013  sc = rtems_task_set_scheduler(s->server, scheduler, priority);
1014  if (sc != RTEMS_SUCCESSFUL) {
1015    return sc;
1016  }
1017
1018  return rtems_task_set_affinity(s->server, affinity_size, affinity);
1019}
Note: See TracBrowser for help on using the repository browser.