[PATCH] score: Critical fix for thread dispatching

Sebastian Huber sebastian.huber at embedded-brains.de
Tue Oct 2 14:13:00 UTC 2012


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 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/cpukit/score/src/threaddispatch.c b/cpukit/score/src/threaddispatch.c
index c8bc006..877a9c3 100644
--- a/cpukit/score/src/threaddispatch.c
+++ b/cpukit/score/src/threaddispatch.c
@@ -55,9 +55,41 @@ 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.
      */
     _SMP_Request_other_cores_to_dispatch();
@@ -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();
 }
-- 
1.7.7




More information about the devel mailing list