summaryrefslogtreecommitdiffstats
path: root/cpukit/score/include/rtems/score/schedulerimpl.h
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2014-07-04 14:34:23 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2014-07-09 10:05:17 +0200
commit5c3d2509593476869e791111cd3d93cc1e840b3a (patch)
tree2f642fcce66748460f0f823fbeb6f292267b8cd0 /cpukit/score/include/rtems/score/schedulerimpl.h
parentschedulerpriorityaffinitysmp.c: Add period at end of sentence (diff)
downloadrtems-5c3d2509593476869e791111cd3d93cc1e840b3a.tar.bz2
score: Implement scheduler helping protocol
The following scheduler operations return a thread in need for help - unblock, - change priority, and - yield. A thread in need for help is a thread that encounters a scheduler state change from scheduled to ready or a thread that cannot be scheduled in an unblock operation. Such a thread can ask threads which depend on resources owned by this thread for help. Add a new ask for help scheduler operation. This operation is used by _Scheduler_Ask_for_help() to help threads in need for help returned by the operations mentioned above. This operation is also used by _Scheduler_Thread_change_resource_root() in case the root of a resource sub-tree changes. A use case is the ownership change of a resource. In case it is not possible to schedule a thread in need for help, then the corresponding scheduler node will be placed into the set of ready scheduler nodes of the scheduler instance. Once a state change from ready to scheduled happens for this scheduler node it may be used to schedule the thread in need for help.
Diffstat (limited to 'cpukit/score/include/rtems/score/schedulerimpl.h')
-rw-r--r--cpukit/score/include/rtems/score/schedulerimpl.h586
1 files changed, 576 insertions, 10 deletions
diff --git a/cpukit/score/include/rtems/score/schedulerimpl.h b/cpukit/score/include/rtems/score/schedulerimpl.h
index 5e4e5098d2..c41c3af3e6 100644
--- a/cpukit/score/include/rtems/score/schedulerimpl.h
+++ b/cpukit/score/include/rtems/score/schedulerimpl.h
@@ -10,6 +10,7 @@
/*
* Copyright (C) 2010 Gedare Bloom.
* Copyright (C) 2011 On-Line Applications Research Corporation (OAR).
+ * Copyright (c) 2014 embedded brains GmbH
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -42,6 +43,13 @@ extern "C" {
*/
void _Scheduler_Handler_initialization( void );
+RTEMS_INLINE_ROUTINE Scheduler_Context *_Scheduler_Get_context(
+ const Scheduler_Control *scheduler
+)
+{
+ return scheduler->context;
+}
+
RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get(
const Thread_Control *the_thread
)
@@ -55,6 +63,19 @@ RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get(
#endif
}
+RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_own(
+ const Thread_Control *the_thread
+)
+{
+#if defined(RTEMS_SMP)
+ return the_thread->Scheduler.own_control;
+#else
+ (void) the_thread;
+
+ return &_Scheduler_Table[ 0 ];
+#endif
+}
+
RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_CPU_index(
uint32_t cpu_index
)
@@ -78,6 +99,13 @@ RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_CPU(
}
#if defined(RTEMS_SMP)
+RTEMS_INLINE_ROUTINE Scheduler_Node *_Scheduler_Thread_get_own_node(
+ const Thread_Control *the_thread
+)
+{
+ return the_thread->Scheduler.own_node;
+}
+
RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Node_get_user(
const Scheduler_Node *node
)
@@ -117,6 +145,39 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Schedule( Thread_Control *the_thread )
}
#if defined(RTEMS_SMP)
+typedef struct {
+ Thread_Control *needs_help;
+ Thread_Control *next_needs_help;
+} Scheduler_Ask_for_help_context ;
+
+RTEMS_INLINE_ROUTINE bool _Scheduler_Ask_for_help_visitor(
+ Resource_Node *resource_node,
+ void *arg
+)
+{
+ bool done;
+ Scheduler_Ask_for_help_context *help_context = arg;
+ Thread_Control *previous_needs_help = help_context->needs_help;
+ Thread_Control *next_needs_help;
+ Thread_Control *offers_help =
+ _Thread_Resource_node_to_thread( resource_node );
+ const Scheduler_Control *scheduler = _Scheduler_Get_own( offers_help );
+
+ next_needs_help = ( *scheduler->Operations.ask_for_help )(
+ scheduler,
+ offers_help,
+ previous_needs_help
+ );
+
+ done = next_needs_help != previous_needs_help;
+
+ if ( done ) {
+ help_context->next_needs_help = next_needs_help;
+ }
+
+ return done;
+}
+
/**
* @brief Ask threads depending on resources owned by the thread for help.
*
@@ -124,13 +185,56 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Schedule( Thread_Control *the_thread )
* pre-emption by a higher priority thread or it was not possible to assign it
* a processor since its priority is to low on its current scheduler instance.
*
+ * The run-time of this function depends on the size of the resource tree of
+ * the thread needing help and other resource trees in case threads in need for
+ * help are produced during this operation.
+ *
* @param[in] needs_help The thread needing help.
*/
+RTEMS_INLINE_ROUTINE void _Scheduler_Ask_for_help(
+ Thread_Control *needs_help
+)
+{
+ do {
+ const Scheduler_Control *scheduler = _Scheduler_Get_own( needs_help );
+
+ needs_help = ( *scheduler->Operations.ask_for_help )(
+ scheduler,
+ needs_help,
+ needs_help
+ );
+
+ if ( needs_help != NULL ) {
+ Scheduler_Ask_for_help_context help_context = { needs_help, NULL };
+
+ _Resource_Iterate(
+ &needs_help->Resource_node,
+ _Scheduler_Ask_for_help_visitor,
+ &help_context
+ );
+
+ needs_help = help_context.next_needs_help;
+ }
+ } while ( needs_help != NULL );
+}
+
RTEMS_INLINE_ROUTINE void _Scheduler_Ask_for_help_if_necessary(
Thread_Control *needs_help
)
{
- (void) needs_help;
+ if (
+ needs_help != NULL
+ && _Resource_Node_owns_resources( &needs_help->Resource_node )
+ ) {
+ Scheduler_Node *node = _Scheduler_Thread_get_own_node( needs_help );
+
+ if (
+ node->help_state != SCHEDULER_HELP_ACTIVE_RIVAL
+ || _Scheduler_Node_get_user( node ) != needs_help
+ ) {
+ _Scheduler_Ask_for_help( needs_help );
+ }
+ }
}
#endif
@@ -218,7 +322,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Change_priority(
bool prepend_it
)
{
- const Scheduler_Control *scheduler = _Scheduler_Get( the_thread );
+ const Scheduler_Control *scheduler = _Scheduler_Get_own( the_thread );
#if defined(RTEMS_SMP)
Thread_Control *needs_help;
@@ -426,6 +530,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Set(
if ( current_scheduler != scheduler ) {
_Thread_Set_state( the_thread, STATES_MIGRATING );
_Scheduler_Node_destroy( current_scheduler, the_thread );
+ the_thread->Scheduler.own_control = scheduler;
the_thread->Scheduler.control = scheduler;
_Scheduler_Node_initialize( scheduler, the_thread );
_Scheduler_Update_priority( the_thread, the_thread->current_priority );
@@ -628,13 +733,6 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Change_priority_if_higher(
}
}
-RTEMS_INLINE_ROUTINE Scheduler_Context *_Scheduler_Get_context(
- const Scheduler_Control *scheduler
-)
-{
- return scheduler->context;
-}
-
RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_processor_count(
const Scheduler_Control *scheduler
)
@@ -721,6 +819,29 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Node_do_initialize(
}
#if defined(RTEMS_SMP)
+/**
+ * @brief Gets an idle thread from the scheduler instance.
+ *
+ * @param[in] context The scheduler instance context.
+ *
+ * @retval idle An idle thread for use. This function must always return an
+ * idle thread. If none is available, then this is a fatal error.
+ */
+typedef Thread_Control *( *Scheduler_Get_idle_thread )(
+ Scheduler_Context *context
+);
+
+/**
+ * @brief Releases an idle thread to the scheduler instance for reuse.
+ *
+ * @param[in] context The scheduler instance context.
+ * @param[in] idle The idle thread to release
+ */
+typedef void ( *Scheduler_Release_idle_thread )(
+ Scheduler_Context *context,
+ Thread_Control *idle
+);
+
RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Node_get_owner(
const Scheduler_Node *node
)
@@ -735,6 +856,50 @@ RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Node_get_idle(
return node->idle;
}
+RTEMS_INLINE_ROUTINE void _Scheduler_Node_set_user(
+ Scheduler_Node *node,
+ Thread_Control *user
+)
+{
+ node->user = user;
+}
+
+RTEMS_INLINE_ROUTINE void _Scheduler_Thread_set_node(
+ Thread_Control *the_thread,
+ Scheduler_Node *node
+)
+{
+ the_thread->Scheduler.node = node;
+}
+
+RTEMS_INLINE_ROUTINE void _Scheduler_Thread_set_scheduler_and_node(
+ Thread_Control *the_thread,
+ Scheduler_Node *node,
+ const Thread_Control *previous_user_of_node
+)
+{
+ const Scheduler_Control *scheduler =
+ _Scheduler_Get_own( previous_user_of_node );
+
+ the_thread->Scheduler.control = scheduler;
+ _Scheduler_Thread_set_node( the_thread, node );
+}
+
+extern const bool _Scheduler_Thread_state_valid_state_changes[ 3 ][ 3 ];
+
+RTEMS_INLINE_ROUTINE void _Scheduler_Thread_change_state(
+ Thread_Control *the_thread,
+ Thread_Scheduler_state new_state
+)
+{
+ _Assert(
+ _Scheduler_Thread_state_valid_state_changes
+ [ the_thread->Scheduler.state ][ new_state ]
+ );
+
+ the_thread->Scheduler.state = new_state;
+}
+
/**
* @brief Changes the scheduler help state of a thread.
*
@@ -748,13 +913,414 @@ RTEMS_INLINE_ROUTINE Scheduler_Help_state _Scheduler_Thread_change_help_state(
Scheduler_Help_state new_help_state
)
{
- Scheduler_Node *node = _Scheduler_Thread_get_node( the_thread );
+ Scheduler_Node *node = _Scheduler_Thread_get_own_node( the_thread );
Scheduler_Help_state previous_help_state = node->help_state;
node->help_state = new_help_state;
return previous_help_state;
}
+
+/**
+ * @brief Changes the resource tree root of a thread.
+ *
+ * For each node of the resource sub-tree specified by the top thread the
+ * scheduler asks for help. So the root thread gains access to all scheduler
+ * nodes corresponding to the resource sub-tree. In case a thread previously
+ * granted help is displaced by this operation, then the scheduler asks for
+ * help using its remaining resource tree.
+ *
+ * The run-time of this function depends on the size of the resource sub-tree
+ * and other resource trees in case threads in need for help are produced
+ * during this operation.
+ *
+ * @param[in] top The thread specifying the resource sub-tree top.
+ * @param[in] root The thread specifying the new resource sub-tree root.
+ */
+void _Scheduler_Thread_change_resource_root(
+ Thread_Control *top,
+ Thread_Control *root
+);
+
+/**
+ * @brief Use an idle thread for this scheduler node.
+ *
+ * A thread in the SCHEDULER_HELP_ACTIVE_OWNER owner state may use an idle
+ * thread for the scheduler node owned by itself in case it executes currently
+ * using another scheduler node or in case it is in a blocking state.
+ *
+ * @param[in] context The scheduler instance context.
+ * @param[in] node The node which wants to use the idle thread.
+ * @param[in] get_idle_thread Function to get an idle thread.
+ */
+RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Use_idle_thread(
+ Scheduler_Context *context,
+ Scheduler_Node *node,
+ Scheduler_Get_idle_thread get_idle_thread
+)
+{
+ Thread_Control *idle = ( *get_idle_thread )( context );
+
+ _Assert( node->help_state == SCHEDULER_HELP_ACTIVE_OWNER );
+ _Assert( _Scheduler_Node_get_idle( node ) == NULL );
+ _Assert(
+ _Scheduler_Node_get_owner( node ) == _Scheduler_Node_get_user( node )
+ );
+
+ _Scheduler_Thread_set_node( idle, node );
+
+ _Scheduler_Node_set_user( node, idle );
+ node->idle = idle;
+
+ return idle;
+}
+
+/**
+ * @brief Try to schedule this scheduler node.
+ *
+ * @param[in] context The scheduler instance context.
+ * @param[in] node The node which wants to get scheduled.
+ * @param[in] get_idle_thread Function to get an idle thread.
+ *
+ * @retval true This node can be scheduled.
+ * @retval false Otherwise.
+ */
+RTEMS_INLINE_ROUTINE bool _Scheduler_Try_to_schedule_node(
+ Scheduler_Context *context,
+ Scheduler_Node *node,
+ Scheduler_Get_idle_thread get_idle_thread
+)
+{
+ bool schedule;
+ Thread_Control *owner;
+ Thread_Control *user;
+
+ if ( node->help_state == SCHEDULER_HELP_YOURSELF ) {
+ return true;
+ }
+
+ owner = _Scheduler_Node_get_owner( node );
+ user = _Scheduler_Node_get_user( node );
+
+ if ( node->help_state == SCHEDULER_HELP_ACTIVE_RIVAL) {
+ if ( user->Scheduler.state == THREAD_SCHEDULER_READY ) {
+ _Scheduler_Thread_set_scheduler_and_node( user, node, owner );
+ } else {
+ _Scheduler_Node_set_user( node, owner );
+ }
+
+ schedule = true;
+ } else if ( node->help_state == SCHEDULER_HELP_ACTIVE_OWNER ) {
+ if ( user->Scheduler.state == THREAD_SCHEDULER_READY ) {
+ _Scheduler_Thread_set_scheduler_and_node( user, node, owner );
+ } else {
+ _Scheduler_Use_idle_thread( context, node, get_idle_thread );
+ }
+
+ schedule = true;
+ } else {
+ _Assert( node->help_state == SCHEDULER_HELP_PASSIVE );
+
+ if ( user->Scheduler.state == THREAD_SCHEDULER_READY ) {
+ _Scheduler_Thread_set_scheduler_and_node( user, node, owner );
+ schedule = true;
+ } else {
+ schedule = false;
+ }
+ }
+
+ return schedule;
+}
+
+/**
+ * @brief Release an idle thread using this scheduler node.
+ *
+ * @param[in] context The scheduler instance context.
+ * @param[in] node The node which may have an idle thread as user.
+ * @param[in] release_idle_thread Function to release an idle thread.
+ *
+ * @retval idle The idle thread which used this node.
+ * @retval NULL This node had no idle thread as an user.
+ */
+RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Release_idle_thread(
+ Scheduler_Context *context,
+ Scheduler_Node *node,
+ Scheduler_Release_idle_thread release_idle_thread
+)
+{
+ Thread_Control *idle = _Scheduler_Node_get_idle( node );
+
+ if ( idle != NULL ) {
+ Thread_Control *owner = _Scheduler_Node_get_owner( node );
+
+ node->idle = NULL;
+ _Scheduler_Node_set_user( node, owner );
+ _Scheduler_Thread_change_state( idle, THREAD_SCHEDULER_READY );
+ _Scheduler_Thread_set_node( idle, idle->Scheduler.own_node );
+
+ ( *release_idle_thread )( context, idle );
+ }
+
+ return idle;
+}
+
+/**
+ * @brief Block this scheduler node.
+ *
+ * @param[in] context The scheduler instance context.
+ * @param[in] node The node which wants to get blocked.
+ * @param[in] is_scheduled This node is scheduled.
+ * @param[in] get_idle_thread Function to get an idle thread.
+ *
+ * @retval true Continue with the blocking operation.
+ * @retval false Otherwise.
+ */
+RTEMS_INLINE_ROUTINE bool _Scheduler_Block_node(
+ Scheduler_Context *context,
+ Scheduler_Node *node,
+ bool is_scheduled,
+ Scheduler_Get_idle_thread get_idle_thread
+)
+{
+ bool block;
+ Thread_Control *old_user = _Scheduler_Node_get_user( node );
+ Thread_Control *new_user;
+
+ _Scheduler_Thread_change_state( old_user, THREAD_SCHEDULER_BLOCKED );
+
+ if ( node->help_state == SCHEDULER_HELP_ACTIVE_RIVAL ) {
+ new_user = _Scheduler_Node_get_owner( node );
+
+ _Assert( new_user != old_user );
+ _Scheduler_Node_set_user( node, new_user );
+ } else if (
+ node->help_state == SCHEDULER_HELP_ACTIVE_OWNER
+ && is_scheduled
+ ) {
+ new_user = _Scheduler_Use_idle_thread( context, node, get_idle_thread );
+ } else {
+ new_user = NULL;
+ }
+
+ if ( new_user != NULL && is_scheduled ) {
+ Per_CPU_Control *cpu = _Thread_Get_CPU( old_user );
+
+ _Scheduler_Thread_change_state( new_user, THREAD_SCHEDULER_SCHEDULED );
+ _Thread_Set_CPU( new_user, cpu );
+ _Thread_Dispatch_update_heir( _Per_CPU_Get(), cpu, new_user );
+
+ block = false;
+ } else {
+ block = true;
+ }
+
+ return block;
+}
+
+/**
+ * @brief Unblock this scheduler node.
+ *
+ * @param[in] context The scheduler instance context.
+ * @param[in] the_thread The thread which wants to get unblocked.
+ * @param[in] node The node which wants to get unblocked.
+ * @param[in] is_scheduled This node is scheduled.
+ * @param[in] release_idle_thread Function to release an idle thread.
+ *
+ * @retval true Continue with the unblocking operation.
+ * @retval false Otherwise.
+ */
+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
+)
+{
+ bool unblock;
+
+ if ( is_scheduled ) {
+ Thread_Control *old_user = _Scheduler_Node_get_user( node );
+ Per_CPU_Control *cpu = _Thread_Get_CPU( old_user );
+
+ if ( node->help_state == SCHEDULER_HELP_ACTIVE_OWNER ) {
+ Thread_Control *idle = _Scheduler_Release_idle_thread(
+ context,
+ node,
+ release_idle_thread
+ );
+
+ _Assert( idle != NULL );
+ (void) idle;
+ } else {
+ _Assert( node->help_state == SCHEDULER_HELP_ACTIVE_RIVAL );
+
+ _Scheduler_Thread_change_state( old_user, THREAD_SCHEDULER_READY );
+ _Scheduler_Node_set_user( node, the_thread );
+ }
+
+ _Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_SCHEDULED );
+ _Thread_Set_CPU( the_thread, cpu );
+ _Thread_Dispatch_update_heir( _Per_CPU_Get(), cpu, the_thread );
+
+ unblock = false;
+ } else {
+ _Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_READY );
+
+ unblock = true;
+ }
+
+ return unblock;
+}
+
+/**
+ * @brief Asks a ready scheduler node for help.
+ *
+ * @param[in] node The ready node offering help.
+ * @param[in] needs_help The thread needing help.
+ *
+ * @retval needs_help The thread needing help.
+ */
+RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Ask_ready_node_for_help(
+ Scheduler_Node *node,
+ Thread_Control *needs_help
+)
+{
+ _Scheduler_Node_set_user( node, needs_help );
+
+ return needs_help;
+}
+
+/**
+ * @brief Asks a scheduled scheduler node for help.
+ *
+ * @param[in] context The scheduler instance context.
+ * @param[in] node The scheduled node offering help.
+ * @param[in] offers_help The thread offering help.
+ * @param[in] needs_help The thread needing help.
+ * @param[in] previous_accepts_help The previous thread accepting help by this
+ * scheduler node.
+ * @param[in] release_idle_thread Function to release an idle thread.
+ *
+ * @retval needs_help The previous thread accepting help by this scheduler node
+ * which was displaced by the thread needing help.
+ * @retval NULL There are no more threads needing help.
+ */
+RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Ask_scheduled_node_for_help(
+ Scheduler_Context *context,
+ Scheduler_Node *node,
+ Thread_Control *offers_help,
+ Thread_Control *needs_help,
+ Thread_Control *previous_accepts_help,
+ Scheduler_Release_idle_thread release_idle_thread
+)
+{
+ Thread_Control *next_needs_help = NULL;
+ Thread_Control *old_user = NULL;
+ Thread_Control *new_user = NULL;
+
+ if (
+ previous_accepts_help != needs_help
+ && _Scheduler_Thread_get_node( previous_accepts_help ) == node
+ ) {
+ Thread_Control *idle = _Scheduler_Release_idle_thread(
+ context,
+ node,
+ release_idle_thread
+ );
+
+ if ( idle != NULL ) {
+ old_user = idle;
+ } else {
+ _Assert( _Scheduler_Node_get_user( node ) == previous_accepts_help );
+ old_user = previous_accepts_help;
+ }
+
+ if ( needs_help->Scheduler.state == THREAD_SCHEDULER_READY ) {
+ new_user = needs_help;
+ } else {
+ _Assert( node->help_state == SCHEDULER_HELP_ACTIVE_RIVAL );
+ _Assert( offers_help->Scheduler.node == offers_help->Scheduler.own_node );
+
+ new_user = offers_help;
+ }
+
+ if ( previous_accepts_help != offers_help ) {
+ next_needs_help = previous_accepts_help;
+ }
+ } else if ( needs_help->Scheduler.state == THREAD_SCHEDULER_READY ) {
+ Thread_Control *idle = _Scheduler_Release_idle_thread(
+ context,
+ node,
+ release_idle_thread
+ );
+
+ if ( idle != NULL ) {
+ old_user = idle;
+ } else {
+ old_user = _Scheduler_Node_get_user( node );
+ }
+
+ new_user = needs_help;
+ } else {
+ _Assert( needs_help->Scheduler.state == THREAD_SCHEDULER_SCHEDULED );
+ }
+
+ if ( new_user != old_user ) {
+ Per_CPU_Control *cpu_self = _Per_CPU_Get();
+ Per_CPU_Control *cpu = _Thread_Get_CPU( old_user );
+
+ _Scheduler_Thread_change_state( old_user, THREAD_SCHEDULER_READY );
+ _Scheduler_Thread_set_scheduler_and_node(
+ old_user,
+ _Scheduler_Thread_get_own_node( old_user ),
+ old_user
+ );
+
+ _Scheduler_Thread_change_state( new_user, THREAD_SCHEDULER_SCHEDULED );
+ _Scheduler_Thread_set_scheduler_and_node( new_user, node, offers_help );
+
+ _Scheduler_Node_set_user( node, new_user );
+ _Thread_Set_CPU( new_user, cpu );
+ _Thread_Dispatch_update_heir( cpu_self, cpu, new_user );
+ }
+
+ return next_needs_help;
+}
+
+/**
+ * @brief Asks a blocked scheduler node for help.
+ *
+ * @param[in] context The scheduler instance context.
+ * @param[in] node The scheduled node offering help.
+ * @param[in] offers_help The thread offering help.
+ * @param[in] needs_help The thread needing help.
+ *
+ * @retval true Enqueue this scheduler node.
+ * @retval false Otherwise.
+ */
+RTEMS_INLINE_ROUTINE bool _Scheduler_Ask_blocked_node_for_help(
+ Scheduler_Context *context,
+ Scheduler_Node *node,
+ Thread_Control *offers_help,
+ Thread_Control *needs_help
+)
+{
+ bool enqueue;
+
+ _Assert( node->help_state == SCHEDULER_HELP_PASSIVE );
+
+ if ( needs_help->Scheduler.state == THREAD_SCHEDULER_READY ) {
+ _Scheduler_Node_set_user( node, needs_help );
+ _Scheduler_Thread_set_scheduler_and_node( needs_help, node, offers_help );
+
+ enqueue = true;
+ } else {
+ enqueue = false;
+ }
+
+ return enqueue;
+}
#endif
/** @} */