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

4.115
Last change on this file since aabfcd0 was aabfcd0, checked in by Sebastian Huber <sebastian.huber@…>, on 06/12/13 at 13:11:57

smp: Fix _Thread_Dispatch_decrement_disable_level

We must obtain the processor ID after interrupts are disabled since a
non-optimizing compiler may store the value on the stack and read it
back.

  • Property mode set to 100644
File size: 3.5 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/system.h>
19#include <rtems/score/apiext.h>
20#include <rtems/score/context.h>
21#include <rtems/score/interr.h>
22#include <rtems/score/isr.h>
23#include <rtems/score/object.h>
24#include <rtems/score/priority.h>
25#include <rtems/score/states.h>
26#include <rtems/score/sysstate.h>
27#include <rtems/score/threaddispatch.h>
28
29#define NO_OWNER_CPU (-1)
30
31void _Thread_Dispatch_initialization( void )
32{
33  Thread_Dispatch_disable_level_lock_control *level_lock =
34    &_Thread_Dispatch_disable_level_lock;
35
36  _Thread_Dispatch_disable_level = 0;
37  _SMP_lock_Initialize( &level_lock->lock );
38  level_lock->owner_cpu = NO_OWNER_CPU;
39  _Thread_Dispatch_set_disable_level( 1 );
40}
41
42bool _Thread_Dispatch_in_critical_section(void)
43{
44  if (  _Thread_Dispatch_disable_level == 0 )
45   return false;
46
47  return true;
48}
49
50uint32_t _Thread_Dispatch_get_disable_level(void)
51{
52  return _Thread_Dispatch_disable_level;
53}
54
55uint32_t _Thread_Dispatch_increment_disable_level( void )
56{
57  Thread_Dispatch_disable_level_lock_control *level_lock =
58    &_Thread_Dispatch_disable_level_lock;
59  int self_cpu;
60  ISR_Level isr_level;
61  uint32_t disable_level;
62
63  _ISR_Disable_on_this_core( isr_level );
64
65  /*
66   * We must obtain the processor ID after interrupts are disabled since a
67   * non-optimizing compiler may store the value on the stack and read it back.
68   */
69  self_cpu = bsp_smp_processor_id();
70
71  if ( level_lock->owner_cpu != self_cpu ) {
72    _SMP_lock_Acquire( &level_lock->lock );
73    level_lock->owner_cpu = self_cpu;
74    level_lock->nest_level = 1;
75  } else {
76    ++level_lock->nest_level;
77  }
78
79  disable_level = _Thread_Dispatch_disable_level;
80  ++disable_level;
81  _Thread_Dispatch_disable_level = disable_level;
82
83  _ISR_Enable_on_this_core( isr_level );
84
85  return disable_level;
86}
87
88uint32_t _Thread_Dispatch_decrement_disable_level( void )
89{
90  Thread_Dispatch_disable_level_lock_control *level_lock =
91    &_Thread_Dispatch_disable_level_lock;
92  ISR_Level isr_level;
93  uint32_t disable_level;
94
95  _ISR_Disable_on_this_core( isr_level );
96
97  disable_level = _Thread_Dispatch_disable_level;
98  --disable_level;
99  _Thread_Dispatch_disable_level = disable_level;
100
101  --level_lock->nest_level;
102  if ( level_lock->nest_level == 0 ) {
103    level_lock->owner_cpu = NO_OWNER_CPU;
104    _SMP_lock_Release( &level_lock->lock );
105  }
106
107  _ISR_Enable_on_this_core( isr_level );
108
109  return disable_level;
110}
111
112
113/*
114 * Note this method is taking a heavy handed approach to
115 * setting the dispatch level. This may be optimized at a
116 * later timee, but it must be in such a way that the nesting
117 * level is decremented by the same number as the dispatch level.
118 * This approach is safest until we are sure the nested spinlock
119 * is successfully working with smp isr source code. 
120 */
121
122uint32_t _Thread_Dispatch_set_disable_level(uint32_t value)
123{
124  /*
125   * If we need the dispatch level to go higher
126   * call increment method the desired number of times.
127   */
128
129  while ( value > _Thread_Dispatch_disable_level ) {
130    _Thread_Dispatch_increment_disable_level();
131  }
132
133  /*
134   * If we need the dispatch level to go lower
135   * call increment method the desired number of times.
136   */
137
138  while ( value < _Thread_Dispatch_disable_level ) {
139    _Thread_Dispatch_decrement_disable_level();
140  }
141
142  return value;
143}
Note: See TracBrowser for help on using the repository browser.