summaryrefslogtreecommitdiffstats
path: root/cpukit/score/src/threaddispatch.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2012-10-02 16:13:00 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2012-10-07 14:40:49 +0200
commit9b83a6654683d2f1f051533cdc41f39456303147 (patch)
tree96aeb75f7744b8e92e25494744766e2f534a1cbf /cpukit/score/src/threaddispatch.c
parentmghttpd: Requires POSIX to build server and tests (diff)
downloadrtems-9b83a6654683d2f1f051533cdc41f39456303147.tar.bz2
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().
Diffstat (limited to 'cpukit/score/src/threaddispatch.c')
-rw-r--r--cpukit/score/src/threaddispatch.c47
1 files changed, 43 insertions, 4 deletions
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,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();
}