forked from Imagelibrary/rtems
@@ -483,6 +483,9 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Priority_and_sticky_update(
|
|||||||
|
|
||||||
_Scheduler_Acquire_critical( scheduler, &lock_context );
|
_Scheduler_Acquire_critical( scheduler, &lock_context );
|
||||||
|
|
||||||
|
scheduler_node->sticky_level += sticky_level_change;
|
||||||
|
_Assert( scheduler_node->sticky_level >= 0 );
|
||||||
|
|
||||||
( *scheduler->Operations.update_priority )(
|
( *scheduler->Operations.update_priority )(
|
||||||
scheduler,
|
scheduler,
|
||||||
the_thread,
|
the_thread,
|
||||||
@@ -929,27 +932,6 @@ typedef void ( *Scheduler_Release_idle_thread )(
|
|||||||
Thread_Control *idle
|
Thread_Control *idle
|
||||||
);
|
);
|
||||||
|
|
||||||
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 ];
|
extern const bool _Scheduler_Thread_state_valid_state_changes[ 3 ][ 3 ];
|
||||||
|
|
||||||
RTEMS_INLINE_ROUTINE void _Scheduler_Thread_change_state(
|
RTEMS_INLINE_ROUTINE void _Scheduler_Thread_change_state(
|
||||||
@@ -975,17 +957,11 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Set_idle_thread(
|
|||||||
Thread_Control *idle
|
Thread_Control *idle
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_Assert(
|
|
||||||
node->help_state == SCHEDULER_HELP_ACTIVE_OWNER
|
|
||||||
|| node->help_state == SCHEDULER_HELP_ACTIVE_RIVAL
|
|
||||||
);
|
|
||||||
_Assert( _Scheduler_Node_get_idle( node ) == NULL );
|
_Assert( _Scheduler_Node_get_idle( node ) == NULL );
|
||||||
_Assert(
|
_Assert(
|
||||||
_Scheduler_Node_get_owner( node ) == _Scheduler_Node_get_user( node )
|
_Scheduler_Node_get_owner( node ) == _Scheduler_Node_get_user( node )
|
||||||
);
|
);
|
||||||
|
|
||||||
_Scheduler_Thread_set_node( idle, node );
|
|
||||||
|
|
||||||
_Scheduler_Node_set_user( node, idle );
|
_Scheduler_Node_set_user( node, idle );
|
||||||
node->idle = idle;
|
node->idle = idle;
|
||||||
}
|
}
|
||||||
@@ -993,25 +969,27 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Set_idle_thread(
|
|||||||
/**
|
/**
|
||||||
* @brief Use an idle thread for this scheduler node.
|
* @brief Use an idle thread for this scheduler node.
|
||||||
*
|
*
|
||||||
* A thread in the SCHEDULER_HELP_ACTIVE_OWNER or SCHEDULER_HELP_ACTIVE_RIVAL
|
* A thread those home scheduler node has a sticky level greater than zero may
|
||||||
* helping state may use an idle thread for the scheduler node owned by itself
|
* use an idle thread in the home scheduler instance in case it executes
|
||||||
* in case it executes currently using another scheduler node or in case it is
|
* currently in another scheduler instance or in case it is in a blocking
|
||||||
* in a blocking state.
|
* state.
|
||||||
*
|
*
|
||||||
* @param[in] context The scheduler instance context.
|
* @param[in] context The scheduler instance context.
|
||||||
* @param[in] node The node which wants to use the idle thread.
|
* @param[in] node The node which wants to use the idle thread.
|
||||||
|
* @param[in] cpu The processor for the idle thread.
|
||||||
* @param[in] get_idle_thread Function to get an idle thread.
|
* @param[in] get_idle_thread Function to get an idle thread.
|
||||||
*/
|
*/
|
||||||
RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Use_idle_thread(
|
RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Use_idle_thread(
|
||||||
Scheduler_Context *context,
|
Scheduler_Context *context,
|
||||||
Scheduler_Node *node,
|
Scheduler_Node *node,
|
||||||
|
Per_CPU_Control *cpu,
|
||||||
Scheduler_Get_idle_thread get_idle_thread
|
Scheduler_Get_idle_thread get_idle_thread
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Thread_Control *idle = ( *get_idle_thread )( context );
|
Thread_Control *idle = ( *get_idle_thread )( context );
|
||||||
|
|
||||||
_Scheduler_Set_idle_thread( node, idle );
|
_Scheduler_Set_idle_thread( node, idle );
|
||||||
|
_Thread_Set_CPU( idle, cpu );
|
||||||
return idle;
|
return idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1042,7 +1020,6 @@ _Scheduler_Try_to_schedule_node(
|
|||||||
{
|
{
|
||||||
ISR_lock_Context lock_context;
|
ISR_lock_Context lock_context;
|
||||||
Scheduler_Try_to_schedule_action action;
|
Scheduler_Try_to_schedule_action action;
|
||||||
Thread_Control *owner;
|
|
||||||
Thread_Control *user;
|
Thread_Control *user;
|
||||||
|
|
||||||
action = SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE;
|
action = SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE;
|
||||||
@@ -1050,52 +1027,23 @@ _Scheduler_Try_to_schedule_node(
|
|||||||
|
|
||||||
_Thread_Scheduler_acquire_critical( user, &lock_context );
|
_Thread_Scheduler_acquire_critical( user, &lock_context );
|
||||||
|
|
||||||
if ( node->help_state == SCHEDULER_HELP_YOURSELF ) {
|
|
||||||
if ( user->Scheduler.state == THREAD_SCHEDULER_READY ) {
|
if ( user->Scheduler.state == THREAD_SCHEDULER_READY ) {
|
||||||
_Thread_Scheduler_cancel_need_for_help( user, _Thread_Get_CPU( user ) );
|
_Thread_Scheduler_cancel_need_for_help( user, _Thread_Get_CPU( user ) );
|
||||||
_Scheduler_Thread_change_state( user, THREAD_SCHEDULER_SCHEDULED );
|
_Scheduler_Thread_change_state( user, THREAD_SCHEDULER_SCHEDULED );
|
||||||
} else {
|
} else if (
|
||||||
|
user->Scheduler.state == THREAD_SCHEDULER_SCHEDULED
|
||||||
|
|| node->sticky_level == 0
|
||||||
|
) {
|
||||||
action = SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK;
|
action = SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK;
|
||||||
}
|
|
||||||
|
|
||||||
_Thread_Scheduler_release_critical( user, &lock_context );
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
|
|
||||||
owner = _Scheduler_Node_get_owner( 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 if ( owner->Scheduler.state == THREAD_SCHEDULER_BLOCKED ) {
|
|
||||||
if ( idle != NULL ) {
|
|
||||||
action = SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE;
|
|
||||||
} else {
|
|
||||||
_Scheduler_Use_idle_thread( context, node, get_idle_thread );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_Scheduler_Node_set_user( node, owner );
|
|
||||||
}
|
|
||||||
} 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 if ( idle != NULL ) {
|
} else if ( idle != NULL ) {
|
||||||
action = SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE;
|
action = SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE;
|
||||||
} else {
|
} else {
|
||||||
_Scheduler_Use_idle_thread( context, node, get_idle_thread );
|
_Scheduler_Use_idle_thread(
|
||||||
}
|
context,
|
||||||
} else {
|
node,
|
||||||
_Assert( node->help_state == SCHEDULER_HELP_PASSIVE );
|
_Thread_Get_CPU( user ),
|
||||||
|
get_idle_thread
|
||||||
if ( user->Scheduler.state == THREAD_SCHEDULER_READY ) {
|
);
|
||||||
_Scheduler_Thread_set_scheduler_and_node( user, node, owner );
|
|
||||||
} else {
|
|
||||||
action = SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( action == SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE ) {
|
|
||||||
_Scheduler_Thread_change_state( user, THREAD_SCHEDULER_SCHEDULED );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_Thread_Scheduler_release_critical( user, &lock_context );
|
_Thread_Scheduler_release_critical( user, &lock_context );
|
||||||
@@ -1125,9 +1073,6 @@ RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Release_idle_thread(
|
|||||||
|
|
||||||
node->idle = NULL;
|
node->idle = NULL;
|
||||||
_Scheduler_Node_set_user( node, owner );
|
_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 );
|
( *release_idle_thread )( context, idle );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1171,63 +1116,63 @@ RTEMS_INLINE_ROUTINE Per_CPU_Control *_Scheduler_Block_node(
|
|||||||
Scheduler_Get_idle_thread get_idle_thread
|
Scheduler_Get_idle_thread get_idle_thread
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
int sticky_level;
|
||||||
ISR_lock_Context lock_context;
|
ISR_lock_Context lock_context;
|
||||||
Thread_Control *old_user;
|
|
||||||
Thread_Control *new_user;
|
|
||||||
Per_CPU_Control *thread_cpu;
|
Per_CPU_Control *thread_cpu;
|
||||||
|
|
||||||
|
sticky_level = node->sticky_level;
|
||||||
|
--sticky_level;
|
||||||
|
node->sticky_level = sticky_level;
|
||||||
|
_Assert( sticky_level >= 0 );
|
||||||
|
|
||||||
_Thread_Scheduler_acquire_critical( thread, &lock_context );
|
_Thread_Scheduler_acquire_critical( thread, &lock_context );
|
||||||
thread_cpu = _Thread_Get_CPU( thread );
|
thread_cpu = _Thread_Get_CPU( thread );
|
||||||
_Thread_Scheduler_cancel_need_for_help( thread, thread_cpu );
|
_Thread_Scheduler_cancel_need_for_help( thread, thread_cpu );
|
||||||
_Scheduler_Thread_change_state( thread, THREAD_SCHEDULER_BLOCKED );
|
_Scheduler_Thread_change_state( thread, THREAD_SCHEDULER_BLOCKED );
|
||||||
_Thread_Scheduler_release_critical( thread, &lock_context );
|
_Thread_Scheduler_release_critical( thread, &lock_context );
|
||||||
|
|
||||||
if ( node->help_state == SCHEDULER_HELP_YOURSELF ) {
|
if ( sticky_level > 0 ) {
|
||||||
_Assert( thread == _Scheduler_Node_get_user( node ) );
|
if ( is_scheduled && _Scheduler_Node_get_idle( node ) == NULL ) {
|
||||||
|
Thread_Control *idle;
|
||||||
|
|
||||||
return thread_cpu;
|
idle = _Scheduler_Use_idle_thread(
|
||||||
}
|
context,
|
||||||
|
node,
|
||||||
new_user = NULL;
|
thread_cpu,
|
||||||
|
get_idle_thread
|
||||||
if ( node->help_state == SCHEDULER_HELP_ACTIVE_OWNER ) {
|
);
|
||||||
if ( is_scheduled ) {
|
_Thread_Dispatch_update_heir( _Per_CPU_Get(), thread_cpu, idle );
|
||||||
_Assert( thread == _Scheduler_Node_get_user( node ) );
|
|
||||||
old_user = thread;
|
|
||||||
new_user = _Scheduler_Use_idle_thread( context, node, get_idle_thread );
|
|
||||||
}
|
|
||||||
} else if ( node->help_state == SCHEDULER_HELP_ACTIVE_RIVAL ) {
|
|
||||||
if ( is_scheduled ) {
|
|
||||||
old_user = _Scheduler_Node_get_user( node );
|
|
||||||
|
|
||||||
if ( thread == old_user ) {
|
|
||||||
Thread_Control *owner = _Scheduler_Node_get_owner( node );
|
|
||||||
|
|
||||||
if (
|
|
||||||
thread != owner
|
|
||||||
&& owner->Scheduler.state == THREAD_SCHEDULER_READY
|
|
||||||
) {
|
|
||||||
new_user = owner;
|
|
||||||
_Scheduler_Node_set_user( node, new_user );
|
|
||||||
} else {
|
|
||||||
new_user = _Scheduler_Use_idle_thread( context, node, get_idle_thread );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Not implemented, this is part of the OMIP support path. */
|
|
||||||
_Assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( new_user != NULL ) {
|
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_Assert( thread == _Scheduler_Node_get_user( node ) );
|
||||||
|
return thread_cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 *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 );
|
||||||
|
|
||||||
|
cpu = _Thread_Get_CPU( idle );
|
||||||
|
_Thread_Set_CPU( the_thread, cpu );
|
||||||
|
_Thread_Dispatch_update_heir( _Per_CPU_Get(), cpu, the_thread );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1252,46 +1197,20 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_Unblock_node(
|
|||||||
{
|
{
|
||||||
bool unblock;
|
bool unblock;
|
||||||
|
|
||||||
|
++node->sticky_level;
|
||||||
|
_Assert( node->sticky_level > 0 );
|
||||||
|
|
||||||
if ( is_scheduled ) {
|
if ( is_scheduled ) {
|
||||||
Thread_Control *old_user = _Scheduler_Node_get_user( node );
|
_Scheduler_Discard_idle_thread(
|
||||||
Per_CPU_Control *cpu = _Thread_Get_CPU( old_user );
|
|
||||||
Thread_Control *idle = _Scheduler_Release_idle_thread(
|
|
||||||
context,
|
context,
|
||||||
|
the_thread,
|
||||||
node,
|
node,
|
||||||
release_idle_thread
|
release_idle_thread
|
||||||
);
|
);
|
||||||
Thread_Control *owner = _Scheduler_Node_get_owner( node );
|
_Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_SCHEDULED );
|
||||||
Thread_Control *new_user;
|
|
||||||
|
|
||||||
if ( node->help_state == SCHEDULER_HELP_ACTIVE_OWNER ) {
|
|
||||||
_Assert( idle != NULL );
|
|
||||||
new_user = the_thread;
|
|
||||||
} else if ( idle != NULL ) {
|
|
||||||
_Assert( node->help_state == SCHEDULER_HELP_ACTIVE_RIVAL );
|
|
||||||
new_user = the_thread;
|
|
||||||
} else if ( the_thread != owner ) {
|
|
||||||
_Assert( node->help_state == SCHEDULER_HELP_ACTIVE_RIVAL );
|
|
||||||
_Assert( old_user != the_thread );
|
|
||||||
_Scheduler_Thread_change_state( owner, THREAD_SCHEDULER_READY );
|
|
||||||
new_user = the_thread;
|
|
||||||
_Scheduler_Node_set_user( node, new_user );
|
|
||||||
} else {
|
|
||||||
_Assert( node->help_state == SCHEDULER_HELP_ACTIVE_RIVAL );
|
|
||||||
_Assert( old_user != the_thread );
|
|
||||||
_Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_READY );
|
|
||||||
new_user = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( new_user != NULL ) {
|
|
||||||
_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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
unblock = false;
|
unblock = false;
|
||||||
} else {
|
} else {
|
||||||
_Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_READY );
|
_Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_READY );
|
||||||
|
|
||||||
unblock = true;
|
unblock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1372,6 +1291,23 @@ RTEMS_INLINE_ROUTINE Status_Control _Scheduler_Set(
|
|||||||
);
|
);
|
||||||
|
|
||||||
#if defined(RTEMS_SMP)
|
#if defined(RTEMS_SMP)
|
||||||
|
{
|
||||||
|
const Scheduler_Control *old_scheduler;
|
||||||
|
|
||||||
|
old_scheduler = _Scheduler_Get( the_thread );
|
||||||
|
|
||||||
|
if ( old_scheduler != new_scheduler ) {
|
||||||
|
States_Control current_state;
|
||||||
|
|
||||||
|
current_state = the_thread->current_state;
|
||||||
|
|
||||||
|
if ( _States_Is_ready( current_state ) ) {
|
||||||
|
_Scheduler_Block( the_thread );
|
||||||
|
}
|
||||||
|
|
||||||
|
_Assert( old_scheduler_node->sticky_level == 0 );
|
||||||
|
_Assert( new_scheduler_node->sticky_level == 0 );
|
||||||
|
|
||||||
_Chain_Extract_unprotected( &old_scheduler_node->Thread.Wait_node );
|
_Chain_Extract_unprotected( &old_scheduler_node->Thread.Wait_node );
|
||||||
_Assert( _Chain_Is_empty( &the_thread->Scheduler.Wait_nodes ) );
|
_Assert( _Chain_Is_empty( &the_thread->Scheduler.Wait_nodes ) );
|
||||||
_Chain_Initialize_one(
|
_Chain_Initialize_one(
|
||||||
@@ -1387,20 +1323,6 @@ RTEMS_INLINE_ROUTINE Status_Control _Scheduler_Set(
|
|||||||
&new_scheduler_node->Thread.Scheduler_node.Chain
|
&new_scheduler_node->Thread.Scheduler_node.Chain
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
|
||||||
const Scheduler_Control *old_scheduler;
|
|
||||||
|
|
||||||
old_scheduler = _Scheduler_Get( the_thread );
|
|
||||||
|
|
||||||
if ( old_scheduler != new_scheduler ) {
|
|
||||||
States_Control current_state;
|
|
||||||
|
|
||||||
current_state = the_thread->current_state;
|
|
||||||
|
|
||||||
if ( _States_Is_ready( current_state ) ) {
|
|
||||||
_Scheduler_Block( the_thread );
|
|
||||||
}
|
|
||||||
|
|
||||||
the_thread->Scheduler.own_control = new_scheduler;
|
the_thread->Scheduler.own_control = new_scheduler;
|
||||||
the_thread->Scheduler.control = new_scheduler;
|
the_thread->Scheduler.control = new_scheduler;
|
||||||
the_thread->Scheduler.own_node = new_scheduler_node;
|
the_thread->Scheduler.own_node = new_scheduler_node;
|
||||||
|
|||||||
@@ -26,75 +26,6 @@ struct _Thread_Control;
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
#if defined(RTEMS_SMP)
|
#if defined(RTEMS_SMP)
|
||||||
/**
|
/**
|
||||||
* @brief The scheduler node requests.
|
* @brief The scheduler node requests.
|
||||||
@@ -145,27 +76,37 @@ struct Scheduler_Node {
|
|||||||
*/
|
*/
|
||||||
Chain_Node Node;
|
Chain_Node Node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The sticky level determines if this scheduler node should use an
|
||||||
|
* idle thread in case this node is scheduled and the owner thread is
|
||||||
|
* blocked.
|
||||||
|
*/
|
||||||
|
int sticky_level;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The thread using this node.
|
* @brief The thread using this node.
|
||||||
|
*
|
||||||
|
* This is either the owner or an idle thread.
|
||||||
*/
|
*/
|
||||||
struct _Thread_Control *user;
|
struct _Thread_Control *user;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The help state of this node.
|
* @brief The idle thread claimed by this node in case the sticky level is
|
||||||
*/
|
* greater than zero and the thread is block or is scheduled on another
|
||||||
Scheduler_Help_state help_state;
|
* scheduler instance.
|
||||||
|
|
||||||
/**
|
|
||||||
* @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
|
* This is necessary to ensure the priority ceiling protocols work across
|
||||||
* execute currently using another node or in case they perform a blocking
|
* scheduler boundaries.
|
||||||
* operation. This is necessary to ensure the priority ceiling protocols
|
|
||||||
* work across scheduler boundaries.
|
|
||||||
*/
|
*/
|
||||||
struct _Thread_Control *idle;
|
struct _Thread_Control *idle;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The thread owning this node.
|
||||||
|
*/
|
||||||
|
struct _Thread_Control *owner;
|
||||||
|
|
||||||
|
#if defined(RTEMS_SMP)
|
||||||
/**
|
/**
|
||||||
* @brief The thread accepting help by this node in case the help state is
|
* @brief The thread accepting help by this node in case the help state is
|
||||||
* not SCHEDULER_HELP_YOURSELF.
|
* not SCHEDULER_HELP_YOURSELF.
|
||||||
@@ -221,11 +162,6 @@ struct Scheduler_Node {
|
|||||||
Priority_Aggregation Priority;
|
Priority_Aggregation Priority;
|
||||||
} Wait;
|
} Wait;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The thread owning this node.
|
|
||||||
*/
|
|
||||||
struct _Thread_Control *owner;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The thread priority information used by the scheduler.
|
* @brief The thread priority information used by the scheduler.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Node_do_initialize(
|
|||||||
_Chain_Initialize_node( &node->Thread.Wait_node );
|
_Chain_Initialize_node( &node->Thread.Wait_node );
|
||||||
node->Wait.Priority.scheduler = scheduler;
|
node->Wait.Priority.scheduler = scheduler;
|
||||||
node->user = the_thread;
|
node->user = the_thread;
|
||||||
node->help_state = SCHEDULER_HELP_YOURSELF;
|
|
||||||
node->idle = NULL;
|
node->idle = NULL;
|
||||||
node->accepts_help = the_thread;
|
node->accepts_help = the_thread;
|
||||||
_SMP_sequence_lock_Initialize( &node->Priority.Lock );
|
_SMP_sequence_lock_Initialize( &node->Priority.Lock );
|
||||||
|
|||||||
@@ -781,8 +781,36 @@ static inline Thread_Control *_Scheduler_SMP_Enqueue_scheduled_ordered(
|
|||||||
* The node has been extracted from the scheduled chain. We have to place
|
* The node has been extracted from the scheduled chain. We have to place
|
||||||
* it now on the scheduled or ready set.
|
* it now on the scheduled or ready set.
|
||||||
*/
|
*/
|
||||||
if ( ( *order )( &node->Node, &highest_ready->Node ) ) {
|
if (
|
||||||
|
node->sticky_level > 0
|
||||||
|
&& ( *order )( &node->Node, &highest_ready->Node )
|
||||||
|
) {
|
||||||
( *insert_scheduled )( context, node );
|
( *insert_scheduled )( context, node );
|
||||||
|
|
||||||
|
if ( _Scheduler_Node_get_idle( node ) != NULL ) {
|
||||||
|
Thread_Control *owner;
|
||||||
|
ISR_lock_Context lock_context;
|
||||||
|
|
||||||
|
owner = _Scheduler_Node_get_owner( node );
|
||||||
|
_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_Discard_idle_thread(
|
||||||
|
context,
|
||||||
|
owner,
|
||||||
|
node,
|
||||||
|
_Scheduler_SMP_Release_idle_thread
|
||||||
|
);
|
||||||
|
_Scheduler_Thread_change_state( owner, THREAD_SCHEDULER_SCHEDULED );
|
||||||
|
}
|
||||||
|
|
||||||
|
_Thread_Scheduler_release_critical( owner, &lock_context );
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -992,10 +1020,7 @@ static inline Thread_Control *_Scheduler_SMP_Unblock(
|
|||||||
needs_help = ( *enqueue_fifo )( context, node, thread );
|
needs_help = ( *enqueue_fifo )( context, node, thread );
|
||||||
} else {
|
} else {
|
||||||
_Assert( node_state == SCHEDULER_SMP_NODE_READY );
|
_Assert( node_state == SCHEDULER_SMP_NODE_READY );
|
||||||
_Assert(
|
_Assert( node->sticky_level > 0 );
|
||||||
node->help_state == SCHEDULER_HELP_ACTIVE_OWNER
|
|
||||||
|| node->help_state == SCHEDULER_HELP_ACTIVE_RIVAL
|
|
||||||
);
|
|
||||||
_Assert( node->idle == NULL );
|
_Assert( node->idle == NULL );
|
||||||
|
|
||||||
if ( node->accepts_help == thread ) {
|
if ( node->accepts_help == thread ) {
|
||||||
@@ -1146,10 +1171,12 @@ static inline bool _Scheduler_SMP_Ask_for_help(
|
|||||||
|
|
||||||
_Thread_Scheduler_acquire_critical( thread, &lock_context );
|
_Thread_Scheduler_acquire_critical( thread, &lock_context );
|
||||||
|
|
||||||
if (
|
if ( thread->Scheduler.state == THREAD_SCHEDULER_READY ) {
|
||||||
thread->Scheduler.state == THREAD_SCHEDULER_READY
|
Scheduler_SMP_Node_state node_state;
|
||||||
&& _Scheduler_SMP_Node_state( node ) == SCHEDULER_SMP_NODE_BLOCKED
|
|
||||||
) {
|
node_state = _Scheduler_SMP_Node_state( node );
|
||||||
|
|
||||||
|
if ( node_state == SCHEDULER_SMP_NODE_BLOCKED ) {
|
||||||
if ( ( *order )( &node->Node, &lowest_scheduled->Node ) ) {
|
if ( ( *order )( &node->Node, &lowest_scheduled->Node ) ) {
|
||||||
_Thread_Scheduler_cancel_need_for_help(
|
_Thread_Scheduler_cancel_need_for_help(
|
||||||
thread,
|
thread,
|
||||||
@@ -1180,6 +1207,24 @@ static inline bool _Scheduler_SMP_Ask_for_help(
|
|||||||
( *insert_ready )( context, node );
|
( *insert_ready )( context, node );
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
} else if ( node_state == SCHEDULER_SMP_NODE_SCHEDULED ) {
|
||||||
|
_Thread_Scheduler_cancel_need_for_help(
|
||||||
|
thread,
|
||||||
|
_Thread_Get_CPU( thread )
|
||||||
|
);
|
||||||
|
_Scheduler_Discard_idle_thread(
|
||||||
|
context,
|
||||||
|
thread,
|
||||||
|
node,
|
||||||
|
_Scheduler_SMP_Release_idle_thread
|
||||||
|
);
|
||||||
|
_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 );
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_Thread_Scheduler_release_critical( thread, &lock_context );
|
_Thread_Scheduler_release_critical( thread, &lock_context );
|
||||||
success = false;
|
success = false;
|
||||||
@@ -1202,6 +1247,7 @@ static inline void _Scheduler_SMP_Reconsider_help_request(
|
|||||||
if (
|
if (
|
||||||
thread->Scheduler.state == THREAD_SCHEDULER_SCHEDULED
|
thread->Scheduler.state == THREAD_SCHEDULER_SCHEDULED
|
||||||
&& _Scheduler_SMP_Node_state( node ) == SCHEDULER_SMP_NODE_READY
|
&& _Scheduler_SMP_Node_state( node ) == SCHEDULER_SMP_NODE_READY
|
||||||
|
&& node->sticky_level == 1
|
||||||
) {
|
) {
|
||||||
_Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_BLOCKED );
|
_Scheduler_SMP_Node_change_state( node, SCHEDULER_SMP_NODE_BLOCKED );
|
||||||
( *extract_from_ready )( context, node );
|
( *extract_from_ready )( context, node );
|
||||||
|
|||||||
@@ -577,6 +577,13 @@ void _Thread_Priority_replace(
|
|||||||
*/
|
*/
|
||||||
void _Thread_Priority_update( Thread_queue_Context *queue_context );
|
void _Thread_Priority_update( Thread_queue_Context *queue_context );
|
||||||
|
|
||||||
|
#if defined(RTEMS_SMP)
|
||||||
|
void _Thread_Priority_and_sticky_update(
|
||||||
|
Thread_Control *the_thread,
|
||||||
|
int sticky_level_change
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns true if the left thread priority is less than the right
|
* @brief Returns true if the left thread priority is less than the right
|
||||||
* thread priority in the intuitive sense of priority and false otherwise.
|
* thread priority in the intuitive sense of priority and false otherwise.
|
||||||
|
|||||||
@@ -334,14 +334,6 @@ static void _Scheduler_priority_affinity_SMP_Check_for_migrations(
|
|||||||
if ( lowest_scheduled == NULL )
|
if ( lowest_scheduled == NULL )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME: Do not consider threads using the scheduler helping protocol
|
|
||||||
* since this could produce more than one thread in need for help in one
|
|
||||||
* operation which is currently not possible.
|
|
||||||
*/
|
|
||||||
if ( lowest_scheduled->help_state != SCHEDULER_HELP_YOURSELF )
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* But if we found a thread which is lower priority than one
|
* But if we found a thread which is lower priority than one
|
||||||
* in the ready set, then we need to swap them out.
|
* in the ready set, then we need to swap them out.
|
||||||
|
|||||||
@@ -1430,11 +1430,6 @@ static void test_mrsp_obtain_and_release_with_help(test_context *ctx)
|
|||||||
|
|
||||||
rtems_test_assert(rtems_get_current_processor() == 1);
|
rtems_test_assert(rtems_get_current_processor() == 1);
|
||||||
|
|
||||||
sc = rtems_task_wake_after(2);
|
|
||||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
||||||
|
|
||||||
rtems_test_assert(rtems_get_current_processor() == 1);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* With this operation the scheduler instance 0 has now only the main and the
|
* With this operation the scheduler instance 0 has now only the main and the
|
||||||
* idle threads in the ready set.
|
* idle threads in the ready set.
|
||||||
|
|||||||
Reference in New Issue
Block a user