forked from Imagelibrary/rtems
score: Add _Scheduler_Help()
Manage the help state of threads with respect to scheduling decisions.
This commit is contained in:
@@ -102,6 +102,7 @@ RTEMS_INLINE_ROUTINE void _MRSP_Claim_ownership(
|
|||||||
_Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node );
|
_Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node );
|
||||||
mrsp->initial_priority_of_owner = initial_priority;
|
mrsp->initial_priority_of_owner = initial_priority;
|
||||||
_MRSP_Elevate_priority( mrsp, new_owner, ceiling_priority );
|
_MRSP_Elevate_priority( mrsp, new_owner, ceiling_priority );
|
||||||
|
_Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER );
|
||||||
}
|
}
|
||||||
|
|
||||||
RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Initialize(
|
RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Initialize(
|
||||||
@@ -185,6 +186,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
|
|||||||
MRSP_Rival rival;
|
MRSP_Rival rival;
|
||||||
bool previous_life_protection;
|
bool previous_life_protection;
|
||||||
unsigned int state;
|
unsigned int state;
|
||||||
|
Scheduler_Help_state previous_help_state;
|
||||||
|
|
||||||
_MRSP_Elevate_priority( mrsp, executing, ceiling_priority );
|
_MRSP_Elevate_priority( mrsp, executing, ceiling_priority );
|
||||||
|
|
||||||
@@ -193,6 +195,8 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
|
|||||||
_Chain_Append_unprotected( &mrsp->Rivals, &rival.Node );
|
_Chain_Append_unprotected( &mrsp->Rivals, &rival.Node );
|
||||||
_Resource_Add_rival( &mrsp->Resource, &executing->Resource_node );
|
_Resource_Add_rival( &mrsp->Resource, &executing->Resource_node );
|
||||||
_Resource_Node_set_dependency( &executing->Resource_node, &mrsp->Resource );
|
_Resource_Node_set_dependency( &executing->Resource_node, &mrsp->Resource );
|
||||||
|
previous_help_state =
|
||||||
|
_Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_ACTIVE_RIVAL );
|
||||||
_MRSP_Set_root(
|
_MRSP_Set_root(
|
||||||
&executing->Resource_node,
|
&executing->Resource_node,
|
||||||
_Resource_Node_get_root( owner )
|
_Resource_Node_get_root( owner )
|
||||||
@@ -234,11 +238,10 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
|
|||||||
mrsp->initial_priority_of_owner = initial_priority;
|
mrsp->initial_priority_of_owner = initial_priority;
|
||||||
status = MRSP_SUCCESSFUL;
|
status = MRSP_SUCCESSFUL;
|
||||||
} else {
|
} else {
|
||||||
Resource_Node *executing_node = &executing->Resource_node;
|
_Resource_Node_extract( &executing->Resource_node );
|
||||||
|
_Resource_Node_set_dependency( &executing->Resource_node, NULL );
|
||||||
_Resource_Node_extract( executing_node );
|
_Scheduler_Thread_change_help_state( executing, previous_help_state );
|
||||||
_Resource_Node_set_dependency( executing_node, NULL );
|
_MRSP_Set_root( &executing->Resource_node, &executing->Resource_node );
|
||||||
_MRSP_Set_root( executing_node, executing_node );
|
|
||||||
_MRSP_Restore_priority( mrsp, executing, initial_priority );
|
_MRSP_Restore_priority( mrsp, executing, initial_priority );
|
||||||
|
|
||||||
status = MRSP_TIMEOUT;
|
status = MRSP_TIMEOUT;
|
||||||
@@ -324,16 +327,21 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release(
|
|||||||
_Resource_Set_owner( &mrsp->Resource, NULL );
|
_Resource_Set_owner( &mrsp->Resource, NULL );
|
||||||
} else {
|
} else {
|
||||||
MRSP_Rival *rival = (MRSP_Rival *) _Chain_First( &mrsp->Rivals );
|
MRSP_Rival *rival = (MRSP_Rival *) _Chain_First( &mrsp->Rivals );
|
||||||
Resource_Node *new_owner = &rival->thread->Resource_node;
|
Thread_Control *new_owner = rival->thread;
|
||||||
|
|
||||||
_Resource_Node_extract( new_owner );
|
_Resource_Node_extract( &new_owner->Resource_node );
|
||||||
_Resource_Node_set_dependency( new_owner, NULL );
|
_Resource_Node_set_dependency( &new_owner->Resource_node, NULL );
|
||||||
_Resource_Node_add_resource( new_owner, &mrsp->Resource );
|
_Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource );
|
||||||
_Resource_Set_owner( &mrsp->Resource, new_owner );
|
_Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node );
|
||||||
_MRSP_Set_root( new_owner, new_owner );
|
_Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER );
|
||||||
|
_MRSP_Set_root( &new_owner->Resource_node, &new_owner->Resource_node );
|
||||||
_MRSP_Add_state( rival, MRSP_RIVAL_STATE_NEW_OWNER );
|
_MRSP_Add_state( rival, MRSP_RIVAL_STATE_NEW_OWNER );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( !_Resource_Node_owns_resources( &executing->Resource_node ) ) {
|
||||||
|
_Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_YOURSELF );
|
||||||
|
}
|
||||||
|
|
||||||
return MRSP_SUCCESSFUL;
|
return MRSP_SUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,75 @@ struct Scheduler_Control {
|
|||||||
uint32_t name;
|
uint32_t name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(RTEMS_SMP)
|
||||||
|
/**
|
||||||
|
* @brief State to indicate potential help for other threads.
|
||||||
|
*
|
||||||
|
* @dot
|
||||||
|
* digraph state {
|
||||||
|
* y [label="HELP YOURSELF"];
|
||||||
|
* ao [label="HELP ACTIVE OWNER"];
|
||||||
|
* ar [label="HELP ACTIVE RIVAL"];
|
||||||
|
*
|
||||||
|
* y -> ao [label="obtain"];
|
||||||
|
* y -> ar [label="wait for obtain"];
|
||||||
|
* ao -> y [label="last release"];
|
||||||
|
* ao -> r [label="wait for obtain"];
|
||||||
|
* ar -> r [label="timeout"];
|
||||||
|
* ar -> ao [label="timeout"];
|
||||||
|
* }
|
||||||
|
* @enddot
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
/**
|
||||||
|
* @brief This scheduler node is solely used by the owner thread.
|
||||||
|
*
|
||||||
|
* This thread owns no resources using a helping protocol and thus does not
|
||||||
|
* take part in the scheduler helping protocol. No help will be provided for
|
||||||
|
* other thread.
|
||||||
|
*/
|
||||||
|
SCHEDULER_HELP_YOURSELF,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This scheduler node is owned by a thread actively owning a resource.
|
||||||
|
*
|
||||||
|
* This scheduler node can be used to help out threads.
|
||||||
|
*
|
||||||
|
* In case this scheduler node changes its state from ready to scheduled and
|
||||||
|
* the thread executes using another node, then an idle thread will be
|
||||||
|
* provided as a user of this node to temporarily execute on behalf of the
|
||||||
|
* owner thread. Thus lower priority threads are denied access to the
|
||||||
|
* processors of this scheduler instance.
|
||||||
|
*
|
||||||
|
* In case a thread actively owning a resource performs a blocking operation,
|
||||||
|
* then an idle thread will be used also in case this node is in the
|
||||||
|
* scheduled state.
|
||||||
|
*/
|
||||||
|
SCHEDULER_HELP_ACTIVE_OWNER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This scheduler node is owned by a thread actively obtaining a
|
||||||
|
* resource currently owned by another thread.
|
||||||
|
*
|
||||||
|
* This scheduler node can be used to help out threads.
|
||||||
|
*
|
||||||
|
* The thread owning this node is ready and will give away its processor in
|
||||||
|
* case the thread owning the resource asks for help.
|
||||||
|
*/
|
||||||
|
SCHEDULER_HELP_ACTIVE_RIVAL,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This scheduler node is owned by a thread obtaining a
|
||||||
|
* resource currently owned by another thread.
|
||||||
|
*
|
||||||
|
* This scheduler node can be used to help out threads.
|
||||||
|
*
|
||||||
|
* The thread owning this node is blocked.
|
||||||
|
*/
|
||||||
|
SCHEDULER_HELP_PASSIVE
|
||||||
|
} Scheduler_Help_state;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Scheduler node for per-thread data.
|
* @brief Scheduler node for per-thread data.
|
||||||
*/
|
*/
|
||||||
@@ -178,10 +247,37 @@ struct Scheduler_Node {
|
|||||||
*/
|
*/
|
||||||
Chain_Node Node;
|
Chain_Node Node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The thread using this node.
|
||||||
|
*/
|
||||||
|
Thread_Control *user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The help state of this node.
|
||||||
|
*/
|
||||||
|
Scheduler_Help_state help_state;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The thread owning this node.
|
* @brief The thread owning this node.
|
||||||
*/
|
*/
|
||||||
Thread_Control *owner;
|
Thread_Control *owner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The idle thread claimed by this node in case the help state is
|
||||||
|
* SCHEDULER_HELP_ACTIVE_OWNER.
|
||||||
|
*
|
||||||
|
* Active owners will lend their own node to an idle thread in case they
|
||||||
|
* execute currently using another node or in case they perform a blocking
|
||||||
|
* operation. This is necessary to ensure the priority ceiling protocols
|
||||||
|
* work across scheduler boundaries.
|
||||||
|
*/
|
||||||
|
Thread_Control *idle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The thread accepting help by this node in case the help state is
|
||||||
|
* not SCHEDULER_HELP_YOURSELF.
|
||||||
|
*/
|
||||||
|
Thread_Control *accepts_help;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,15 @@ RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_CPU(
|
|||||||
return _Scheduler_Get_by_CPU_index( cpu_index );
|
return _Scheduler_Get_by_CPU_index( cpu_index );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(RTEMS_SMP)
|
||||||
|
RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Node_get_user(
|
||||||
|
const Scheduler_Node *node
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return node->user;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The preferred method to add a new scheduler is to define the jump table
|
* The preferred method to add a new scheduler is to define the jump table
|
||||||
* entries and add a case to the _Scheduler_Initialize routine.
|
* entries and add a case to the _Scheduler_Initialize routine.
|
||||||
@@ -658,7 +667,11 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Node_do_initialize(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
#if defined(RTEMS_SMP)
|
#if defined(RTEMS_SMP)
|
||||||
|
node->user = the_thread;
|
||||||
|
node->help_state = SCHEDULER_HELP_YOURSELF;
|
||||||
node->owner = the_thread;
|
node->owner = the_thread;
|
||||||
|
node->idle = NULL;
|
||||||
|
node->accepts_help = the_thread;
|
||||||
#else
|
#else
|
||||||
(void) node;
|
(void) node;
|
||||||
(void) the_thread;
|
(void) the_thread;
|
||||||
@@ -672,6 +685,34 @@ RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Node_get_owner(
|
|||||||
{
|
{
|
||||||
return node->owner;
|
return node->owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Node_get_idle(
|
||||||
|
const Scheduler_Node *node
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return node->idle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Changes the scheduler help state of a thread.
|
||||||
|
*
|
||||||
|
* @param[in] the_thread The thread.
|
||||||
|
* @param[in] new_help_state The new help state.
|
||||||
|
*
|
||||||
|
* @return The previous help state.
|
||||||
|
*/
|
||||||
|
RTEMS_INLINE_ROUTINE Scheduler_Help_state _Scheduler_Thread_change_help_state(
|
||||||
|
Thread_Control *the_thread,
|
||||||
|
Scheduler_Help_state new_help_state
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Scheduler_Node *node = _Scheduler_Thread_get_node( the_thread );
|
||||||
|
Scheduler_Help_state previous_help_state = node->help_state;
|
||||||
|
|
||||||
|
node->help_state = new_help_state;
|
||||||
|
|
||||||
|
return previous_help_state;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|||||||
@@ -455,8 +455,8 @@ static inline void _Scheduler_SMP_Allocate_processor(
|
|||||||
Scheduler_SMP_Allocate_processor allocate_processor
|
Scheduler_SMP_Allocate_processor allocate_processor
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Thread_Control *scheduled_thread = _Scheduler_Node_get_owner( scheduled );
|
Thread_Control *scheduled_thread = _Scheduler_Node_get_user( scheduled );
|
||||||
Thread_Control *victim_thread = _Scheduler_Node_get_owner( victim );
|
Thread_Control *victim_thread = _Scheduler_Node_get_user( victim );
|
||||||
|
|
||||||
_Scheduler_SMP_Node_change_state(
|
_Scheduler_SMP_Node_change_state(
|
||||||
_Scheduler_SMP_Node_downcast( scheduled ),
|
_Scheduler_SMP_Node_downcast( scheduled ),
|
||||||
|
|||||||
Reference in New Issue
Block a user