summaryrefslogtreecommitdiffstats
path: root/cpukit/score/src/threaddispatchdisablelevel.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-05-28 10:54:46 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-05-31 15:20:32 +0200
commite358088fc25fb3f62b30ae6a187f3e374f6a5ed7 (patch)
tree554337534e7212617c1523be0453c604ad120916 /cpukit/score/src/threaddispatchdisablelevel.c
parentscore: Mark as no return (diff)
downloadrtems-e358088fc25fb3f62b30ae6a187f3e374f6a5ed7.tar.bz2
smp: New SMP lock API
Move the SMP lock implementation to the CPU port. An optimal SMP lock implementation is highly architecture dependent. For example the memory models may be fundamentally different. The new SMP lock API has a flaw. It does not provide the ability to use a local context for acquire and release pairs. Such a context is necessary to implement for example the Mellor-Crummey and Scott (MCS) locks. The SMP lock is currently used in _Thread_Disable_dispatch() and _Thread_Enable_dispatch() and makes them to a giant lock acquire and release. Since these functions do not pass state information via a local context there is currently no use case for such a feature.
Diffstat (limited to 'cpukit/score/src/threaddispatchdisablelevel.c')
-rw-r--r--cpukit/score/src/threaddispatchdisablelevel.c86
1 files changed, 44 insertions, 42 deletions
diff --git a/cpukit/score/src/threaddispatchdisablelevel.c b/cpukit/score/src/threaddispatchdisablelevel.c
index 36be088663..b1930909bb 100644
--- a/cpukit/score/src/threaddispatchdisablelevel.c
+++ b/cpukit/score/src/threaddispatchdisablelevel.c
@@ -26,10 +26,16 @@
#include <rtems/score/sysstate.h>
#include <rtems/score/thread.h>
+#define NO_OWNER_CPU (-1)
+
void _Thread_Dispatch_initialization( void )
{
- _Thread_Dispatch_disable_level = 0;
- _SMP_lock_spinlock_nested_Initialize(&_Thread_Dispatch_disable_level_lock);
+ Thread_Dispatch_disable_level_lock_control *level_lock =
+ &_Thread_Dispatch_disable_level_lock;
+
+ _Thread_Dispatch_disable_level = 0;
+ _SMP_lock_Initialize( &level_lock->lock );
+ level_lock->owner_cpu = NO_OWNER_CPU;
_Thread_Dispatch_set_disable_level( 1 );
}
@@ -46,59 +52,55 @@ uint32_t _Thread_Dispatch_get_disable_level(void)
return _Thread_Dispatch_disable_level;
}
-uint32_t _Thread_Dispatch_increment_disable_level(void)
+uint32_t _Thread_Dispatch_increment_disable_level( void )
{
- ISR_Level isr_level;
- uint32_t level;
+ Thread_Dispatch_disable_level_lock_control *level_lock =
+ &_Thread_Dispatch_disable_level_lock;
+ int self_cpu = bsp_smp_processor_id();
+ ISR_Level isr_level;
+ uint32_t disable_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_Disable_on_this_core( isr_level );
- isr_level = _SMP_lock_spinlock_nested_Obtain(
- &_Thread_Dispatch_disable_level_lock
- );
-
- _Thread_Dispatch_disable_level++;
- level = _Thread_Dispatch_disable_level;
+ 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;
+ }
- _ISR_Enable_on_this_core(isr_level);
- return level;
+ disable_level = _Thread_Dispatch_disable_level;
+ ++disable_level;
+ _Thread_Dispatch_disable_level = disable_level;
+
+ _ISR_Enable_on_this_core( isr_level );
+
+ return disable_level;
}
-uint32_t _Thread_Dispatch_decrement_disable_level(void)
+uint32_t _Thread_Dispatch_decrement_disable_level( void )
{
- ISR_Level isr_level;
- uint32_t level;
+ Thread_Dispatch_disable_level_lock_control *level_lock =
+ &_Thread_Dispatch_disable_level_lock;
+ ISR_Level isr_level;
+ uint32_t disable_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;
+ --level_lock->nest_level;
+ if ( level_lock->nest_level == 0 ) {
+ level_lock->owner_cpu = NO_OWNER_CPU;
+ _SMP_lock_Release( &level_lock->lock );
+ }
+ disable_level = _Thread_Dispatch_disable_level;
+ --disable_level;
+ _Thread_Dispatch_disable_level = 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
- );
+ _ISR_Enable_on_this_core( isr_level );
- return level;
+ return disable_level;
}