summaryrefslogtreecommitdiffstats
path: root/cpukit/include
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/include')
-rw-r--r--cpukit/include/rtems/score/schedulerimpl.h276
-rw-r--r--cpukit/include/rtems/score/schedulerprioritysmp.h1
-rw-r--r--cpukit/include/rtems/score/schedulerprioritysmpimpl.h35
-rw-r--r--cpukit/include/rtems/score/schedulersmp.h9
-rw-r--r--cpukit/include/rtems/score/schedulersmpimpl.h572
5 files changed, 427 insertions, 466 deletions
diff --git a/cpukit/include/rtems/score/schedulerimpl.h b/cpukit/include/rtems/score/schedulerimpl.h
index eb279876c7..12b6806402 100644
--- a/cpukit/include/rtems/score/schedulerimpl.h
+++ b/cpukit/include/rtems/score/schedulerimpl.h
@@ -798,26 +798,26 @@ RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_index(
#if defined(RTEMS_SMP)
/**
- * @brief Gets an idle thread from the scheduler instance.
+ * @brief Gets a scheduler node which is owned by an unused idle thread.
*
- * @param context The scheduler instance context.
+ * @param arg is the handler argument.
*
- * @return idle An idle thread for use. This function must always return an
- * idle thread. If none is available, then this is a fatal error.
+ * @return Returns a scheduler node owned by an idle thread for use. This
+ * handler must always return a node. If none is available, then this is a
+ * fatal error.
*/
-typedef Thread_Control *( *Scheduler_Get_idle_thread )(
- Scheduler_Context *context
-);
+typedef Scheduler_Node *( *Scheduler_Get_idle_node )( void *arg );
/**
- * @brief Releases an idle thread to the scheduler instance for reuse.
+ * @brief Releases the scheduler node which is owned by an idle thread.
*
- * @param context The scheduler instance context.
- * @param idle The idle thread to release.
+ * @param node is the node to release.
+ *
+ * @param arg is the handler argument.
*/
-typedef void ( *Scheduler_Release_idle_thread )(
- Scheduler_Context *context,
- Thread_Control *idle
+typedef void ( *Scheduler_Release_idle_node )(
+ Scheduler_Node *node,
+ void *arg
);
/**
@@ -841,189 +841,114 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Thread_change_state(
}
/**
- * @brief Uses an idle thread for this scheduler node.
+ * @brief Uses an idle thread for the scheduler node.
*
- * A thread whose home scheduler node has a sticky level greater than zero may
- * use an idle thread in the home scheduler instance in the case it executes
- * currently in another scheduler instance or in the case it is in a blocking
- * state.
+ * @param[in, out] node is the node which wants to use an idle thread.
*
- * @param context The scheduler instance context.
- * @param[in, out] node The node which wants to use the idle thread.
- * @param cpu The processor for the idle thread.
- * @param get_idle_thread Function to get an idle thread.
+ * @param get_idle_node is the get idle node handler.
+ *
+ * @param arg is the handler argument.
*/
RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Use_idle_thread(
- Scheduler_Context *context,
- Scheduler_Node *node,
- Scheduler_Get_idle_thread get_idle_thread
+ Scheduler_Node *node,
+ Scheduler_Get_idle_node get_idle_node,
+ void *arg
)
{
- Thread_Control *idle = ( *get_idle_thread )( context );
+ Scheduler_Node *idle_node;
+ Thread_Control *idle;
+ idle_node = ( *get_idle_node )( arg );
+ idle = _Scheduler_Node_get_owner( idle_node );
+ _Assert( idle->is_idle );
_Scheduler_Node_set_idle_user( node, idle );
+
return idle;
}
/**
- * @brief This enumeration defines what a scheduler should do with a node which
- * could be scheduled.
- */
-typedef enum {
- SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE,
- SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE,
- SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK
-} Scheduler_Try_to_schedule_action;
-
-/**
- * @brief Tries to schedule the scheduler node.
- *
- * When a scheduler needs to schedule a node, it shall use this function to
- * determine what it shall do with the node. The node replaces a victim node if
- * it can be scheduled.
- *
- * This function uses the state of the node and the scheduler state of the owner
- * thread to determine what shall be done. Each scheduler maintains its nodes
- * independent of other schedulers. This function ensures that a thread is
- * scheduled by at most one scheduler. If a node requires an executing thread
- * due to some locking protocol and the owner thread is already scheduled by
- * another scheduler, then an idle thread shall be attached to the node.
- *
- * @param[in, out] context is the scheduler context.
- * @param[in, out] node is the node which could be scheduled.
- * @param idle is an idle thread used by the victim node or NULL.
- * @param get_idle_thread points to a function to get an idle thread.
- *
- * @retval SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE The node shall be scheduled.
- *
- * @retval SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE The node shall be
- * scheduled and the provided idle thread shall be attached to the node. This
- * action is returned, if the node cannot use the owner thread and shall use
- * an idle thread instead. In this case, the idle thread is provided by the
- * victim node.
- *
- * @retval SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK The node shall be blocked. This
- * action is returned, if the owner thread is already scheduled by another
- * scheduler.
+ * @brief Releases the idle thread used by the scheduler node.
+ *
+ * @param[in, out] node is the node which wants to release the idle thread.
+ *
+ * @param idle is the idle thread to release.
+ *
+ * @param release_idle_node is the release idle node handler.
+ *
+ * @param arg is the handler argument.
*/
-RTEMS_INLINE_ROUTINE Scheduler_Try_to_schedule_action
-_Scheduler_Try_to_schedule_node(
- Scheduler_Context *context,
- Scheduler_Node *node,
- Scheduler_Node *victim,
- Scheduler_Get_idle_thread get_idle_thread
+RTEMS_INLINE_ROUTINE void _Scheduler_Release_idle_thread(
+ Scheduler_Node *node,
+ const Thread_Control *idle,
+ Scheduler_Release_idle_node release_idle_node,
+ void *arg
)
{
- ISR_lock_Context lock_context;
- Scheduler_Try_to_schedule_action action;
- Thread_Control *owner;
+ Thread_Control *owner;
+ Scheduler_Node *idle_node;
- action = SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE;
owner = _Scheduler_Node_get_owner( node );
- _Assert( _Scheduler_Node_get_user( node ) == owner );
- _Assert( _Scheduler_Node_get_idle( node ) == NULL );
-
- _Thread_Scheduler_acquire_critical( owner, &lock_context );
-
- if ( owner->Scheduler.state == THREAD_SCHEDULER_READY ) {
- _Thread_Scheduler_cancel_need_for_help( owner, _Thread_Get_CPU( owner ) );
- _Scheduler_Thread_change_state( owner, THREAD_SCHEDULER_SCHEDULED );
- } else if (
- owner->Scheduler.state == THREAD_SCHEDULER_SCHEDULED
- && node->sticky_level <= 1
- ) {
- action = SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK;
- } else if ( node->sticky_level == 0 ) {
- action = SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK;
- } else if ( _Scheduler_Node_get_idle( victim ) != NULL ) {
- action = SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE;
- } else {
- Thread_Control *idle;
- Thread_Control *user;
-
- idle = _Scheduler_Use_idle_thread( context, node, get_idle_thread );
- user = _Scheduler_Node_get_user( node );
- _Thread_Set_CPU( idle, _Thread_Get_CPU( user ) );
- }
-
- _Thread_Scheduler_release_critical( owner, &lock_context );
- return action;
+ _Assert( _Scheduler_Node_get_user( node ) == idle );
+ _Scheduler_Node_set_user( node, owner );
+ node->idle = NULL;
+ idle_node = _Thread_Scheduler_get_home_node( idle );
+ ( *release_idle_node )( idle_node, arg );
}
/**
- * @brief Releases an idle thread using this scheduler node.
+ * @brief Releases the idle thread used by the scheduler node if the node uses
+ * an idle thread.
*
- * @param context The scheduler instance context.
- * @param[in, out] node The node which may have an idle thread as user.
- * @param release_idle_thread Function to release an idle thread.
+ * @param[in, out] node is the node which wants to release the idle thread.
+ *
+ * @param release_idle_node is the release idle node handler.
+ *
+ * @param arg is the handler argument.
+ *
+ * @retval NULL The scheduler node did not use an idle thread.
*
- * @retval idle The idle thread which used this node.
- * @retval NULL This node had no idle thread as an user.
+ * @return Returns the idle thread used by the scheduler node.
*/
-RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Release_idle_thread(
- Scheduler_Context *context,
- Scheduler_Node *node,
- Scheduler_Release_idle_thread release_idle_thread
+RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Release_idle_thread_if_necessary(
+ Scheduler_Node *node,
+ Scheduler_Release_idle_node release_idle_node,
+ void *arg
)
{
- Thread_Control *idle = _Scheduler_Node_get_idle( node );
+ Thread_Control *idle;
- if ( idle != NULL ) {
- Thread_Control *owner = _Scheduler_Node_get_owner( node );
+ idle = _Scheduler_Node_get_idle( node );
- node->idle = NULL;
- _Scheduler_Node_set_user( node, owner );
- ( *release_idle_thread )( context, idle );
+ if ( idle != NULL ) {
+ _Scheduler_Release_idle_thread( node, idle, release_idle_node, arg );
}
return idle;
}
/**
- * @brief Exchanges an idle thread from the scheduler node that uses it
- * right now to another scheduler node.
- *
- * @param needs_idle is the scheduler node that needs an idle thread.
- *
- * @param uses_idle is the scheduler node that used the idle thread.
- */
-RTEMS_INLINE_ROUTINE void _Scheduler_Exchange_idle_thread(
- Scheduler_Node *needs_idle,
- Scheduler_Node *uses_idle
-)
-{
- _Scheduler_Node_set_idle_user(
- needs_idle,
- _Scheduler_Node_get_idle( uses_idle )
- );
- _Scheduler_Node_set_user(
- uses_idle,
- _Scheduler_Node_get_owner( uses_idle )
- );
- uses_idle->idle = NULL;
-}
-
-/**
* @brief Blocks this scheduler node.
*
- * @param context The scheduler instance context.
* @param[in, out] thread The thread which wants to get blocked referencing this
* node. This is not necessarily the user of this node in case the node
* participates in the scheduler helping protocol.
- * @param[in, out] node The node which wants to get blocked.
- * @param is_scheduled This node is scheduled.
- * @param get_idle_thread Function to get an idle thread.
+ *
+ * @param[in, out] node is the node which wants to get blocked.
+ *
+ * @param get_idle_node is the get idle node handler.
+ *
+ * @param arg is the get idle node handler argument.
*
* @retval thread_cpu The processor of the thread. Indicates to continue with
* the blocking operation.
* @retval NULL Otherwise.
*/
RTEMS_INLINE_ROUTINE Per_CPU_Control *_Scheduler_Block_node(
- Scheduler_Context *context,
- Thread_Control *thread,
- Scheduler_Node *node,
- bool is_scheduled,
- Scheduler_Get_idle_thread get_idle_thread
+ Thread_Control *thread,
+ Scheduler_Node *node,
+ bool is_scheduled,
+ Scheduler_Get_idle_node get_idle_node,
+ void *arg
)
{
int sticky_level;
@@ -1045,7 +970,7 @@ RTEMS_INLINE_ROUTINE Per_CPU_Control *_Scheduler_Block_node(
if ( is_scheduled && _Scheduler_Node_get_idle( node ) == NULL ) {
Thread_Control *idle;
- idle = _Scheduler_Use_idle_thread( context, node, get_idle_thread );
+ idle = _Scheduler_Use_idle_thread( node, get_idle_node, arg );
_Thread_Set_CPU( idle, thread_cpu );
_Thread_Dispatch_update_heir( _Per_CPU_Get(), thread_cpu, idle );
}
@@ -1058,31 +983,28 @@ RTEMS_INLINE_ROUTINE Per_CPU_Control *_Scheduler_Block_node(
}
/**
- * @brief Discard the idle thread from the scheduler node.
+ * @brief Discards the idle thread used by the scheduler node.
+ *
+ * @param[in, out] the_thread is the thread owning the node.
+ *
+ * @param[in, out] node is the node which wants to release the idle thread.
+ *
+ * @param release_idle_node is the release idle node handler.
*
- * @param context The scheduler context.
- * @param[in, out] the_thread The thread for the operation.
- * @param[in, out] node The scheduler node to discard the idle thread from.
- * @param release_idle_thread Method to release the idle thread from the context.
+ * @param arg is the handler argument.
*/
RTEMS_INLINE_ROUTINE void _Scheduler_Discard_idle_thread(
- Scheduler_Context *context,
- Thread_Control *the_thread,
- Scheduler_Node *node,
- Scheduler_Release_idle_thread release_idle_thread
+ Thread_Control *the_thread,
+ Scheduler_Node *node,
+ Scheduler_Release_idle_node release_idle_node,
+ void *arg
)
{
Thread_Control *idle;
- Thread_Control *owner;
Per_CPU_Control *cpu;
idle = _Scheduler_Node_get_idle( node );
- owner = _Scheduler_Node_get_owner( node );
-
- node->idle = NULL;
- _Assert( _Scheduler_Node_get_user( node ) == idle );
- _Scheduler_Node_set_user( node, owner );
- ( *release_idle_thread )( context, idle );
+ _Scheduler_Release_idle_thread( node, idle, release_idle_node, arg );
cpu = _Thread_Get_CPU( idle );
_Thread_Set_CPU( the_thread, cpu );
@@ -1102,11 +1024,11 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Discard_idle_thread(
* @retval false Do not continue with the unblocking operation.
*/
RTEMS_INLINE_ROUTINE bool _Scheduler_Unblock_node(
- Scheduler_Context *context,
- Thread_Control *the_thread,
- Scheduler_Node *node,
- bool is_scheduled,
- Scheduler_Release_idle_thread release_idle_thread
+ Thread_Control *the_thread,
+ Scheduler_Node *node,
+ bool is_scheduled,
+ Scheduler_Release_idle_node release_idle_node,
+ void *arg
)
{
bool unblock;
@@ -1115,13 +1037,13 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_Unblock_node(
_Assert( node->sticky_level > 0 );
if ( is_scheduled ) {
+ _Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_SCHEDULED );
_Scheduler_Discard_idle_thread(
- context,
the_thread,
node,
- release_idle_thread
+ release_idle_node,
+ arg
);
- _Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_SCHEDULED );
unblock = false;
} else {
_Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_READY );
diff --git a/cpukit/include/rtems/score/schedulerprioritysmp.h b/cpukit/include/rtems/score/schedulerprioritysmp.h
index 9ece9ae143..21916647bc 100644
--- a/cpukit/include/rtems/score/schedulerprioritysmp.h
+++ b/cpukit/include/rtems/score/schedulerprioritysmp.h
@@ -57,6 +57,7 @@ extern "C" {
*/
typedef struct {
Scheduler_SMP_Context Base;
+ Chain_Control *idle_ready_queue;
Priority_bit_map_Control Bit_map;
Chain_Control Ready[ RTEMS_ZERO_LENGTH_ARRAY ];
} Scheduler_priority_SMP_Context;
diff --git a/cpukit/include/rtems/score/schedulerprioritysmpimpl.h b/cpukit/include/rtems/score/schedulerprioritysmpimpl.h
index 6e14200840..8ffd8d01c1 100644
--- a/cpukit/include/rtems/score/schedulerprioritysmpimpl.h
+++ b/cpukit/include/rtems/score/schedulerprioritysmpimpl.h
@@ -156,6 +156,41 @@ static inline void _Scheduler_priority_SMP_Extract_from_ready(
);
}
+static inline Scheduler_Node *_Scheduler_priority_SMP_Get_idle( void *arg )
+{
+ Scheduler_priority_SMP_Context *self;
+ Scheduler_priority_SMP_Node *lowest_ready;
+
+ self = _Scheduler_priority_SMP_Get_self( arg );
+ lowest_ready = (Scheduler_priority_SMP_Node *)
+ _Chain_Last( self->idle_ready_queue );
+ _Scheduler_priority_Ready_queue_extract(
+ &lowest_ready->Base.Base.Node.Chain,
+ &lowest_ready->Ready_queue,
+ &self->Bit_map
+ );
+
+ return &lowest_ready->Base.Base;
+}
+
+static inline void _Scheduler_priority_SMP_Release_idle(
+ Scheduler_Node *node_base,
+ void *arg
+)
+{
+ Scheduler_priority_SMP_Context *self;
+ Scheduler_priority_SMP_Node *node;
+
+ self = _Scheduler_priority_SMP_Get_self( arg );
+ node = _Scheduler_priority_SMP_Node_downcast( node_base );
+
+ _Scheduler_priority_Ready_queue_enqueue(
+ &node->Base.Base.Node.Chain,
+ &node->Ready_queue,
+ &self->Bit_map
+ );
+}
+
static inline void _Scheduler_priority_SMP_Do_update(
Scheduler_Context *context,
Scheduler_Node *node_to_update,
diff --git a/cpukit/include/rtems/score/schedulersmp.h b/cpukit/include/rtems/score/schedulersmp.h
index 1d5294b4f0..fb4d6c46d2 100644
--- a/cpukit/include/rtems/score/schedulersmp.h
+++ b/cpukit/include/rtems/score/schedulersmp.h
@@ -55,15 +55,6 @@ typedef struct {
* @brief The chain of scheduled nodes.
*/
Chain_Control Scheduled;
-
- /**
- * @brief Chain of the available idle threads.
- *
- * Idle threads are used for the scheduler helping protocol. It is crucial
- * that the idle threads preserve their relative order. This is the case for
- * this priority based scheduler.
- */
- Chain_Control Idle_threads;
} Scheduler_SMP_Context;
/**
diff --git a/cpukit/include/rtems/score/schedulersmpimpl.h b/cpukit/include/rtems/score/schedulersmpimpl.h
index 731b15d4bf..6fb97c86b2 100644
--- a/cpukit/include/rtems/score/schedulersmpimpl.h
+++ b/cpukit/include/rtems/score/schedulersmpimpl.h
@@ -8,7 +8,7 @@
*/
/*
- * Copyright (c) 2013, 2017 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2013, 2021 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
@@ -282,7 +282,11 @@ typedef bool ( *Scheduler_SMP_Has_ready )(
typedef Scheduler_Node *( *Scheduler_SMP_Get_highest_ready )(
Scheduler_Context *context,
- Scheduler_Node *node
+ Scheduler_Node *filter
+);
+
+typedef Scheduler_Node *( *Scheduler_SMP_Get_lowest_ready )(
+ Scheduler_Context *context
);
typedef Scheduler_Node *( *Scheduler_SMP_Get_lowest_scheduled )(
@@ -339,7 +343,7 @@ typedef void ( *Scheduler_SMP_Enqueue_scheduled )(
typedef void ( *Scheduler_SMP_Allocate_processor )(
Scheduler_Context *context,
Scheduler_Node *scheduled,
- Scheduler_Node *victim,
+ Thread_Control *victim_thread,
Per_CPU_Control *victim_cpu
);
@@ -414,7 +418,6 @@ static inline void _Scheduler_SMP_Initialize(
)
{
_Chain_Initialize_empty( &self->Scheduled );
- _Chain_Initialize_empty( &self->Idle_threads );
}
/**
@@ -556,51 +559,79 @@ static inline bool _Scheduler_SMP_Is_processor_owned_by_us(
}
/**
- * @brief Gets The first idle thread of the given context.
+ * @brief This enumeration defines what a scheduler should do with a node which
+ * could be scheduled.
+ */
+typedef enum {
+ SCHEDULER_SMP_DO_SCHEDULE,
+ SCHEDULER_SMP_DO_NOT_SCHEDULE
+} Scheduler_SMP_Action;
+
+/**
+ * @brief Tries to schedule the scheduler node.
+ *
+ * When an SMP scheduler needs to schedule a node, it shall use this function
+ * to determine what it shall do with the node.
+ *
+ * This function uses the state of the node and the scheduler state of the
+ * owner thread to determine what shall be done. Each scheduler maintains its
+ * nodes independent of other schedulers. This function ensures that a thread
+ * is scheduled by at most one scheduler. If a node requires an executing
+ * thread due to some locking protocol and the owner thread is already
+ * scheduled by another scheduler, then an idle thread will be attached to the
+ * node.
+ *
+ * @param[in, out] node is the node which should be scheduled.
+ *
+ * @param get_idle_node is the get idle node handler.
+ *
+ * @param arg is the get idle node handler argument.
*
- * @param context The scheduler context to get the first idle thread from.
+ * @retval SCHEDULER_SMP_DO_SCHEDULE The node shall be scheduled.
*
- * @return The first idle thread of @a context.
+ * @retval SCHEDULER_SMP_DO_NOT_SCHEDULE The node shall be blocked. This
+ * action is returned, if the owner thread is already scheduled by another
+ * scheduler.
*/
-static inline Thread_Control *_Scheduler_SMP_Get_idle_thread(
- Scheduler_Context *context
+static inline Scheduler_SMP_Action _Scheduler_SMP_Try_to_schedule(
+ Scheduler_Node *node,
+ Scheduler_Get_idle_node get_idle_node,
+ void *arg
)
{
- Scheduler_SMP_Context *self = _Scheduler_SMP_Get_self( context );
- Thread_Control *idle = (Thread_Control *)
- _Chain_Get_first_unprotected( &self->Idle_threads );
+ ISR_lock_Context lock_context;
+ Thread_Control *owner;
+ Thread_Scheduler_state owner_state;
+ int owner_sticky_level;
+
+ owner = _Scheduler_Node_get_owner( node );
+ _Assert( _Scheduler_Node_get_idle( node ) == NULL );
+
+ _Thread_Scheduler_acquire_critical( owner, &lock_context );
+ owner_state = owner->Scheduler.state;
+ owner_sticky_level = node->sticky_level;
+
+ if ( RTEMS_PREDICT_TRUE( owner_state == THREAD_SCHEDULER_READY ) ) {
+ _Thread_Scheduler_cancel_need_for_help( owner, _Thread_Get_CPU( owner ) );
+ _Scheduler_Thread_change_state( owner, THREAD_SCHEDULER_SCHEDULED );
+ _Thread_Scheduler_release_critical( owner, &lock_context );
+ return SCHEDULER_SMP_DO_SCHEDULE;
+ }
- _Assert( &idle->Object.Node != _Chain_Tail( &self->Idle_threads ) );
+ _Thread_Scheduler_release_critical( owner, &lock_context );
- return idle;
-}
+ if (
+ ( owner_state == THREAD_SCHEDULER_SCHEDULED && owner_sticky_level <= 1 ) ||
+ owner_sticky_level == 0
+ ) {
+ _Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_BLOCKED );
-/**
- * @brief Releases the thread and adds it to the idle threads.
- *
- * @param[in, out] context The scheduler context instance.
- * @param idle The thread to add to the idle threads.
- */
-static inline void _Scheduler_SMP_Release_idle_thread(
- Scheduler_Context *context,
- Thread_Control *idle
-)
-{
- Scheduler_SMP_Context *self = _Scheduler_SMP_Get_self( context );
+ return SCHEDULER_SMP_DO_NOT_SCHEDULE;
+ }
- _Chain_Prepend_unprotected( &self->Idle_threads, &idle->Object.Node );
-}
+ (void) _Scheduler_Use_idle_thread( node, get_idle_node, arg );
-/**
- * @brief Extracts the node of the idle thread.
- *
- * @param[in, out] idle The thread to extract the node of.
- */
-static inline void _Scheduler_SMP_Extract_idle_thread(
- Thread_Control *idle
-)
-{
- _Chain_Extract_unprotected( &idle->Object.Node );
+ return SCHEDULER_SMP_DO_SCHEDULE;
}
/**
@@ -616,12 +647,11 @@ static inline void _Scheduler_SMP_Extract_idle_thread(
static inline void _Scheduler_SMP_Allocate_processor_lazy(
Scheduler_Context *context,
Scheduler_Node *scheduled,
- Scheduler_Node *victim,
+ Thread_Control *victim_thread,
Per_CPU_Control *victim_cpu
)
{
Thread_Control *scheduled_thread = _Scheduler_Node_get_user( scheduled );
- Thread_Control *victim_thread = _Scheduler_Node_get_user( victim );
Per_CPU_Control *scheduled_cpu = _Thread_Get_CPU( scheduled_thread );
Per_CPU_Control *cpu_self = _Per_CPU_Get();
Thread_Control *heir;
@@ -666,7 +696,7 @@ static inline void _Scheduler_SMP_Allocate_processor_lazy(
static inline void _Scheduler_SMP_Allocate_processor_exact(
Scheduler_Context *context,
Scheduler_Node *scheduled,
- Scheduler_Node *victim,
+ Thread_Control *victim_thread,
Per_CPU_Control *victim_cpu
)
{
@@ -674,7 +704,7 @@ static inline void _Scheduler_SMP_Allocate_processor_exact(
Per_CPU_Control *cpu_self = _Per_CPU_Get();
(void) context;
- (void) victim;
+ (void) victim_thread;
_Thread_Set_CPU( scheduled_thread, victim_cpu );
_Thread_Dispatch_update_heir( cpu_self, victim_cpu, scheduled_thread );
@@ -692,69 +722,80 @@ static inline void _Scheduler_SMP_Allocate_processor_exact(
static inline void _Scheduler_SMP_Allocate_processor(
Scheduler_Context *context,
Scheduler_Node *scheduled,
- Scheduler_Node *victim,
+ Thread_Control *victim_thread,
Per_CPU_Control *victim_cpu,
Scheduler_SMP_Allocate_processor allocate_processor
)
{
_Scheduler_SMP_Node_change_state( scheduled, SCHEDULER_SMP_NODE_SCHEDULED );
- ( *allocate_processor )( context, scheduled, victim, victim_cpu );
+ ( *allocate_processor )( context, scheduled, victim_thread, victim_cpu );
}
/**
- * @brief Preempts the victim's thread and allocates a cpu for the scheduled thread.
+ * @brief Preempts the victim's thread and allocates a processor for the user
+ * of the scheduled node.
*
- * @param context The scheduler context instance.
- * @param scheduled Node of the scheduled thread that is about to be executed.
- * @param[in, out] victim Node of the thread to preempt.
- * @param allocate_processor The function for allocation of a processor for the new thread.
+ * @param[in, out] context is the scheduler context.
+ *
+ * @param scheduled[in, out] is the node of the user thread that is about to
+ * get a processor allocated.
+ *
+ * @param[in, out] victim is the victim node of the thread to preempt.
*
- * @return The preempted thread.
+ * @param[in, out] victim_idle is the idle thread used by the victim node or NULL.
+ *
+ * @param allocate_processor The function for allocation of a processor for the new thread.
*/
-static inline Thread_Control *_Scheduler_SMP_Preempt(
+static inline void _Scheduler_SMP_Preempt(
Scheduler_Context *context,
Scheduler_Node *scheduled,
Scheduler_Node *victim,
+ Thread_Control *victim_idle,
Scheduler_SMP_Allocate_processor allocate_processor
)
{
- Thread_Control *victim_thread;
- ISR_lock_Context scheduler_lock_context;
+ Thread_Control *victim_owner;
+ Thread_Control *victim_user;
+ ISR_lock_Context lock_context;
Per_CPU_Control *victim_cpu;
- victim_thread = _Scheduler_Node_get_user( victim );
_Scheduler_SMP_Node_change_state( victim, SCHEDULER_SMP_NODE_READY );
- _Thread_Scheduler_acquire_critical( victim_thread, &scheduler_lock_context );
+ victim_owner = _Scheduler_Node_get_owner( victim );
+ _Thread_Scheduler_acquire_critical( victim_owner, &lock_context );
- victim_cpu = _Thread_Get_CPU( victim_thread );
+ if ( RTEMS_PREDICT_TRUE( victim_idle == NULL ) ) {
+ victim_user = victim_owner;
+ victim_cpu = _Thread_Get_CPU( victim_owner );
- if ( victim_thread->Scheduler.state == THREAD_SCHEDULER_SCHEDULED ) {
- _Scheduler_Thread_change_state( victim_thread, THREAD_SCHEDULER_READY );
+ if ( victim_owner->Scheduler.state == THREAD_SCHEDULER_SCHEDULED ) {
+ _Scheduler_Thread_change_state( victim_owner, THREAD_SCHEDULER_READY );
- if ( victim_thread->Scheduler.helping_nodes > 0 ) {
- ISR_lock_Context per_cpu_lock_context;
+ if ( victim_owner->Scheduler.helping_nodes > 0 ) {
+ ISR_lock_Context lock_context_2;
- _Per_CPU_Acquire( victim_cpu, &per_cpu_lock_context );
- _Chain_Append_unprotected(
- &victim_cpu->Threads_in_need_for_help,
- &victim_thread->Scheduler.Help_node
- );
- _Per_CPU_Release( victim_cpu, &per_cpu_lock_context );
+ _Per_CPU_Acquire( victim_cpu, &lock_context_2 );
+ _Chain_Append_unprotected(
+ &victim_cpu->Threads_in_need_for_help,
+ &victim_owner->Scheduler.Help_node
+ );
+ _Per_CPU_Release( victim_cpu, &lock_context_2 );
+ }
}
+ } else {
+ victim_user = victim_idle;
+ victim_cpu = _Thread_Get_CPU( victim_idle );
}
- _Thread_Scheduler_release_critical( victim_thread, &scheduler_lock_context );
+ _Thread_Scheduler_release_critical( victim_owner, &lock_context );
_Scheduler_SMP_Allocate_processor(
context,
scheduled,
- victim,
+ victim_user,
victim_cpu,
allocate_processor
);
-
- return victim_thread;
}
/**
@@ -808,54 +849,43 @@ static inline void _Scheduler_SMP_Enqueue_to_scheduled(
Scheduler_Node *lowest_scheduled,
Scheduler_SMP_Insert insert_scheduled,
Scheduler_SMP_Move move_from_scheduled_to_ready,
- Scheduler_SMP_Allocate_processor allocate_processor
+ Scheduler_SMP_Move move_from_ready_to_scheduled,
+ Scheduler_SMP_Allocate_processor allocate_processor,
+ Scheduler_Get_idle_node get_idle_node,
+ Scheduler_Release_idle_node release_idle_node
)
{
- Scheduler_Try_to_schedule_action action;
+ Thread_Control *lowest_scheduled_idle;
+ Scheduler_SMP_Action action;
- action = _Scheduler_Try_to_schedule_node(
- context,
- node,
+ lowest_scheduled_idle = _Scheduler_Release_idle_thread_if_necessary(
lowest_scheduled,
- _Scheduler_SMP_Get_idle_thread
+ release_idle_node,
+ context
);
- if ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE ) {
+ ( *move_from_scheduled_to_ready )( context, lowest_scheduled );
+
+ action = _Scheduler_SMP_Try_to_schedule( node, get_idle_node, context );
+
+ if ( RTEMS_PREDICT_TRUE( action == SCHEDULER_SMP_DO_SCHEDULE ) ) {
_Scheduler_SMP_Preempt(
context,
node,
lowest_scheduled,
+ lowest_scheduled_idle,
allocate_processor
);
- ( *move_from_scheduled_to_ready )( context, lowest_scheduled );
( *insert_scheduled )( context, node, priority );
+ } else {
+ _Assert( action == SCHEDULER_SMP_DO_NOT_SCHEDULE );
- _Scheduler_Release_idle_thread(
- context,
- lowest_scheduled,
- _Scheduler_SMP_Release_idle_thread
- );
- } else if ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE ) {
- _Scheduler_SMP_Node_change_state(
- lowest_scheduled,
- SCHEDULER_SMP_NODE_READY
- );
- _Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_SCHEDULED );
-
- ( *move_from_scheduled_to_ready )( context, lowest_scheduled );
- ( *insert_scheduled )( context, node, priority );
+ if ( lowest_scheduled_idle != NULL ) {
+ (void) _Scheduler_Use_idle_thread( lowest_scheduled, get_idle_node, context );
+ }
- _Scheduler_Exchange_idle_thread( node, lowest_scheduled );
- ( *allocate_processor )(
- context,
- node,
- lowest_scheduled,
- _Thread_Get_CPU( _Scheduler_Node_get_user( node ) )
- );
- } else {
- _Assert( action == SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK );
- _Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_BLOCKED );
+ ( *move_from_ready_to_scheduled )( context, lowest_scheduled );
}
}
@@ -889,8 +919,11 @@ static inline bool _Scheduler_SMP_Enqueue(
Scheduler_SMP_Insert insert_ready,
Scheduler_SMP_Insert insert_scheduled,
Scheduler_SMP_Move move_from_scheduled_to_ready,
+ Scheduler_SMP_Move move_from_ready_to_scheduled,
Scheduler_SMP_Get_lowest_scheduled get_lowest_scheduled,
- Scheduler_SMP_Allocate_processor allocate_processor
+ Scheduler_SMP_Allocate_processor allocate_processor,
+ Scheduler_Get_idle_node get_idle_node,
+ Scheduler_Release_idle_node release_idle_node
)
{
bool needs_help;
@@ -906,10 +939,14 @@ static inline bool _Scheduler_SMP_Enqueue(
lowest_scheduled,
insert_scheduled,
move_from_scheduled_to_ready,
- allocate_processor
+ move_from_ready_to_scheduled,
+ allocate_processor,
+ get_idle_node,
+ release_idle_node
);
needs_help = false;
} else {
+ _Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_READY );
( *insert_ready )( context, node, insert_priority );
needs_help = true;
}
@@ -946,12 +983,22 @@ static inline void _Scheduler_SMP_Enqueue_scheduled(
Scheduler_SMP_Insert insert_ready,
Scheduler_SMP_Insert insert_scheduled,
Scheduler_SMP_Move move_from_ready_to_scheduled,
- Scheduler_SMP_Allocate_processor allocate_processor
+ Scheduler_SMP_Allocate_processor allocate_processor,
+ Scheduler_Get_idle_node get_idle_node,
+ Scheduler_Release_idle_node release_idle_node
)
{
+ Thread_Control *node_idle;
+
+ node_idle = _Scheduler_Release_idle_thread_if_necessary(
+ node,
+ release_idle_node,
+ context
+ );
+
while ( true ) {
- Scheduler_Node *highest_ready;
- Scheduler_Try_to_schedule_action action;
+ Scheduler_Node *highest_ready;
+ Scheduler_SMP_Action action;
highest_ready = ( *get_highest_ready )( context, node );
@@ -963,9 +1010,7 @@ static inline void _Scheduler_SMP_Enqueue_scheduled(
node->sticky_level > 0
&& ( *order )( &insert_priority, &highest_ready->Node.Chain )
) {
- ( *insert_scheduled )( context, node, insert_priority );
-
- if ( _Scheduler_Node_get_idle( node ) != NULL ) {
+ if ( node_idle != NULL ) {
Thread_Control *owner;
ISR_lock_Context lock_context;
@@ -973,77 +1018,53 @@ static inline void _Scheduler_SMP_Enqueue_scheduled(
_Thread_Scheduler_acquire_critical( owner, &lock_context );
if ( owner->Scheduler.state == THREAD_SCHEDULER_READY ) {
+ Per_CPU_Control *cpu;
+
_Thread_Scheduler_cancel_need_for_help(
owner,
_Thread_Get_CPU( owner )
);
- _Scheduler_Discard_idle_thread(
- context,
- owner,
- node,
- _Scheduler_SMP_Release_idle_thread
- );
_Scheduler_Thread_change_state( owner, THREAD_SCHEDULER_SCHEDULED );
+ cpu = _Thread_Get_CPU( node_idle );
+ _Thread_Set_CPU( owner, cpu );
+ _Thread_Scheduler_release_critical( owner, &lock_context );
+ _Thread_Dispatch_update_heir( _Per_CPU_Get(), cpu, owner );
+ } else {
+ Thread_Control *new_idle;
+
+ _Thread_Scheduler_release_critical( owner, &lock_context );
+ new_idle = _Scheduler_Use_idle_thread( node, get_idle_node, context );
+ _Assert_Unused_variable_equals( new_idle, node_idle );
}
-
- _Thread_Scheduler_release_critical( owner, &lock_context );
}
+ ( *insert_scheduled )( context, node, insert_priority );
+
return;
}
- action = _Scheduler_Try_to_schedule_node(
- context,
+ action = _Scheduler_SMP_Try_to_schedule(
highest_ready,
- node,
- _Scheduler_SMP_Get_idle_thread
+ get_idle_node,
+ context
);
- if ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE ) {
+ if ( RTEMS_PREDICT_TRUE( action == SCHEDULER_SMP_DO_SCHEDULE ) ) {
_Scheduler_SMP_Preempt(
context,
highest_ready,
node,
+ node_idle,
allocate_processor
);
( *move_from_ready_to_scheduled )( context, highest_ready );
( *insert_ready )( context, node, insert_priority );
-
- _Scheduler_Release_idle_thread(
- context,
- node,
- _Scheduler_SMP_Release_idle_thread
- );
- return;
- } else if ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE ) {
- _Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_READY );
- _Scheduler_SMP_Node_change_state(
- highest_ready,
- SCHEDULER_SMP_NODE_SCHEDULED
- );
-
- ( *move_from_ready_to_scheduled )( context, highest_ready );
- ( *insert_ready )( context, node, insert_priority );
-
- _Scheduler_Exchange_idle_thread( highest_ready, node );
- ( *allocate_processor )(
- context,
- highest_ready,
- node,
- _Thread_Get_CPU( _Scheduler_Node_get_user( highest_ready ) )
- );
return;
- } else {
- _Assert( action == SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK );
-
- _Scheduler_SMP_Node_change_state(
- highest_ready,
- SCHEDULER_SMP_NODE_BLOCKED
- );
-
- ( *extract_from_ready )( context, highest_ready );
}
+
+ _Assert( action == SCHEDULER_SMP_DO_NOT_SCHEDULE );
+ ( *extract_from_ready )( context, highest_ready );
}
}
@@ -1083,63 +1104,46 @@ static inline void _Scheduler_SMP_Schedule_highest_ready(
Scheduler_SMP_Extract extract_from_ready,
Scheduler_SMP_Get_highest_ready get_highest_ready,
Scheduler_SMP_Move move_from_ready_to_scheduled,
- Scheduler_SMP_Allocate_processor allocate_processor
+ Scheduler_SMP_Allocate_processor allocate_processor,
+ Scheduler_Get_idle_node get_idle_node,
+ Scheduler_Release_idle_node release_idle_node
)
{
- Scheduler_Try_to_schedule_action action;
+ Thread_Control *victim_thread;
+ Scheduler_SMP_Action action;
- do {
+ victim_thread = _Scheduler_Node_get_user( victim );
+ (void) _Scheduler_Release_idle_thread_if_necessary(
+ victim,
+ release_idle_node,
+ context
+ );
+
+ while ( true ) {
Scheduler_Node *highest_ready = ( *get_highest_ready )( context, victim );
- action = _Scheduler_Try_to_schedule_node(
- context,
+ action = _Scheduler_SMP_Try_to_schedule(
highest_ready,
- victim,
- _Scheduler_SMP_Get_idle_thread
+ get_idle_node,
+ context
);
- if ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE ) {
+ if ( RTEMS_PREDICT_TRUE( action == SCHEDULER_SMP_DO_SCHEDULE ) ) {
_Scheduler_SMP_Allocate_processor(
context,
highest_ready,
- victim,
+ victim_thread,
victim_cpu,
allocate_processor
);
( *move_from_ready_to_scheduled )( context, highest_ready );
-
- _Scheduler_Release_idle_thread(
- context,
- victim,
- _Scheduler_SMP_Release_idle_thread
- );
- } else if ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE ) {
- _Scheduler_SMP_Node_change_state(
- highest_ready,
- SCHEDULER_SMP_NODE_SCHEDULED
- );
-
- ( *move_from_ready_to_scheduled )( context, highest_ready );
-
- _Scheduler_Exchange_idle_thread( highest_ready, victim );
- ( *allocate_processor )(
- context,
- highest_ready,
- victim,
- _Thread_Get_CPU( _Scheduler_Node_get_user( highest_ready ) )
- );
- } else {
- _Assert( action == SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK );
-
- _Scheduler_SMP_Node_change_state(
- highest_ready,
- SCHEDULER_SMP_NODE_BLOCKED
- );
-
- ( *extract_from_ready )( context, highest_ready );
+ return;
}
- } while ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK );
+
+ _Assert( action == SCHEDULER_SMP_DO_NOT_SCHEDULE );
+ ( *extract_from_ready )( context, highest_ready );
+ }
}
/**
@@ -1147,7 +1151,6 @@ static inline void _Scheduler_SMP_Schedule_highest_ready(
*
* @param context The scheduler context instance.
* @param victim The node of the thread that is repressed by the newly scheduled thread.
- * @param victim_cpu The cpu to allocate.
* @param extract_from_ready Function to extract a node from the set of
* ready nodes.
* @param get_highest_ready Function to get the highest ready node.
@@ -1159,61 +1162,49 @@ static inline void _Scheduler_SMP_Schedule_highest_ready(
static inline void _Scheduler_SMP_Preempt_and_schedule_highest_ready(
Scheduler_Context *context,
Scheduler_Node *victim,
- Per_CPU_Control *victim_cpu,
Scheduler_SMP_Extract extract_from_ready,
Scheduler_SMP_Get_highest_ready get_highest_ready,
Scheduler_SMP_Move move_from_ready_to_scheduled,
- Scheduler_SMP_Allocate_processor allocate_processor
+ Scheduler_SMP_Allocate_processor allocate_processor,
+ Scheduler_Get_idle_node get_idle_node,
+ Scheduler_Release_idle_node release_idle_node
)
{
- Scheduler_Try_to_schedule_action action;
+ Thread_Control *victim_idle;
+ Scheduler_SMP_Action action;
- do {
+ _Scheduler_SMP_Node_change_state( victim, SCHEDULER_SMP_NODE_READY );
+ victim_idle = _Scheduler_Release_idle_thread_if_necessary(
+ victim,
+ release_idle_node,
+ context
+ );
+
+ while ( true ) {
Scheduler_Node *highest_ready = ( *get_highest_ready )( context, victim );
- action = _Scheduler_Try_to_schedule_node(
- context,
+ action = _Scheduler_SMP_Try_to_schedule(
highest_ready,
- victim,
- _Scheduler_SMP_Get_idle_thread
+ get_idle_node,
+ context
);
- if ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE ) {
+ if ( RTEMS_PREDICT_TRUE( action == SCHEDULER_SMP_DO_SCHEDULE ) ) {
_Scheduler_SMP_Preempt(
context,
highest_ready,
victim,
+ victim_idle,
allocate_processor
);
( *move_from_ready_to_scheduled )( context, highest_ready );
-
- _Scheduler_Release_idle_thread(
- context,
- victim,
- _Scheduler_SMP_Release_idle_thread
- );
- } else if ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE ) {
- _Scheduler_SMP_Node_change_state(
- highest_ready,
- SCHEDULER_SMP_NODE_SCHEDULED
- );
-
- ( *move_from_ready_to_scheduled )( context, highest_ready );
-
- _Scheduler_Exchange_idle_thread( highest_ready, victim );
- ( *allocate_processor )( context, highest_ready, victim, _Thread_Get_CPU( _Scheduler_Node_get_user( highest_ready ) ) );
- } else {
- _Assert( action == SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK );
-
- _Scheduler_SMP_Node_change_state(
- highest_ready,
- SCHEDULER_SMP_NODE_BLOCKED
- );
-
- ( *extract_from_ready )( context, highest_ready );
+ return;
}
- } while ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK );
+
+ _Assert( action == SCHEDULER_SMP_DO_NOT_SCHEDULE );
+ ( *extract_from_ready )( context, highest_ready );
+ }
}
/**
@@ -1240,7 +1231,9 @@ static inline void _Scheduler_SMP_Block(
Scheduler_SMP_Extract extract_from_ready,
Scheduler_SMP_Get_highest_ready get_highest_ready,
Scheduler_SMP_Move move_from_ready_to_scheduled,
- Scheduler_SMP_Allocate_processor allocate_processor
+ Scheduler_SMP_Allocate_processor allocate_processor,
+ Scheduler_Get_idle_node get_idle_node,
+ Scheduler_Release_idle_node release_idle_node
)
{
Scheduler_SMP_Node_state node_state;
@@ -1249,11 +1242,11 @@ static inline void _Scheduler_SMP_Block(
node_state = _Scheduler_SMP_Node_state( node );
thread_cpu = _Scheduler_Block_node(
- context,
thread,
node,
node_state == SCHEDULER_SMP_NODE_SCHEDULED,
- _Scheduler_SMP_Get_idle_thread
+ get_idle_node,
+ context
);
if ( thread_cpu != NULL ) {
@@ -1268,7 +1261,9 @@ static inline void _Scheduler_SMP_Block(
extract_from_ready,
get_highest_ready,
move_from_ready_to_scheduled,
- allocate_processor
+ allocate_processor,
+ get_idle_node,
+ release_idle_node
);
} else if ( node_state == SCHEDULER_SMP_NODE_READY ) {
( *extract_from_ready )( context, node );
@@ -1287,11 +1282,12 @@ static inline void _Scheduler_SMP_Block(
* of a context.
*/
static inline void _Scheduler_SMP_Unblock(
- Scheduler_Context *context,
- Thread_Control *thread,
- Scheduler_Node *node,
- Scheduler_SMP_Update update,
- Scheduler_SMP_Enqueue enqueue
+ Scheduler_Context *context,
+ Thread_Control *thread,
+ Scheduler_Node *node,
+ Scheduler_SMP_Update update,
+ Scheduler_SMP_Enqueue enqueue,
+ Scheduler_Release_idle_node release_idle_node
)
{
Scheduler_SMP_Node_state node_state;
@@ -1299,11 +1295,11 @@ static inline void _Scheduler_SMP_Unblock(
node_state = _Scheduler_SMP_Node_state( node );
unblock = _Scheduler_Unblock_node(
- context,
thread,
node,
node_state == SCHEDULER_SMP_NODE_SCHEDULED,
- _Scheduler_SMP_Release_idle_thread
+ release_idle_node,
+ context
);
if ( unblock ) {
@@ -1320,7 +1316,6 @@ static inline void _Scheduler_SMP_Unblock(
if ( node_state == SCHEDULER_SMP_NODE_BLOCKED ) {
Priority_Control insert_priority;
- _Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_READY );
insert_priority = SCHEDULER_PRIORITY_APPEND( priority );
needs_help = ( *enqueue )( context, node, insert_priority );
} else {
@@ -1507,7 +1502,8 @@ static inline bool _Scheduler_SMP_Ask_for_help(
Scheduler_SMP_Insert insert_scheduled,
Scheduler_SMP_Move move_from_scheduled_to_ready,
Scheduler_SMP_Get_lowest_scheduled get_lowest_scheduled,
- Scheduler_SMP_Allocate_processor allocate_processor
+ Scheduler_SMP_Allocate_processor allocate_processor,
+ Scheduler_Release_idle_node release_idle_node
)
{
Scheduler_Node *lowest_scheduled;
@@ -1537,6 +1533,8 @@ static inline bool _Scheduler_SMP_Ask_for_help(
insert_priority = _Scheduler_SMP_Node_priority( node );
if ( ( *order )( &insert_priority, &lowest_scheduled->Node.Chain ) ) {
+ Thread_Control *lowest_scheduled_idle;
+
_Thread_Scheduler_cancel_need_for_help(
thread,
_Thread_Get_CPU( thread )
@@ -1544,24 +1542,27 @@ static inline bool _Scheduler_SMP_Ask_for_help(
_Scheduler_Thread_change_state( thread, THREAD_SCHEDULER_SCHEDULED );
_Thread_Scheduler_release_critical( thread, &lock_context );
+ lowest_scheduled_idle = _Scheduler_Release_idle_thread_if_necessary(
+ lowest_scheduled,
+ release_idle_node,
+ context
+ );
+
_Scheduler_SMP_Preempt(
context,
node,
lowest_scheduled,
+ lowest_scheduled_idle,
allocate_processor
);
( *move_from_scheduled_to_ready )( context, lowest_scheduled );
( *insert_scheduled )( context, node, insert_priority );
- _Scheduler_Release_idle_thread(
- context,
- lowest_scheduled,
- _Scheduler_SMP_Release_idle_thread
- );
success = true;
} else {
_Thread_Scheduler_release_critical( thread, &lock_context );
+
_Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_READY );
( *insert_ready )( context, node, insert_priority );
success = false;
@@ -1571,14 +1572,14 @@ static inline bool _Scheduler_SMP_Ask_for_help(
thread,
_Thread_Get_CPU( thread )
);
+ _Scheduler_Thread_change_state( thread, THREAD_SCHEDULER_SCHEDULED );
+ _Thread_Scheduler_release_critical( thread, &lock_context );
_Scheduler_Discard_idle_thread(
- context,
thread,
node,
- _Scheduler_SMP_Release_idle_thread
+ release_idle_node,
+ context
);
- _Scheduler_Thread_change_state( thread, THREAD_SCHEDULER_SCHEDULED );
- _Thread_Scheduler_release_critical( thread, &lock_context );
success = true;
} else {
_Thread_Scheduler_release_critical( thread, &lock_context );
@@ -1650,7 +1651,9 @@ static inline void _Scheduler_SMP_Withdraw_node(
Scheduler_SMP_Extract extract_from_ready,
Scheduler_SMP_Get_highest_ready get_highest_ready,
Scheduler_SMP_Move move_from_ready_to_scheduled,
- Scheduler_SMP_Allocate_processor allocate_processor
+ Scheduler_SMP_Allocate_processor allocate_processor,
+ Scheduler_Get_idle_node get_idle_node,
+ Scheduler_Release_idle_node release_idle_node
)
{
ISR_lock_Context lock_context;
@@ -1664,6 +1667,7 @@ static inline void _Scheduler_SMP_Withdraw_node(
if ( node_state == SCHEDULER_SMP_NODE_SCHEDULED ) {
Per_CPU_Control *thread_cpu;
+ _Assert( thread == _Scheduler_Node_get_user( node ) );
thread_cpu = _Thread_Get_CPU( thread );
_Scheduler_Thread_change_state( thread, next_state );
_Thread_Scheduler_release_critical( thread, &lock_context );
@@ -1676,7 +1680,9 @@ static inline void _Scheduler_SMP_Withdraw_node(
extract_from_ready,
get_highest_ready,
move_from_ready_to_scheduled,
- allocate_processor
+ allocate_processor,
+ get_idle_node,
+ release_idle_node
);
} else if ( node_state == SCHEDULER_SMP_NODE_READY ) {
_Thread_Scheduler_release_critical( thread, &lock_context );
@@ -1721,7 +1727,6 @@ static inline void _Scheduler_SMP_Make_sticky(
( *update )( context, node, priority );
}
- _Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_READY );
insert_priority = SCHEDULER_PRIORITY_APPEND( priority );
(void) ( *enqueue )( context, node, insert_priority );
}
@@ -1744,7 +1749,9 @@ static inline void _Scheduler_SMP_Clean_sticky(
Scheduler_SMP_Extract extract_from_ready,
Scheduler_SMP_Get_highest_ready get_highest_ready,
Scheduler_SMP_Move move_from_ready_to_scheduled,
- Scheduler_SMP_Allocate_processor allocate_processor
+ Scheduler_SMP_Allocate_processor allocate_processor,
+ Scheduler_Get_idle_node get_idle_node,
+ Scheduler_Release_idle_node release_idle_node
)
{
Scheduler_SMP_Node_state node_state;
@@ -1755,8 +1762,8 @@ static inline void _Scheduler_SMP_Clean_sticky(
Scheduler_Context *context;
context = _Scheduler_Get_context( scheduler );
- _Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_BLOCKED );
+ _Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_BLOCKED );
( *extract_from_scheduled )( context, node );
_Scheduler_SMP_Schedule_highest_ready(
@@ -1766,7 +1773,9 @@ static inline void _Scheduler_SMP_Clean_sticky(
extract_from_ready,
get_highest_ready,
move_from_ready_to_scheduled,
- allocate_processor
+ allocate_processor,
+ get_idle_node,
+ release_idle_node
);
}
}
@@ -1798,7 +1807,6 @@ static inline void _Scheduler_SMP_Do_start_idle(
_Thread_Set_CPU( idle, cpu );
( *register_idle )( context, &node->Base, cpu );
_Chain_Append_unprotected( &self->Scheduled, &node->Base.Node.Chain );
- _Scheduler_SMP_Release_idle_thread( &self->Base, idle );
}
/**
@@ -1823,7 +1831,6 @@ static inline void _Scheduler_SMP_Add_processor(
self = _Scheduler_SMP_Get_self( context );
idle->Scheduler.state = THREAD_SCHEDULER_SCHEDULED;
- _Scheduler_SMP_Release_idle_thread( &self->Base, idle );
node = _Thread_Scheduler_get_home_node( idle );
_Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_SCHEDULED );
( *register_idle )( context, node, _Thread_Get_CPU( idle ) );
@@ -1853,11 +1860,13 @@ static inline void _Scheduler_SMP_Add_processor(
* @return The idle thread of @a cpu.
*/
static inline Thread_Control *_Scheduler_SMP_Remove_processor(
- Scheduler_Context *context,
- Per_CPU_Control *cpu,
- Scheduler_SMP_Extract extract_from_scheduled,
- Scheduler_SMP_Extract extract_from_ready,
- Scheduler_SMP_Enqueue enqueue
+ Scheduler_Context *context,
+ Per_CPU_Control *cpu,
+ Scheduler_SMP_Extract extract_from_scheduled,
+ Scheduler_SMP_Extract extract_from_ready,
+ Scheduler_SMP_Enqueue enqueue,
+ Scheduler_Get_idle_node get_idle_node,
+ Scheduler_Release_idle_node release_idle_node
)
{
Scheduler_SMP_Context *self;
@@ -1877,24 +1886,25 @@ static inline Thread_Control *_Scheduler_SMP_Remove_processor(
chain_node = _Chain_Next( chain_node );
} while ( _Thread_Get_CPU( victim_user ) != cpu );
- ( *extract_from_scheduled )( context, victim_node );
+ ( *extract_from_scheduled )( &self->Base, victim_node );
victim_owner = _Scheduler_Node_get_owner( victim_node );
if ( !victim_owner->is_idle ) {
+ Thread_Control *victim_idle;
Scheduler_Node *idle_node;
- _Scheduler_Release_idle_thread(
- &self->Base,
+ victim_idle = _Scheduler_Release_idle_thread_if_necessary(
victim_node,
- _Scheduler_SMP_Release_idle_thread
+ release_idle_node,
+ &self->Base
);
- idle = _Scheduler_SMP_Get_idle_thread( &self->Base );
- idle_node = _Thread_Scheduler_get_home_node( idle );
- ( *extract_from_ready )( &self->Base, idle_node );
+ idle_node = ( *get_idle_node )( &self->Base );
+ idle = _Scheduler_Node_get_owner( idle_node );
_Scheduler_SMP_Preempt(
&self->Base,
idle_node,
victim_node,
+ victim_idle,
_Scheduler_SMP_Allocate_processor_exact
);
@@ -1903,13 +1913,12 @@ static inline Thread_Control *_Scheduler_SMP_Remove_processor(
insert_priority = _Scheduler_SMP_Node_priority( victim_node );
insert_priority = SCHEDULER_PRIORITY_APPEND( insert_priority );
- ( *enqueue )( context, victim_node, insert_priority );
+ ( *enqueue )( &self->Base, victim_node, insert_priority );
}
} else {
_Assert( victim_owner == victim_user );
_Assert( _Scheduler_Node_get_idle( victim_node ) == NULL );
idle = victim_owner;
- _Scheduler_SMP_Extract_idle_thread( idle );
}
return idle;
@@ -1947,7 +1956,9 @@ static inline void _Scheduler_SMP_Set_affinity(
Scheduler_SMP_Get_highest_ready get_highest_ready,
Scheduler_SMP_Move move_from_ready_to_scheduled,
Scheduler_SMP_Enqueue enqueue,
- Scheduler_SMP_Allocate_processor allocate_processor
+ Scheduler_SMP_Allocate_processor allocate_processor,
+ Scheduler_Get_idle_node get_idle_node,
+ Scheduler_Release_idle_node release_idle_node
)
{
Scheduler_SMP_Node_state node_state;
@@ -1962,11 +1973,12 @@ static inline void _Scheduler_SMP_Set_affinity(
_Scheduler_SMP_Preempt_and_schedule_highest_ready(
context,
node,
- _Thread_Get_CPU( thread ),
extract_from_ready,
get_highest_ready,
move_from_ready_to_scheduled,
- allocate_processor
+ allocate_processor,
+ get_idle_node,
+ release_idle_node
);
( *set_affinity )( context, node, arg );
( *enqueue )( context, node, insert_priority );