source: rtems/cpukit/score/src/userextiterate.c @ 99fc1d1d

5
Last change on this file since 99fc1d1d was 709f38a, checked in by Sebastian Huber <sebastian.huber@…>, on 04/13/16 at 04:48:58

score: Use chain iterator for user extensions

Add a lock and use a chain iterator for safe iteration during concurrent
user extension addition and removal.

Ensure that dynamically added thread delete and fatal extensions are
called in reverse order.

Update #2555.
Update #2692.

  • Property mode set to 100644
File size: 5.2 KB
Line 
1/**
2 * @file
3 *
4 * @brief User Extension Iteration Helpers
5 *
6 * @ingroup ScoreUserExt
7 */
8
9/*
10 * Copyright (c) 2012, 2016 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Dornierstr. 4
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23#if HAVE_CONFIG_H
24  #include "config.h"
25#endif
26
27#include <rtems/config.h>
28#include <rtems/score/userextimpl.h>
29
30#include <pthread.h>
31
32User_extensions_List _User_extensions_List = {
33  CHAIN_INITIALIZER_EMPTY( _User_extensions_List.Active ),
34  CHAIN_ITERATOR_REGISTRY_INITIALIZER( _User_extensions_List.Iterators )
35#if defined(RTEMS_SMP)
36  ,
37  ISR_LOCK_INITIALIZER( "User Extensions List" )
38#endif
39};
40
41void _User_extensions_Thread_create_visitor(
42  Thread_Control              *executing,
43  void                        *arg,
44  const User_extensions_Table *callouts
45)
46{
47  User_extensions_thread_create_extension callout = callouts->thread_create;
48
49  if ( callout != NULL ) {
50    User_extensions_Thread_create_context *ctx = arg;
51
52    ctx->ok = ctx->ok && (*callout)( executing, ctx->created );
53  }
54}
55
56void _User_extensions_Thread_delete_visitor(
57  Thread_Control              *executing,
58  void                        *arg,
59  const User_extensions_Table *callouts
60)
61{
62  User_extensions_thread_delete_extension callout = callouts->thread_delete;
63
64  if ( callout != NULL ) {
65    (*callout)( executing, arg );
66  }
67}
68
69void _User_extensions_Thread_start_visitor(
70  Thread_Control              *executing,
71  void                        *arg,
72  const User_extensions_Table *callouts
73)
74{
75  User_extensions_thread_start_extension callout = callouts->thread_start;
76
77  if ( callout != NULL ) {
78    (*callout)( executing, arg );
79  }
80}
81
82void _User_extensions_Thread_restart_visitor(
83  Thread_Control              *executing,
84  void                        *arg,
85  const User_extensions_Table *callouts
86)
87{
88  User_extensions_thread_restart_extension callout = callouts->thread_restart;
89
90  if ( callout != NULL ) {
91    (*callout)( executing, arg );
92  }
93}
94
95void _User_extensions_Thread_begin_visitor(
96  Thread_Control              *executing,
97  void                        *arg,
98  const User_extensions_Table *callouts
99)
100{
101  User_extensions_thread_begin_extension callout = callouts->thread_begin;
102
103  if ( callout != NULL ) {
104    (*callout)( executing );
105  }
106}
107
108void _User_extensions_Thread_exitted_visitor(
109  Thread_Control              *executing,
110  void                        *arg,
111  const User_extensions_Table *callouts
112)
113{
114  User_extensions_thread_exitted_extension callout = callouts->thread_exitted;
115
116  if ( callout != NULL ) {
117    (*callout)( executing );
118  }
119}
120
121void _User_extensions_Fatal_visitor(
122  Thread_Control              *executing,
123  void                        *arg,
124  const User_extensions_Table *callouts
125)
126{
127  User_extensions_fatal_extension callout = callouts->fatal;
128
129  if ( callout != NULL ) {
130    const User_extensions_Fatal_context *ctx = arg;
131
132    (*callout)( ctx->source, ctx->is_internal, ctx->error );
133  }
134}
135
136void _User_extensions_Thread_terminate_visitor(
137  Thread_Control              *executing,
138  void                        *arg,
139  const User_extensions_Table *callouts
140)
141{
142  User_extensions_thread_terminate_extension callout =
143    callouts->thread_terminate;
144
145  if ( callout != NULL ) {
146    (*callout)( executing );
147  }
148}
149
150void _User_extensions_Iterate(
151  void                     *arg,
152  User_extensions_Visitor   visitor,
153  Chain_Iterator_direction  direction
154)
155{
156  Thread_Control              *executing;
157  const User_extensions_Table *callouts_current;
158  const User_extensions_Table *callouts_end;
159  const Chain_Node            *end;
160  Chain_Node                  *node;
161  User_extensions_Iterator     iter;
162  ISR_lock_Context             lock_context;
163
164  executing = _Thread_Get_executing();
165
166  callouts_current = rtems_configuration_get_user_extension_table();
167  callouts_end = callouts_current
168    + rtems_configuration_get_number_of_initial_extensions();
169
170  while ( callouts_current != callouts_end ) {
171    (*visitor)( executing, arg, callouts_current );
172
173    ++callouts_current;
174  }
175
176  if ( direction == CHAIN_ITERATOR_FORWARD ) {
177    end = _Chain_Immutable_tail( &_User_extensions_List.Active );
178  } else {
179    end = _Chain_Immutable_head( &_User_extensions_List.Active );
180  }
181
182  _User_extensions_Acquire( &lock_context );
183
184  _Chain_Iterator_initialize(
185    &_User_extensions_List.Active,
186    &_User_extensions_List.Iterators,
187    &iter.Iterator,
188    direction
189  );
190
191  if ( executing != NULL ) {
192    iter.previous = executing->last_user_extensions_iterator;
193    executing->last_user_extensions_iterator = &iter;
194  }
195
196  while ( ( node = _Chain_Iterator_next( &iter.Iterator ) ) != end ) {
197    const User_extensions_Control *extension;
198
199    _Chain_Iterator_set_position( &iter.Iterator, node );
200
201    _User_extensions_Release( &lock_context );
202
203    extension = (const User_extensions_Control *) node;
204    ( *visitor )( executing, arg, &extension->Callouts );
205
206    _User_extensions_Acquire( &lock_context );
207  }
208
209  if ( executing != NULL ) {
210    executing->last_user_extensions_iterator = iter.previous;
211  }
212
213  _Chain_Iterator_destroy( &iter.Iterator );
214
215  _User_extensions_Release( &lock_context );
216}
Note: See TracBrowser for help on using the repository browser.