From 9b83a6654683d2f1f051533cdc41f39456303147 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 2 Oct 2012 16:13:00 +0200 Subject: score: Critical fix for thread dispatching The changes in _Thread_Dispatch() of commits dad36c52b8be5d7b46bc7af85655055db7208652 and d4dc7c8196355f08044e67a3f5c1e19485f17ff1 introduced a severe bug which destroys the real-time properties of RTEMS completely. Consider the following scenario. We have three tasks L (lowest priority), M (middle priority), and H (highest priority). Now let a thread dispatch from M to L happen. An interrupt occurs in _Thread_Dispatch() here: void _Thread_Dispatch( void ) { [...] post_switch: _ISR_Enable( level ); <-- INTERRUPT <-- AFTER INTERRUPT _Thread_Unnest_dispatch(); _API_extensions_Run_postswitch(); } The interrupt event makes task H ready. The interrupt code will see _Thread_Dispatch_disable_level > 0 and thus doesn't perform a _Thread_Dispatch(). Now we return to position "AFTER INTERRUPT". This means task L executes now although task H is ready! Task H will execute once someone calls _Thread_Dispatch(). --- cpukit/score/src/threaddispatch.c | 47 +++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) (limited to 'cpukit/score/src/threaddispatch.c') diff --git a/cpukit/score/src/threaddispatch.c b/cpukit/score/src/threaddispatch.c index 672a0999ab..8a77d1b4fe 100644 --- a/cpukit/score/src/threaddispatch.c +++ b/cpukit/score/src/threaddispatch.c @@ -55,8 +55,40 @@ void _Thread_Dispatch( void ) Thread_Control *heir; ISR_Level level; - _Thread_Disable_dispatch(); #if defined(RTEMS_SMP) + /* + * WARNING: The SMP sequence has severe defects regarding the real-time + * performance. + * + * Consider the following scenario. We have three tasks L (lowest + * priority), M (middle priority), and H (highest priority). Now let a + * thread dispatch from M to L happen. An interrupt occurs in + * _Thread_Dispatch() here: + * + * void _Thread_Dispatch( void ) + * { + * [...] + * + * post_switch: + * + * _ISR_Enable( level ); + * + * <-- INTERRUPT + * <-- AFTER INTERRUPT + * + * _Thread_Unnest_dispatch(); + * + * _API_extensions_Run_postswitch(); + * } + * + * The interrupt event makes task H ready. The interrupt code will see + * _Thread_Dispatch_disable_level > 0 and thus doesn't perform a + * _Thread_Dispatch(). Now we return to position "AFTER INTERRUPT". This + * means task L executes now although task H is ready! Task H will execute + * once someone calls _Thread_Dispatch(). + */ + _Thread_Disable_dispatch(); + /* * If necessary, send dispatch request to other cores. */ @@ -69,8 +101,10 @@ void _Thread_Dispatch( void ) executing = _Thread_Executing; _ISR_Disable( level ); while ( _Thread_Dispatch_necessary == true ) { - heir = _Thread_Heir; + #ifndef RTEMS_SMP + _Thread_Dispatch_set_disable_level( 1 ); + #endif _Thread_Dispatch_necessary = false; _Thread_Executing = heir; @@ -167,10 +201,15 @@ void _Thread_Dispatch( void ) } post_switch: + #ifndef RTEMS_SMP + _Thread_Dispatch_set_disable_level( 0 ); + #endif _ISR_Enable( level ); - _Thread_Unnest_dispatch(); - + #ifdef RTEMS_SMP + _Thread_Unnest_dispatch(); + #endif + _API_extensions_Run_postswitch(); } -- cgit v1.2.3