source: rtems/cpukit/include/rtems/score/userextimpl.h @ 26333f2a

5
Last change on this file since 26333f2a was 26333f2a, checked in by Sebastian Huber <sebastian.huber@…>, on 02/08/19 at 09:16:07

score: Fix _User_extensions_Thread_switch() (SMP)

We have to read the first node again once we obtained the lock since it
may have aready changed.

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