summaryrefslogtreecommitdiffstats
path: root/cpukit/score/src
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2014-06-12 14:37:57 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2014-06-12 16:13:26 +0200
commit701dd96f598bd58a41884795ba5bf0b5da337d78 (patch)
tree2d8374400a2622c19ad5215e0d1e150eebda1396 /cpukit/score/src
parentbsp/realview-pbx-a9: Fix SMP startup (diff)
downloadrtems-701dd96f598bd58a41884795ba5bf0b5da337d78.tar.bz2
score: PR2181: Add _Thread_Yield()
The _Scheduler_Yield() was called by the executing thread with thread dispatching disabled and interrupts enabled. The rtems_task_suspend() is explicitly allowed in ISRs: http://rtems.org/onlinedocs/doc-current/share/rtems/html/c_user/Interrupt-Manager-Directives-Allowed-from-an-ISR.html#Interrupt-Manager-Directives-Allowed-from-an-ISR Unlike the other scheduler operations the locking was performed inside the operation. This lead to the following race condition. Suppose a ISR suspends the executing thread right before the yield scheduler operation. Now the executing thread is not longer in the set of ready threads. The typical scheduler operations did not check the thread state and will now extract the thread again and enqueue it. This corrupted data structures. Add _Thread_Yield() and do the scheduler yield operation with interrupts disabled. This has a negligible effect on the interrupt latency.
Diffstat (limited to 'cpukit/score/src')
-rw-r--r--cpukit/score/src/schedulerdefaulttick.c4
-rw-r--r--cpukit/score/src/scheduleredfyield.c7
-rw-r--r--cpukit/score/src/schedulerprioritysmp.c14
-rw-r--r--cpukit/score/src/schedulerpriorityyield.c23
-rw-r--r--cpukit/score/src/schedulersimplesmp.c14
-rw-r--r--cpukit/score/src/schedulersimpleyield.c15
-rw-r--r--cpukit/score/src/threadyield.c41
7 files changed, 70 insertions, 48 deletions
diff --git a/cpukit/score/src/schedulerdefaulttick.c b/cpukit/score/src/schedulerdefaulttick.c
index 98cd05e1c0..db67ca1508 100644
--- a/cpukit/score/src/schedulerdefaulttick.c
+++ b/cpukit/score/src/schedulerdefaulttick.c
@@ -29,6 +29,8 @@ void _Scheduler_default_Tick(
Thread_Control *executing
)
{
+ (void) scheduler;
+
#ifdef __RTEMS_USE_TICKS_FOR_STATISTICS__
/*
* Increment the number of ticks this thread has been executing
@@ -69,7 +71,7 @@ void _Scheduler_default_Tick(
* currently executing thread is placed at the rear of the
* FIFO for this priority and a new heir is selected.
*/
- _Scheduler_Yield( scheduler, executing );
+ _Thread_Yield( executing );
executing->cpu_time_budget =
rtems_configuration_get_ticks_per_timeslice();
}
diff --git a/cpukit/score/src/scheduleredfyield.c b/cpukit/score/src/scheduleredfyield.c
index 9eb07825fe..d43448becf 100644
--- a/cpukit/score/src/scheduleredfyield.c
+++ b/cpukit/score/src/scheduleredfyield.c
@@ -29,9 +29,6 @@ void _Scheduler_EDF_Yield(
Scheduler_EDF_Context *context =
_Scheduler_EDF_Get_context( scheduler );
Scheduler_EDF_Node *node = _Scheduler_EDF_Node_get( the_thread );
- ISR_Level level;
-
- _ISR_Disable( level );
/*
* The RBTree has more than one node, enqueue behind the tasks
@@ -40,9 +37,5 @@ void _Scheduler_EDF_Yield(
_RBTree_Extract( &context->Ready, &node->Node );
_RBTree_Insert( &context->Ready, &node->Node );
- _ISR_Flash( level );
-
_Scheduler_EDF_Schedule_body( scheduler, the_thread, false );
-
- _ISR_Enable( level );
}
diff --git a/cpukit/score/src/schedulerprioritysmp.c b/cpukit/score/src/schedulerprioritysmp.c
index 96b1689f37..bcbd26df3f 100644
--- a/cpukit/score/src/schedulerprioritysmp.c
+++ b/cpukit/score/src/schedulerprioritysmp.c
@@ -237,12 +237,12 @@ void _Scheduler_priority_SMP_Yield(
)
{
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
- ISR_Level level;
- _ISR_Disable( level );
-
- _Scheduler_SMP_Extract_from_scheduled( thread );
- _Scheduler_priority_SMP_Enqueue_scheduled_fifo( context, thread );
-
- _ISR_Enable( level );
+ return _Scheduler_SMP_Yield(
+ context,
+ thread,
+ _Scheduler_priority_SMP_Extract_from_ready,
+ _Scheduler_priority_SMP_Enqueue_fifo,
+ _Scheduler_priority_SMP_Enqueue_scheduled_fifo
+ );
}
diff --git a/cpukit/score/src/schedulerpriorityyield.c b/cpukit/score/src/schedulerpriorityyield.c
index f2aeada660..60bab3983e 100644
--- a/cpukit/score/src/schedulerpriorityyield.c
+++ b/cpukit/score/src/schedulerpriorityyield.c
@@ -19,7 +19,6 @@
#endif
#include <rtems/score/schedulerpriorityimpl.h>
-#include <rtems/score/isr.h>
#include <rtems/score/threadimpl.h>
void _Scheduler_priority_Yield(
@@ -29,23 +28,19 @@ void _Scheduler_priority_Yield(
{
Scheduler_priority_Node *node = _Scheduler_priority_Node_get( the_thread );
Chain_Control *ready_chain = node->Ready_queue.ready_chain;
- ISR_Level level;
(void) scheduler;
- _ISR_Disable( level );
- if ( !_Chain_Has_only_one_node( ready_chain ) ) {
- _Chain_Extract_unprotected( &the_thread->Object.Node );
- _Chain_Append_unprotected( ready_chain, &the_thread->Object.Node );
+ if ( !_Chain_Has_only_one_node( ready_chain ) ) {
+ _Chain_Extract_unprotected( &the_thread->Object.Node );
+ _Chain_Append_unprotected( ready_chain, &the_thread->Object.Node );
- _ISR_Flash( level );
-
- if ( _Thread_Is_heir( the_thread ) )
- _Thread_Heir = (Thread_Control *) _Chain_First( ready_chain );
- _Thread_Dispatch_necessary = true;
+ if ( _Thread_Is_heir( the_thread ) ) {
+ _Thread_Heir = (Thread_Control *) _Chain_First( ready_chain );
}
- else if ( !_Thread_Is_heir( the_thread ) )
- _Thread_Dispatch_necessary = true;
- _ISR_Enable( level );
+ _Thread_Dispatch_necessary = true;
+ } else if ( !_Thread_Is_heir( the_thread ) ) {
+ _Thread_Dispatch_necessary = true;
+ }
}
diff --git a/cpukit/score/src/schedulersimplesmp.c b/cpukit/score/src/schedulersimplesmp.c
index eb260efd09..37458d6b6f 100644
--- a/cpukit/score/src/schedulersimplesmp.c
+++ b/cpukit/score/src/schedulersimplesmp.c
@@ -302,12 +302,12 @@ void _Scheduler_simple_SMP_Yield(
)
{
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
- ISR_Level level;
- _ISR_Disable( level );
-
- _Scheduler_SMP_Extract_from_scheduled( thread );
- _Scheduler_simple_SMP_Enqueue_scheduled_fifo( context, thread );
-
- _ISR_Enable( level );
+ return _Scheduler_SMP_Yield(
+ context,
+ thread,
+ _Scheduler_simple_SMP_Extract_from_ready,
+ _Scheduler_simple_SMP_Enqueue_fifo,
+ _Scheduler_simple_SMP_Enqueue_scheduled_fifo
+ );
}
diff --git a/cpukit/score/src/schedulersimpleyield.c b/cpukit/score/src/schedulersimpleyield.c
index 65578d0bbb..b807530600 100644
--- a/cpukit/score/src/schedulersimpleyield.c
+++ b/cpukit/score/src/schedulersimpleyield.c
@@ -19,7 +19,6 @@
#endif
#include <rtems/score/schedulersimpleimpl.h>
-#include <rtems/score/isr.h>
void _Scheduler_simple_Yield(
const Scheduler_Control *scheduler,
@@ -28,16 +27,8 @@ void _Scheduler_simple_Yield(
{
Scheduler_simple_Context *context =
_Scheduler_simple_Get_context( scheduler );
- ISR_Level level;
- _ISR_Disable( level );
-
- _Chain_Extract_unprotected( &the_thread->Object.Node );
- _Scheduler_simple_Insert_priority_fifo( &context->Ready, the_thread );
-
- _ISR_Flash( level );
-
- _Scheduler_simple_Schedule_body( scheduler, the_thread, false );
-
- _ISR_Enable( level );
+ _Chain_Extract_unprotected( &the_thread->Object.Node );
+ _Scheduler_simple_Insert_priority_fifo( &context->Ready, the_thread );
+ _Scheduler_simple_Schedule_body( scheduler, the_thread, false );
}
diff --git a/cpukit/score/src/threadyield.c b/cpukit/score/src/threadyield.c
new file mode 100644
index 0000000000..b49e2b30ba
--- /dev/null
+++ b/cpukit/score/src/threadyield.c
@@ -0,0 +1,41 @@
+/**
+ * @file
+ *
+ * @brief Thread Yield
+ *
+ * @ingroup ScoreThread
+ */
+
+/*
+ * Copyright (c) 2014 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include <rtems/score/threadimpl.h>
+#include <rtems/score/schedulerimpl.h>
+
+void _Thread_Yield( Thread_Control *executing )
+{
+ ISR_Level level;
+
+ _ISR_Disable( level );
+
+ if ( _States_Is_ready( executing->current_state ) ) {
+ _Scheduler_Yield( _Scheduler_Get( executing ), executing );
+ }
+
+ _ISR_Enable( level );
+}