source: rtems/cpukit/score/src/threaddispatchdisablelevel.c @ ba25cc2

4.115
Last change on this file since ba25cc2 was ba25cc2, checked in by Sebastian Huber <sebastian.huber@…>, on 02/19/14 at 10:21:34

score: Add and use _Giant_Drop()

New test smptests/smpfatal03.

  • Property mode set to 100644
File size: 4.3 KB
Line 
1/**
2 * @file
3 *
4 * @brief Thread Dispatch Disable Functions
5 *
6 * @ingroup ScoreThread
7 */
8
9/*
10 *  COPYRIGHT (c) 1989-2011.
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.com/license/LICENSE.
16 */
17
18#include <rtems/score/threaddispatch.h>
19#include <rtems/score/assert.h>
20#include <rtems/score/sysstate.h>
21
22#define NO_OWNER_CPU 0xffffffffU
23
24typedef struct {
25  SMP_lock_Control lock;
26  uint32_t owner_cpu;
27  uint32_t nest_level;
28} Giant_Control;
29
30static Giant_Control _Giant = {
31  .lock = SMP_LOCK_INITIALIZER,
32  .owner_cpu = NO_OWNER_CPU,
33  .nest_level = 0
34};
35
36static void _Giant_Do_acquire( uint32_t self_cpu_index )
37{
38  Giant_Control *giant = &_Giant;
39
40  if ( giant->owner_cpu != self_cpu_index ) {
41    _SMP_lock_Acquire( &giant->lock );
42    giant->owner_cpu = self_cpu_index;
43    giant->nest_level = 1;
44  } else {
45    ++giant->nest_level;
46  }
47}
48
49static void _Giant_Do_release( void )
50{
51  Giant_Control *giant = &_Giant;
52
53  --giant->nest_level;
54  if ( giant->nest_level == 0 ) {
55    giant->owner_cpu = NO_OWNER_CPU;
56    _SMP_lock_Release( &giant->lock );
57  }
58}
59
60void _Giant_Drop( uint32_t self_cpu )
61{
62  Giant_Control *giant = &_Giant;
63
64  _Assert( _ISR_Get_level() != 0 );
65
66  if ( giant->owner_cpu == self_cpu ) {
67    giant->nest_level = 0;
68    giant->owner_cpu = NO_OWNER_CPU;
69    _SMP_lock_Release( &giant->lock );
70  }
71}
72
73uint32_t _Thread_Dispatch_increment_disable_level( void )
74{
75  ISR_Level isr_level;
76  uint32_t self_cpu_index;
77  uint32_t disable_level;
78  Per_CPU_Control *self_cpu;
79
80  _ISR_Disable_without_giant( isr_level );
81
82  /*
83   * We must obtain the processor ID after interrupts are disabled to prevent
84   * thread migration.
85   */
86  self_cpu_index = _SMP_Get_current_processor();
87
88  _Giant_Do_acquire( self_cpu_index );
89
90  self_cpu = _Per_CPU_Get_by_index( self_cpu_index );
91  disable_level = self_cpu->thread_dispatch_disable_level;
92  ++disable_level;
93  self_cpu->thread_dispatch_disable_level = disable_level;
94
95  _ISR_Enable_without_giant( isr_level );
96
97  return disable_level;
98}
99
100uint32_t _Thread_Dispatch_decrement_disable_level( void )
101{
102  ISR_Level isr_level;
103  uint32_t disable_level;
104  Per_CPU_Control *self_cpu;
105
106  _ISR_Disable_without_giant( isr_level );
107
108  self_cpu = _Per_CPU_Get();
109  disable_level = self_cpu->thread_dispatch_disable_level;
110  --disable_level;
111  self_cpu->thread_dispatch_disable_level = disable_level;
112
113  _Giant_Do_release();
114  _Assert( disable_level != 0 || _Giant.owner_cpu == NO_OWNER_CPU );
115
116  _ISR_Enable_without_giant( isr_level );
117
118  return disable_level;
119}
120
121
122/*
123 * Note this method is taking a heavy handed approach to
124 * setting the dispatch level. This may be optimized at a
125 * later timee, but it must be in such a way that the nesting
126 * level is decremented by the same number as the dispatch level.
127 * This approach is safest until we are sure the nested spinlock
128 * is successfully working with smp isr source code. 
129 */
130
131uint32_t _Thread_Dispatch_set_disable_level(uint32_t value)
132{
133  ISR_Level isr_level;
134  uint32_t disable_level;
135
136  _ISR_Disable_without_giant( isr_level );
137  disable_level = _Thread_Dispatch_disable_level;
138  _ISR_Enable_without_giant( isr_level );
139
140  /*
141   * If we need the dispatch level to go higher
142   * call increment method the desired number of times.
143   */
144
145  while ( value > disable_level ) {
146    disable_level = _Thread_Dispatch_increment_disable_level();
147  }
148
149  /*
150   * If we need the dispatch level to go lower
151   * call increment method the desired number of times.
152   */
153
154  while ( value < disable_level ) {
155    disable_level = _Thread_Dispatch_decrement_disable_level();
156  }
157
158  return value;
159}
160
161void _Giant_Acquire( void )
162{
163  ISR_Level isr_level;
164
165  _ISR_Disable_without_giant( isr_level );
166  _Assert( _Thread_Dispatch_disable_level != 0 );
167  _Giant_Do_acquire( _SMP_Get_current_processor() );
168  _ISR_Enable_without_giant( isr_level );
169}
170
171void _Giant_Release( void )
172{
173  ISR_Level isr_level;
174
175  _ISR_Disable_without_giant( isr_level );
176  _Assert( _Thread_Dispatch_disable_level != 0 );
177  _Giant_Do_release();
178  _ISR_Enable_without_giant( isr_level );
179}
180
181#if defined( RTEMS_DEBUG )
182void _Assert_Owner_of_giant( void )
183{
184  Giant_Control *giant = &_Giant;
185
186  _Assert(
187    giant->owner_cpu == _SMP_Get_current_processor()
188      || !_System_state_Is_up( _System_state_Get() )
189  );
190}
191#endif
Note: See TracBrowser for help on using the repository browser.