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

4.115
Last change on this file since bf30999 was bf30999, checked in by Sebastian Huber <sebastian.huber@…>, on 08/23/13 at 14:15:50

smp: Add and use _Assert_Owner_of_giant()

Add and use _ISR_Disable_without_giant() and
_ISR_Enable_without_giant() if RTEMS_SMP is defined.

On single processor systems the ISR disable/enable was the big hammer
which ensured system-wide mutual exclusion. On SMP configurations this
no longer works since other processors do not care about disabled
interrupts on this processor and continue to execute freely.

On SMP in addition to ISR disable/enable an SMP lock must be used.
Currently we have only the Giant lock so we can check easily that ISR
disable/enable is used only in the right context.

  • Property mode set to 100644
File size: 4.1 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
60uint32_t _Thread_Dispatch_increment_disable_level( void )
61{
62  ISR_Level isr_level;
63  uint32_t self_cpu_index;
64  uint32_t disable_level;
65  Per_CPU_Control *self_cpu;
66
67  _ISR_Disable_without_giant( isr_level );
68
69  /*
70   * We must obtain the processor ID after interrupts are disabled to prevent
71   * thread migration.
72   */
73  self_cpu_index = _SMP_Get_current_processor();
74
75  _Giant_Do_acquire( self_cpu_index );
76
77  self_cpu = _Per_CPU_Get_by_index( self_cpu_index );
78  disable_level = self_cpu->thread_dispatch_disable_level;
79  ++disable_level;
80  self_cpu->thread_dispatch_disable_level = disable_level;
81
82  _ISR_Enable_without_giant( isr_level );
83
84  return disable_level;
85}
86
87uint32_t _Thread_Dispatch_decrement_disable_level( void )
88{
89  ISR_Level isr_level;
90  uint32_t disable_level;
91  Per_CPU_Control *self_cpu;
92
93  _ISR_Disable_without_giant( isr_level );
94
95  self_cpu = _Per_CPU_Get();
96  disable_level = self_cpu->thread_dispatch_disable_level;
97  --disable_level;
98  self_cpu->thread_dispatch_disable_level = disable_level;
99
100  _Giant_Do_release();
101  _Assert( disable_level != 0 || _Giant.owner_cpu == NO_OWNER_CPU );
102
103  _ISR_Enable_without_giant( isr_level );
104
105  return disable_level;
106}
107
108
109/*
110 * Note this method is taking a heavy handed approach to
111 * setting the dispatch level. This may be optimized at a
112 * later timee, but it must be in such a way that the nesting
113 * level is decremented by the same number as the dispatch level.
114 * This approach is safest until we are sure the nested spinlock
115 * is successfully working with smp isr source code. 
116 */
117
118uint32_t _Thread_Dispatch_set_disable_level(uint32_t value)
119{
120  ISR_Level isr_level;
121  uint32_t disable_level;
122
123  _ISR_Disable_without_giant( isr_level );
124  disable_level = _Thread_Dispatch_disable_level;
125  _ISR_Enable_without_giant( isr_level );
126
127  /*
128   * If we need the dispatch level to go higher
129   * call increment method the desired number of times.
130   */
131
132  while ( value > disable_level ) {
133    disable_level = _Thread_Dispatch_increment_disable_level();
134  }
135
136  /*
137   * If we need the dispatch level to go lower
138   * call increment method the desired number of times.
139   */
140
141  while ( value < disable_level ) {
142    disable_level = _Thread_Dispatch_decrement_disable_level();
143  }
144
145  return value;
146}
147
148void _Giant_Acquire( void )
149{
150  ISR_Level isr_level;
151
152  _ISR_Disable_without_giant( isr_level );
153  _Assert( _Thread_Dispatch_disable_level != 0 );
154  _Giant_Do_acquire( _SMP_Get_current_processor() );
155  _ISR_Enable_without_giant( isr_level );
156}
157
158void _Giant_Release( void )
159{
160  ISR_Level isr_level;
161
162  _ISR_Disable_without_giant( isr_level );
163  _Assert( _Thread_Dispatch_disable_level != 0 );
164  _Giant_Do_release();
165  _ISR_Enable_without_giant( isr_level );
166}
167
168#if defined( RTEMS_DEBUG )
169void _Assert_Owner_of_giant( void )
170{
171  Giant_Control *giant = &_Giant;
172
173  _Assert(
174    giant->owner_cpu == _SMP_Get_current_processor()
175      || !_System_state_Is_up( _System_state_Get() )
176  );
177}
178#endif
Note: See TracBrowser for help on using the repository browser.