summaryrefslogtreecommitdiffstats
path: root/cpukit/score/src/threaddispatchdisablelevel.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/score/src/threaddispatchdisablelevel.c')
-rw-r--r--cpukit/score/src/threaddispatchdisablelevel.c119
1 files changed, 76 insertions, 43 deletions
diff --git a/cpukit/score/src/threaddispatchdisablelevel.c b/cpukit/score/src/threaddispatchdisablelevel.c
index 816959a1ca..50af3674da 100644
--- a/cpukit/score/src/threaddispatchdisablelevel.c
+++ b/cpukit/score/src/threaddispatchdisablelevel.c
@@ -15,59 +15,69 @@
* 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/priority.h>
#include <rtems/score/threaddispatch.h>
+#include <rtems/score/assert.h>
#define NO_OWNER_CPU 0xffffffffU
-void _Thread_Dispatch_initialization( void )
+typedef struct {
+ SMP_lock_Control lock;
+ uint32_t owner_cpu;
+ uint32_t nest_level;
+} Giant_Control;
+
+static Giant_Control _Giant = {
+ .lock = SMP_LOCK_INITIALIZER,
+ .owner_cpu = NO_OWNER_CPU,
+ .nest_level = 0
+};
+
+static void _Giant_Do_acquire( uint32_t self_cpu_index )
{
- Thread_Dispatch_disable_level_lock_control *level_lock =
- &_Thread_Dispatch_disable_level_lock;
+ Giant_Control *giant = &_Giant;
- _Thread_Dispatch_disable_level = 0;
- _SMP_lock_Initialize( &level_lock->lock );
- level_lock->owner_cpu = NO_OWNER_CPU;
- _Thread_Dispatch_set_disable_level( 1 );
+ if ( giant->owner_cpu != self_cpu_index ) {
+ _SMP_lock_Acquire( &giant->lock );
+ giant->owner_cpu = self_cpu_index;
+ giant->nest_level = 1;
+ } else {
+ ++giant->nest_level;
+ }
}
-uint32_t _Thread_Dispatch_get_disable_level(void)
+static void _Giant_Do_release( void )
{
- return _Thread_Dispatch_disable_level;
+ Giant_Control *giant = &_Giant;
+
+ --giant->nest_level;
+ if ( giant->nest_level == 0 ) {
+ giant->owner_cpu = NO_OWNER_CPU;
+ _SMP_lock_Release( &giant->lock );
+ }
}
uint32_t _Thread_Dispatch_increment_disable_level( void )
{
- Thread_Dispatch_disable_level_lock_control *level_lock =
- &_Thread_Dispatch_disable_level_lock;
+ Giant_Control *giant = &_Giant;
ISR_Level isr_level;
- uint32_t self_cpu;
+ uint32_t self_cpu_index;
uint32_t disable_level;
+ Per_CPU_Control *self_cpu;
_ISR_Disable( isr_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.
+ * We must obtain the processor ID after interrupts are disabled to prevent
+ * thread migration.
*/
- self_cpu = _SMP_Get_current_processor();
+ self_cpu_index = _SMP_Get_current_processor();
- if ( level_lock->owner_cpu != self_cpu ) {
- _SMP_lock_Acquire( &level_lock->lock );
- level_lock->owner_cpu = self_cpu;
- level_lock->nest_level = 1;
- } else {
- ++level_lock->nest_level;
- }
+ _Giant_Do_acquire( self_cpu_index );
- disable_level = _Thread_Dispatch_disable_level;
+ self_cpu = _Per_CPU_Get_by_index( self_cpu_index );
+ disable_level = self_cpu->thread_dispatch_disable_level;
++disable_level;
- _Thread_Dispatch_disable_level = disable_level;
+ self_cpu->thread_dispatch_disable_level = disable_level;
_ISR_Enable( isr_level );
@@ -76,22 +86,18 @@ uint32_t _Thread_Dispatch_increment_disable_level( void )
uint32_t _Thread_Dispatch_decrement_disable_level( void )
{
- Thread_Dispatch_disable_level_lock_control *level_lock =
- &_Thread_Dispatch_disable_level_lock;
ISR_Level isr_level;
uint32_t disable_level;
+ Per_CPU_Control *self_cpu;
_ISR_Disable( isr_level );
- disable_level = _Thread_Dispatch_disable_level;
+ self_cpu = _Per_CPU_Get();
+ disable_level = self_cpu->thread_dispatch_disable_level;
--disable_level;
- _Thread_Dispatch_disable_level = disable_level;
+ self_cpu->thread_dispatch_disable_level = disable_level;
- --level_lock->nest_level;
- if ( level_lock->nest_level == 0 ) {
- level_lock->owner_cpu = NO_OWNER_CPU;
- _SMP_lock_Release( &level_lock->lock );
- }
+ _Giant_Do_release();
_ISR_Enable( isr_level );
@@ -110,13 +116,20 @@ uint32_t _Thread_Dispatch_decrement_disable_level( void )
uint32_t _Thread_Dispatch_set_disable_level(uint32_t value)
{
+ ISR_Level isr_level;
+ uint32_t disable_level;
+
+ _ISR_Disable( isr_level );
+ disable_level = _Thread_Dispatch_disable_level;
+ _ISR_Enable( isr_level );
+
/*
* 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();
+ while ( value > disable_level ) {
+ disable_level = _Thread_Dispatch_increment_disable_level();
}
/*
@@ -124,9 +137,29 @@ uint32_t _Thread_Dispatch_set_disable_level(uint32_t value)
* call increment method the desired number of times.
*/
- while ( value < _Thread_Dispatch_disable_level ) {
- _Thread_Dispatch_decrement_disable_level();
+ while ( value < disable_level ) {
+ disable_level = _Thread_Dispatch_decrement_disable_level();
}
return value;
}
+
+void _Giant_Acquire( void )
+{
+ ISR_Level isr_level;
+
+ _ISR_Disable( isr_level );
+ _Assert( _Thread_Dispatch_disable_level != 0 );
+ _Giant_Do_acquire( _SMP_Get_current_processor() );
+ _ISR_Enable( isr_level );
+}
+
+void _Giant_Release( void )
+{
+ ISR_Level isr_level;
+
+ _ISR_Disable( isr_level );
+ _Assert( _Thread_Dispatch_disable_level != 0 );
+ _Giant_Do_release();
+ _ISR_Enable( isr_level );
+}