summaryrefslogtreecommitdiffstats
path: root/cpukit/score/src/threaddispatchdisablelevel.c
blob: 15e2f6d215bf6fa8321ce178366daec1009edd39 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 *  Thread Dispatch Disable Level Methods
 *
 *  COPYRIGHT (c) 1989-2011.
 *  On-Line Applications Research Corporation (OAR).
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 */

#include <rtems/system.h>
#include <rtems/score/apiext.h>
#include <rtems/score/context.h>
#include <rtems/score/interr.h>
#include <rtems/score/isr.h>
#include <rtems/score/object.h>
#include <rtems/score/priority.h>
#include <rtems/score/states.h>
#include <rtems/score/sysstate.h>
#include <rtems/score/thread.h>

void _Thread_Dispatch_initialization( void )
{
  _Thread_Dispatch_disable_level = 0; 
  _SMP_lock_spinlock_nested_Initialize(&_Thread_Dispatch_disable_level_lock);
  _Thread_Dispatch_set_disable_level( 1 );
}

bool _Thread_Dispatch_in_critical_section(void)
{
  if (  _Thread_Dispatch_disable_level == 0 )
   return false;

  return true;
}

uint32_t _Thread_Dispatch_get_disable_level(void)
{
  return _Thread_Dispatch_disable_level;
}

uint32_t _Thread_Dispatch_increment_disable_level(void)
{
  ISR_Level  isr_level;
  uint32_t   level;

  /*
   * Note: _SMP_lock_spinlock_nested_Obtain returns
   *       with ISR's disabled and the isr_level that
   *       should be restored after a short period.
   *
   * Here we obtain the lock and increment the 
   * Thread dispatch disable level while under the
   * protection of the isr being off.  After this
   * point it is safe to re-enable ISRs and allow
   * the dispatch disable lock to provide protection.
   */

  isr_level = _SMP_lock_spinlock_nested_Obtain(
    &_Thread_Dispatch_disable_level_lock
  );
  
  _Thread_Dispatch_disable_level++;
  level = _Thread_Dispatch_disable_level;

  _ISR_Enable_on_this_core(isr_level);
  return level;
}

uint32_t _Thread_Dispatch_decrement_disable_level(void)
{
  ISR_Level  isr_level;
  uint32_t   level;

  /*  First we must disable ISRs in order to protect
   *  accesses to the dispatch disable level.
   */
  _ISR_Disable_on_this_core( isr_level );

  _Thread_Dispatch_disable_level--;
  level = _Thread_Dispatch_disable_level;


  /* 
   * Note: _SMP_lock_spinlock_nested_Obtain returns with
   *        ISR's disabled and _SMP_lock_spinlock_nested_Release
   *        is responsable for re-enabling interrupts.
   */
  _SMP_lock_spinlock_nested_Release( 
    &_Thread_Dispatch_disable_level_lock,
    isr_level
  ); 

  return level;
}


/*
 * Note this method is taking a heavy handed approach to 
 * setting the dispatch level. This may be optimized at a 
 * later timee, but it must be in such a way that the nesting
 * level is decremented by the same number as the dispatch level.
 * This approach is safest until we are sure the nested spinlock
 * is successfully working with smp isr source code.  
 */

uint32_t _Thread_Dispatch_set_disable_level(uint32_t value)
{
  /*
   * If we need the dispatch level to go higher 
   * call increment method the desired number of times.
   */

  while ( value > _Thread_Dispatch_disable_level ) {
    _Thread_Dispatch_increment_disable_level();
  }

  /*
   * If we need the dispatch level to go lower
   * call increment method the desired number of times.
   */

  while ( value < _Thread_Dispatch_disable_level ) {
    _Thread_Dispatch_decrement_disable_level();
  }

  return value;
}