source: rtems/cpukit/score/include/rtems/score/userextimpl.h @ 6f6da82c

5
Last change on this file since 6f6da82c was 6f6da82c, checked in by Sebastian Huber <sebastian.huber@…>, on 01/26/17 at 10:06:50

score: Fix user extensions order

Use forward and reverse order for initial and dynamic extensions. This
is the behaviour documented in the C Users Guide. Change thread
terminate order to backward to be in line with the thread delete order.
Change fatal error order to forward to ensure that initial extensions
are called first due the peculiar execution context of fatal error
extensions, see _Terminate() documentation.

Update #2692.

  • Property mode set to 100644
File size: 8.1 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup ScoreUserExt
5 *
6 * @brief User Extension Handler API
7 */
8
9/*
10 *  COPYRIGHT (c) 1989-2009.
11 *  On-Line Applications Research Corporation (OAR).
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
15 *  http://www.rtems.org/license/LICENSE.
16 */
17
18#ifndef _RTEMS_SCORE_USEREXTIMPL_H
19#define _RTEMS_SCORE_USEREXTIMPL_H
20
21#include <rtems/score/userext.h>
22#include <rtems/score/isrlock.h>
23#include <rtems/score/chainimpl.h>
24#include <rtems/score/percpu.h>
25
26#ifdef __cplusplus
27extern "C" {
28#endif
29
30/**
31 * @defgroup ScoreUserExt User Extension Handler
32 *
33 * @ingroup Score
34 *
35 * @addtogroup ScoreUserExt
36 */
37/**@{**/
38
39/**
40 * @brief Chain iterator for dynamic user extensions.
41 *
42 * Since user extensions may delete or restart the executing thread, we must
43 * clean up registered iterators.
44 *
45 * @see _User_extensions_Iterate(), _User_extensions_Destroy_iterators() and
46 *   Thread_Control::last_user_extensions_iterator.
47 */
48typedef struct User_extensions_Iterator {
49  Chain_Iterator                   Iterator;
50  struct User_extensions_Iterator *previous;
51} User_extensions_Iterator;
52
53typedef struct {
54  /**
55   * @brief Active dynamically added user extensions.
56   */
57  Chain_Control Active;
58
59  /**
60   * @brief Chain iterator registration.
61   */
62  Chain_Iterator_registry Iterators;
63
64  /**
65   * @brief Lock to protect User_extensions_List::Active and
66   * User_extensions_List::Iterators.
67   */
68  ISR_LOCK_MEMBER( Lock )
69} User_extensions_List;
70
71/**
72 * @brief List of active extensions.
73 */
74extern User_extensions_List _User_extensions_List;
75
76/**
77 * @brief List of active task switch extensions.
78 */
79extern Chain_Control _User_extensions_Switches_list;
80
81/**
82 * @name Extension Maintainance
83 */
84/**@{**/
85
86void _User_extensions_Handler_initialization( void );
87
88void _User_extensions_Add_set(
89  User_extensions_Control *extension
90);
91
92RTEMS_INLINE_ROUTINE void _User_extensions_Add_API_set(
93  User_extensions_Control *extension
94)
95{
96  _User_extensions_Add_set( extension );
97}
98
99RTEMS_INLINE_ROUTINE void _User_extensions_Add_set_with_table(
100  User_extensions_Control     *extension,
101  const User_extensions_Table *extension_table
102)
103{
104  extension->Callouts = *extension_table;
105
106  _User_extensions_Add_set( extension );
107}
108
109void _User_extensions_Remove_set(
110  User_extensions_Control *extension
111);
112
113/**
114 * @brief User extension visitor.
115 *
116 * @param[in, out] executing The currently executing thread.
117 * @param[in, out] arg The argument passed to _User_extensions_Iterate().
118 * @param[in] callouts The current callouts.
119 */
120typedef void (*User_extensions_Visitor)(
121  Thread_Control              *executing,
122  void                        *arg,
123  const User_extensions_Table *callouts
124);
125
126typedef struct {
127  Thread_Control *created;
128  bool            ok;
129} User_extensions_Thread_create_context;
130
131void _User_extensions_Thread_create_visitor(
132  Thread_Control              *executing,
133  void                        *arg,
134  const User_extensions_Table *callouts
135);
136
137void _User_extensions_Thread_delete_visitor(
138  Thread_Control              *executing,
139  void                        *arg,
140  const User_extensions_Table *callouts
141);
142
143void _User_extensions_Thread_start_visitor(
144  Thread_Control              *executing,
145  void                        *arg,
146  const User_extensions_Table *callouts
147);
148
149void _User_extensions_Thread_restart_visitor(
150  Thread_Control              *executing,
151  void                        *arg,
152  const User_extensions_Table *callouts
153);
154
155void _User_extensions_Thread_begin_visitor(
156  Thread_Control              *executing,
157  void                        *arg,
158  const User_extensions_Table *callouts
159);
160
161void _User_extensions_Thread_exitted_visitor(
162  Thread_Control              *executing,
163  void                        *arg,
164  const User_extensions_Table *callouts
165);
166
167typedef struct {
168  Internal_errors_Source source;
169  Internal_errors_t      error;
170} User_extensions_Fatal_context;
171
172void _User_extensions_Fatal_visitor(
173  Thread_Control              *executing,
174  void                        *arg,
175  const User_extensions_Table *callouts
176);
177
178void _User_extensions_Thread_terminate_visitor(
179  Thread_Control              *executing,
180  void                        *arg,
181  const User_extensions_Table *callouts
182);
183
184/**
185 * @brief Iterates through all user extensions and calls the visitor for each.
186 *
187 * @param[in, out] arg The argument passed to the visitor.
188 * @param[in] visitor The visitor for each extension.
189 * @param[in] direction The iteration direction for dynamic extensions.
190 */
191void _User_extensions_Iterate(
192  void                     *arg,
193  User_extensions_Visitor   visitor,
194  Chain_Iterator_direction  direction
195);
196
197/** @} */
198
199/**
200 * @name Extension Callout Dispatcher
201 */
202/**@{**/
203
204static inline bool _User_extensions_Thread_create( Thread_Control *created )
205{
206  User_extensions_Thread_create_context ctx = { created, true };
207
208  _User_extensions_Iterate(
209    &ctx,
210    _User_extensions_Thread_create_visitor,
211    CHAIN_ITERATOR_FORWARD
212  );
213
214  return ctx.ok;
215}
216
217static inline void _User_extensions_Thread_delete( Thread_Control *deleted )
218{
219  _User_extensions_Iterate(
220    deleted,
221    _User_extensions_Thread_delete_visitor,
222    CHAIN_ITERATOR_BACKWARD
223  );
224}
225
226static inline void _User_extensions_Thread_start( Thread_Control *started )
227{
228  _User_extensions_Iterate(
229    started,
230    _User_extensions_Thread_start_visitor,
231    CHAIN_ITERATOR_FORWARD
232  );
233}
234
235static inline void _User_extensions_Thread_restart( Thread_Control *restarted )
236{
237  _User_extensions_Iterate(
238    restarted,
239    _User_extensions_Thread_restart_visitor,
240    CHAIN_ITERATOR_FORWARD
241  );
242}
243
244static inline void _User_extensions_Thread_begin( Thread_Control *executing )
245{
246  _User_extensions_Iterate(
247    executing,
248    _User_extensions_Thread_begin_visitor,
249    CHAIN_ITERATOR_FORWARD
250  );
251}
252
253static inline void _User_extensions_Thread_switch(
254  Thread_Control *executing,
255  Thread_Control *heir
256)
257{
258  const Chain_Control *chain = &_User_extensions_Switches_list;
259  const Chain_Node    *tail = _Chain_Immutable_tail( chain );
260  const Chain_Node    *node = _Chain_Immutable_first( chain );
261
262  if ( node != tail ) {
263    Per_CPU_Control *cpu_self;
264#if defined(RTEMS_SMP)
265    ISR_Level        level;
266#endif
267
268    cpu_self = _Per_CPU_Get();
269
270#if defined(RTEMS_SMP)
271    _ISR_Local_disable( level );
272#endif
273    _Per_CPU_Acquire( cpu_self );
274
275    while ( node != tail ) {
276      const User_extensions_Switch_control *extension =
277        (const User_extensions_Switch_control *) node;
278
279      (*extension->thread_switch)( executing, heir );
280
281      node = _Chain_Immutable_next( node );
282    }
283
284    _Per_CPU_Release( cpu_self );
285#if defined(RTEMS_SMP)
286    _ISR_Local_enable( level );
287#endif
288  }
289}
290
291static inline void _User_extensions_Thread_exitted( Thread_Control *executing )
292{
293  _User_extensions_Iterate(
294    executing,
295    _User_extensions_Thread_exitted_visitor,
296    CHAIN_ITERATOR_FORWARD
297  );
298}
299
300static inline void _User_extensions_Fatal(
301  Internal_errors_Source source,
302  Internal_errors_t      error
303)
304{
305  User_extensions_Fatal_context ctx = { source, error };
306
307  _User_extensions_Iterate(
308    &ctx,
309    _User_extensions_Fatal_visitor,
310    CHAIN_ITERATOR_FORWARD
311  );
312}
313
314static inline void _User_extensions_Thread_terminate(
315  Thread_Control *executing
316)
317{
318  _User_extensions_Iterate(
319    executing,
320    _User_extensions_Thread_terminate_visitor,
321    CHAIN_ITERATOR_BACKWARD
322  );
323}
324
325static inline void _User_extensions_Acquire( ISR_lock_Context *lock_context )
326{
327  _ISR_lock_ISR_disable_and_acquire(
328    &_User_extensions_List.Lock,
329    lock_context
330  );
331}
332
333static inline void _User_extensions_Release( ISR_lock_Context *lock_context )
334{
335  _ISR_lock_Release_and_ISR_enable(
336    &_User_extensions_List.Lock,
337    lock_context
338  );
339}
340
341static inline void _User_extensions_Destroy_iterators(
342  Thread_Control *the_thread
343)
344{
345  ISR_lock_Context          lock_context;
346  User_extensions_Iterator *iter;
347
348  _User_extensions_Acquire( &lock_context );
349
350  iter = the_thread->last_user_extensions_iterator;
351
352  while ( iter != NULL ) {
353    _Chain_Iterator_destroy( &iter->Iterator );
354    iter = iter->previous;
355  }
356
357  _User_extensions_Release( &lock_context );
358}
359
360/** @} */
361
362/** @} */
363
364#ifdef __cplusplus
365}
366#endif
367
368#endif
369/* end of include file */
Note: See TracBrowser for help on using the repository browser.