mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-09-20 23:12:22 +08:00
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.
This commit is contained in:
@@ -133,13 +133,15 @@ endif
|
||||
if HAS_SMP
|
||||
libscore_a_SOURCES += src/percpustatewait.c
|
||||
libscore_a_SOURCES += src/profilingsmplock.c
|
||||
libscore_a_SOURCES += src/schedulersmpvalidstatechanges.c
|
||||
libscore_a_SOURCES += src/schedulerchangeroot.c
|
||||
libscore_a_SOURCES += src/schedulerpriorityaffinitysmp.c
|
||||
libscore_a_SOURCES += src/schedulerprioritysmp.c
|
||||
libscore_a_SOURCES += src/schedulersimplesmp.c
|
||||
libscore_a_SOURCES += src/schedulersmpdebug.c
|
||||
libscore_a_SOURCES += src/smp.c
|
||||
libscore_a_SOURCES += src/cpuset.c
|
||||
libscore_a_SOURCES += src/cpusetprintsupport.c
|
||||
libscore_a_SOURCES += src/schedulerdefaultaskforhelp.c
|
||||
libscore_a_SOURCES += src/schedulerdefaultgetaffinity.c
|
||||
libscore_a_SOURCES += src/schedulerdefaultsetaffinity.c
|
||||
libscore_a_SOURCES += src/schedulersmpstartidle.c
|
||||
|
||||
@@ -42,25 +42,6 @@ extern "C" {
|
||||
|
||||
#define MRSP_RIVAL_STATE_TIMEOUT 0x2U
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _MRSP_Set_root_visitor(
|
||||
Resource_Node *node,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
_Resource_Node_set_root( node, arg );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _MRSP_Set_root(
|
||||
Resource_Node *top,
|
||||
Resource_Node *root
|
||||
)
|
||||
{
|
||||
_Resource_Node_set_root( top, root );
|
||||
_Resource_Iterate( top, _MRSP_Set_root_visitor, root );
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _MRSP_Elevate_priority(
|
||||
MRSP_Control *mrsp,
|
||||
Thread_Control *new_owner,
|
||||
@@ -197,9 +178,10 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
|
||||
_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(
|
||||
&executing->Resource_node,
|
||||
_Resource_Node_get_root( owner )
|
||||
|
||||
_Scheduler_Thread_change_resource_root(
|
||||
executing,
|
||||
_Thread_Resource_node_to_thread( _Resource_Node_get_root( owner ) )
|
||||
);
|
||||
|
||||
if ( timeout > 0 ) {
|
||||
@@ -241,7 +223,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
|
||||
_Resource_Node_extract( &executing->Resource_node );
|
||||
_Resource_Node_set_dependency( &executing->Resource_node, NULL );
|
||||
_Scheduler_Thread_change_help_state( executing, previous_help_state );
|
||||
_MRSP_Set_root( &executing->Resource_node, &executing->Resource_node );
|
||||
_Scheduler_Thread_change_resource_root( executing, executing );
|
||||
_MRSP_Restore_priority( mrsp, executing, initial_priority );
|
||||
|
||||
status = MRSP_TIMEOUT;
|
||||
@@ -334,7 +316,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release(
|
||||
_Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource );
|
||||
_Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node );
|
||||
_Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER );
|
||||
_MRSP_Set_root( &new_owner->Resource_node, &new_owner->Resource_node );
|
||||
_Scheduler_Thread_change_resource_root( new_owner, new_owner );
|
||||
_MRSP_Add_state( rival, MRSP_RIVAL_STATE_NEW_OWNER );
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,31 @@ typedef struct {
|
||||
bool
|
||||
);
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
/**
|
||||
* Ask for help operation.
|
||||
*
|
||||
* @param[in] scheduler The scheduler of the thread offering help.
|
||||
* @param[in] offers_help The thread offering help.
|
||||
* @param[in] needs_help The thread needing help.
|
||||
*
|
||||
* @retval needs_help It was not possible to schedule the thread needing
|
||||
* help, so it is returned to continue the search for help.
|
||||
* @retval next_needs_help It was possible to schedule the thread needing
|
||||
* help, but this displaced another thread eligible to ask for help. So
|
||||
* this thread is returned to start a new search for help.
|
||||
* @retval NULL It was possible to schedule the thread needing help, and no
|
||||
* other thread needs help as a result.
|
||||
*
|
||||
* @see _Scheduler_Ask_for_help().
|
||||
*/
|
||||
Thread_Control *( *ask_for_help )(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *offers_help,
|
||||
Thread_Control *needs_help
|
||||
);
|
||||
#endif
|
||||
|
||||
/** @see _Scheduler_Node_initialize() */
|
||||
void ( *node_initialize )( const Scheduler_Control *, Thread_Control * );
|
||||
|
||||
@@ -375,6 +400,28 @@ extern const Scheduler_Control _Scheduler_Table[];
|
||||
extern const Scheduler_Assignment _Scheduler_Assignments[];
|
||||
#endif
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
/**
|
||||
* @brief Does nothing.
|
||||
*
|
||||
* @param[in] scheduler Unused.
|
||||
* @param[in] offers_help Unused.
|
||||
* @param[in] needs_help Unused.
|
||||
*
|
||||
* @retval NULL Always.
|
||||
*/
|
||||
Thread_Control *_Scheduler_default_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *offers_help,
|
||||
Thread_Control *needs_help
|
||||
);
|
||||
|
||||
#define SCHEDULER_OPERATION_DEFAULT_ASK_FOR_HELP \
|
||||
_Scheduler_default_Ask_for_help,
|
||||
#else
|
||||
#define SCHEDULER_OPERATION_DEFAULT_ASK_FOR_HELP
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Does nothing.
|
||||
*
|
||||
|
||||
@@ -53,6 +53,7 @@ extern "C" {
|
||||
_Scheduler_EDF_Block, /* block entry point */ \
|
||||
_Scheduler_CBS_Unblock, /* unblock entry point */ \
|
||||
_Scheduler_EDF_Change_priority, /* change priority entry point */ \
|
||||
SCHEDULER_OPERATION_DEFAULT_ASK_FOR_HELP \
|
||||
_Scheduler_CBS_Node_initialize, /* node initialize entry point */ \
|
||||
_Scheduler_default_Node_destroy, /* node destroy entry point */ \
|
||||
_Scheduler_EDF_Update_priority, /* update priority entry point */ \
|
||||
|
||||
@@ -46,6 +46,7 @@ extern "C" {
|
||||
_Scheduler_EDF_Block, /* block entry point */ \
|
||||
_Scheduler_EDF_Unblock, /* unblock entry point */ \
|
||||
_Scheduler_EDF_Change_priority, /* change priority entry point */ \
|
||||
SCHEDULER_OPERATION_DEFAULT_ASK_FOR_HELP \
|
||||
_Scheduler_EDF_Node_initialize, /* node initialize entry point */ \
|
||||
_Scheduler_default_Node_destroy, /* node destroy entry point */ \
|
||||
_Scheduler_EDF_Update_priority, /* update priority entry point */ \
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,6 +45,7 @@ extern "C" {
|
||||
_Scheduler_priority_Block, /* block entry point */ \
|
||||
_Scheduler_priority_Unblock, /* unblock entry point */ \
|
||||
_Scheduler_priority_Change_priority, /* change priority entry point */ \
|
||||
SCHEDULER_OPERATION_DEFAULT_ASK_FOR_HELP \
|
||||
_Scheduler_default_Node_initialize, /* node initialize entry point */ \
|
||||
_Scheduler_default_Node_destroy, /* node destroy entry point */ \
|
||||
_Scheduler_priority_Update_priority, /* update priority entry point */ \
|
||||
|
||||
@@ -55,6 +55,7 @@ extern "C" {
|
||||
_Scheduler_priority_affinity_SMP_Block, \
|
||||
_Scheduler_priority_affinity_SMP_Unblock, \
|
||||
_Scheduler_priority_affinity_SMP_Change_priority, \
|
||||
_Scheduler_priority_affinity_SMP_Ask_for_help, \
|
||||
_Scheduler_priority_affinity_SMP_Node_initialize, \
|
||||
_Scheduler_default_Node_destroy, \
|
||||
_Scheduler_priority_SMP_Update_priority, \
|
||||
@@ -139,6 +140,12 @@ Thread_Control *_Scheduler_priority_affinity_SMP_Change_priority(
|
||||
bool prepend_it
|
||||
);
|
||||
|
||||
Thread_Control *_Scheduler_priority_affinity_SMP_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *offers_help,
|
||||
Thread_Control *needs_help
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Set affinity for the priority affinity SMP scheduler.
|
||||
*
|
||||
|
||||
@@ -84,6 +84,7 @@ typedef struct {
|
||||
_Scheduler_priority_SMP_Block, \
|
||||
_Scheduler_priority_SMP_Unblock, \
|
||||
_Scheduler_priority_SMP_Change_priority, \
|
||||
_Scheduler_priority_SMP_Ask_for_help, \
|
||||
_Scheduler_priority_SMP_Node_initialize, \
|
||||
_Scheduler_default_Node_destroy, \
|
||||
_Scheduler_priority_SMP_Update_priority, \
|
||||
@@ -118,6 +119,12 @@ Thread_Control *_Scheduler_priority_SMP_Change_priority(
|
||||
bool prepend_it
|
||||
);
|
||||
|
||||
Thread_Control *_Scheduler_priority_SMP_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *needs_help,
|
||||
Thread_Control *offers_help
|
||||
);
|
||||
|
||||
void _Scheduler_priority_SMP_Update_priority(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *thread,
|
||||
|
||||
@@ -148,6 +148,28 @@ static inline void _Scheduler_priority_SMP_Extract_from_ready(
|
||||
);
|
||||
}
|
||||
|
||||
static inline Thread_Control *_Scheduler_priority_SMP_Get_idle_thread(
|
||||
Scheduler_Context *context
|
||||
)
|
||||
{
|
||||
return _Scheduler_SMP_Get_idle_thread(
|
||||
context,
|
||||
_Scheduler_priority_SMP_Extract_from_ready
|
||||
);
|
||||
}
|
||||
|
||||
static void _Scheduler_priority_SMP_Release_idle_thread(
|
||||
Scheduler_Context *context,
|
||||
Thread_Control *idle
|
||||
)
|
||||
{
|
||||
_Scheduler_SMP_Release_idle_thread(
|
||||
context,
|
||||
idle,
|
||||
_Scheduler_priority_SMP_Insert_ready_fifo
|
||||
);
|
||||
}
|
||||
|
||||
static inline void _Scheduler_priority_SMP_Do_update(
|
||||
Scheduler_Context *context,
|
||||
Scheduler_Node *node_to_update,
|
||||
|
||||
@@ -43,6 +43,7 @@ extern "C" {
|
||||
_Scheduler_simple_Block, /* block entry point */ \
|
||||
_Scheduler_simple_Unblock, /* unblock entry point */ \
|
||||
_Scheduler_simple_Change_priority, /* change priority entry point */ \
|
||||
SCHEDULER_OPERATION_DEFAULT_ASK_FOR_HELP \
|
||||
_Scheduler_default_Node_initialize, /* node initialize entry point */ \
|
||||
_Scheduler_default_Node_destroy, /* node destroy entry point */ \
|
||||
_Scheduler_default_Update_priority, /* update priority entry point */ \
|
||||
|
||||
@@ -65,6 +65,7 @@ typedef struct {
|
||||
_Scheduler_simple_SMP_Block, \
|
||||
_Scheduler_simple_SMP_Unblock, \
|
||||
_Scheduler_simple_SMP_Change_priority, \
|
||||
_Scheduler_simple_SMP_Ask_for_help, \
|
||||
_Scheduler_simple_SMP_Node_initialize, \
|
||||
_Scheduler_default_Node_destroy, \
|
||||
_Scheduler_simple_SMP_Update_priority, \
|
||||
@@ -99,6 +100,12 @@ Thread_Control *_Scheduler_simple_SMP_Change_priority(
|
||||
bool prepend_it
|
||||
);
|
||||
|
||||
Thread_Control *_Scheduler_simple_SMP_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *offers_help,
|
||||
Thread_Control *needs_help
|
||||
);
|
||||
|
||||
void _Scheduler_simple_SMP_Update_priority(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *thread,
|
||||
|
||||
@@ -51,6 +51,11 @@ typedef struct {
|
||||
* @brief The chain of scheduled nodes.
|
||||
*/
|
||||
Chain_Control Scheduled;
|
||||
|
||||
/**
|
||||
* @brief Chain of the available idle threads.
|
||||
*/
|
||||
Chain_Control Idle_threads;
|
||||
} Scheduler_SMP_Context;
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -445,19 +445,77 @@ typedef struct {
|
||||
Thread_Control *terminator;
|
||||
} Thread_Life_control;
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
/**
|
||||
* @brief The thread state with respect to the scheduler.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* @brief This thread is blocked with respect to the scheduler.
|
||||
*
|
||||
* This thread uses no scheduler nodes.
|
||||
*/
|
||||
THREAD_SCHEDULER_BLOCKED,
|
||||
|
||||
/**
|
||||
* @brief This thread is scheduled with respect to the scheduler.
|
||||
*
|
||||
* This thread executes using one of its scheduler nodes. This could be its
|
||||
* own scheduler node or in case it owns resources taking part in the
|
||||
* scheduler helping protocol a scheduler node of another thread.
|
||||
*/
|
||||
THREAD_SCHEDULER_SCHEDULED,
|
||||
|
||||
/**
|
||||
* @brief This thread is ready with respect to the scheduler.
|
||||
*
|
||||
* None of the scheduler nodes of this thread is scheduled.
|
||||
*/
|
||||
THREAD_SCHEDULER_READY
|
||||
} Thread_Scheduler_state;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Thread scheduler control.
|
||||
*/
|
||||
typedef struct {
|
||||
#if defined(RTEMS_SMP)
|
||||
/**
|
||||
* @brief The current scheduler control of this thread.
|
||||
* @brief The current scheduler state of this thread.
|
||||
*/
|
||||
Thread_Scheduler_state state;
|
||||
|
||||
/**
|
||||
* @brief The own scheduler control of this thread.
|
||||
*
|
||||
* This field is constant after initialization.
|
||||
*/
|
||||
const struct Scheduler_Control *own_control;
|
||||
|
||||
/**
|
||||
* @brief The scheduler control of this thread.
|
||||
*
|
||||
* The scheduler helping protocol may change this field.
|
||||
*/
|
||||
const struct Scheduler_Control *control;
|
||||
|
||||
/**
|
||||
* @brief The own scheduler node of this thread.
|
||||
*
|
||||
* This field is constant after initialization. It is used by change
|
||||
* priority and ask for help operations.
|
||||
*/
|
||||
struct Scheduler_Node *own_node;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief The current scheduler node of this thread.
|
||||
* @brief The scheduler node of this thread.
|
||||
*
|
||||
* On uni-processor configurations this field is constant after
|
||||
* initialization.
|
||||
*
|
||||
* On SMP configurations the scheduler helping protocol may change this
|
||||
* field.
|
||||
*/
|
||||
struct Scheduler_Node *node;
|
||||
|
||||
|
||||
@@ -828,6 +828,16 @@ RTEMS_INLINE_ROUTINE bool _Thread_Owns_resources(
|
||||
return owns_resources;
|
||||
}
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
RTEMS_INLINE_ROUTINE Thread_Control *_Thread_Resource_node_to_thread(
|
||||
Resource_Node *node
|
||||
)
|
||||
{
|
||||
return (Thread_Control *)
|
||||
( (char *) node - offsetof( Thread_Control, Resource_node ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Thread_Debug_set_real_processor(
|
||||
Thread_Control *the_thread,
|
||||
Per_CPU_Control *cpu
|
||||
|
||||
@@ -29,6 +29,8 @@ void _Scheduler_CBS_Node_initialize(
|
||||
|
||||
(void) scheduler;
|
||||
|
||||
_Scheduler_Node_do_initialize( &node->Base.Base, the_thread );
|
||||
|
||||
node->Base.thread = the_thread;
|
||||
node->Base.queue_state = SCHEDULER_EDF_QUEUE_STATE_NEVER_HAS_BEEN;
|
||||
node->cbs_server = NULL;
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <rtems/score/schedulerimpl.h>
|
||||
|
||||
typedef struct {
|
||||
Thread_Control *root;
|
||||
Thread_Control *needs_help;
|
||||
} Scheduler_Set_root_context;
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _Scheduler_Set_root_visitor(
|
||||
Resource_Node *resource_node,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
Scheduler_Set_root_context *ctx = arg;
|
||||
Thread_Control *root = ctx->root;
|
||||
Thread_Control *needs_help = root;
|
||||
Thread_Control *offers_help =
|
||||
_Thread_Resource_node_to_thread( resource_node );
|
||||
const Scheduler_Control *scheduler = _Scheduler_Get_own( offers_help );
|
||||
Thread_Control *needs_help_too;
|
||||
|
||||
_Resource_Node_set_root( resource_node, &root->Resource_node );
|
||||
|
||||
needs_help_too = ( *scheduler->Operations.ask_for_help )(
|
||||
scheduler,
|
||||
offers_help,
|
||||
needs_help
|
||||
);
|
||||
|
||||
if ( needs_help_too != needs_help && needs_help_too != NULL ) {
|
||||
_Assert( ctx->needs_help == NULL );
|
||||
ctx->needs_help = needs_help_too;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void _Scheduler_Thread_change_resource_root(
|
||||
Thread_Control *top,
|
||||
Thread_Control *root
|
||||
)
|
||||
{
|
||||
Scheduler_Set_root_context ctx = { root, NULL };
|
||||
Thread_Control *offers_help = top;
|
||||
Scheduler_Node *offers_help_node;
|
||||
Thread_Control *offers_help_too;
|
||||
ISR_Level level;
|
||||
|
||||
_ISR_Disable( level );
|
||||
|
||||
offers_help_node = _Scheduler_Thread_get_node( offers_help );
|
||||
offers_help_too = _Scheduler_Node_get_owner( offers_help_node );
|
||||
|
||||
if ( offers_help != offers_help_too ) {
|
||||
_Scheduler_Set_root_visitor( &offers_help_too->Resource_node, &ctx );
|
||||
_Assert( ctx.needs_help == offers_help );
|
||||
ctx.needs_help = NULL;
|
||||
}
|
||||
|
||||
_Scheduler_Set_root_visitor( &top->Resource_node, &ctx );
|
||||
_Resource_Iterate( &top->Resource_node, _Scheduler_Set_root_visitor, &ctx );
|
||||
|
||||
if ( ctx.needs_help != NULL ) {
|
||||
_Scheduler_Ask_for_help( ctx.needs_help );
|
||||
}
|
||||
|
||||
_ISR_Enable( level );
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <rtems/score/scheduler.h>
|
||||
|
||||
Thread_Control *_Scheduler_default_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *offers_help,
|
||||
Thread_Control *needs_help
|
||||
)
|
||||
{
|
||||
(void) scheduler;
|
||||
(void) offers_help;
|
||||
(void) needs_help;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -19,13 +19,16 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <rtems/score/scheduler.h>
|
||||
#include <rtems/score/schedulerimpl.h>
|
||||
|
||||
void _Scheduler_default_Node_initialize(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
Scheduler_Node *node = _Scheduler_Thread_get_own_node( the_thread );
|
||||
|
||||
(void) scheduler;
|
||||
(void) the_thread;
|
||||
|
||||
_Scheduler_Node_do_initialize( node, the_thread );
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ void _Scheduler_EDF_Node_initialize(
|
||||
|
||||
(void) scheduler;
|
||||
|
||||
_Scheduler_Node_do_initialize( &node->Base, the_thread );
|
||||
|
||||
node->thread = the_thread;
|
||||
node->queue_state = SCHEDULER_EDF_QUEUE_STATE_NEVER_HAS_BEEN;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,15 @@ static bool _Scheduler_priority_affinity_SMP_Insert_priority_fifo_order(
|
||||
&& _Scheduler_SMP_Insert_priority_fifo_order( to_insert, next );
|
||||
}
|
||||
|
||||
static Scheduler_priority_affinity_SMP_Node *
|
||||
_Scheduler_priority_affinity_SMP_Thread_get_own_node(
|
||||
Thread_Control *thread
|
||||
)
|
||||
{
|
||||
return (Scheduler_priority_affinity_SMP_Node *)
|
||||
_Scheduler_Thread_get_own_node( thread );
|
||||
}
|
||||
|
||||
/*
|
||||
* This method returns the scheduler node for the specified thread
|
||||
* as a scheduler specific type.
|
||||
@@ -69,7 +78,8 @@ _Scheduler_priority_affinity_SMP_Thread_get_node(
|
||||
Thread_Control *thread
|
||||
)
|
||||
{
|
||||
return (Scheduler_priority_affinity_SMP_Node *) _Scheduler_Thread_get_node( thread );
|
||||
return (Scheduler_priority_affinity_SMP_Node *)
|
||||
_Scheduler_Thread_get_node( thread );
|
||||
}
|
||||
|
||||
static Scheduler_priority_affinity_SMP_Node *
|
||||
@@ -90,7 +100,7 @@ void _Scheduler_priority_affinity_SMP_Node_initialize(
|
||||
)
|
||||
{
|
||||
Scheduler_priority_affinity_SMP_Node *node =
|
||||
_Scheduler_priority_affinity_SMP_Thread_get_node( thread );
|
||||
_Scheduler_priority_affinity_SMP_Thread_get_own_node( thread );
|
||||
|
||||
(void) scheduler;
|
||||
|
||||
@@ -221,7 +231,8 @@ void _Scheduler_priority_affinity_SMP_Block(
|
||||
_Scheduler_priority_SMP_Extract_from_ready,
|
||||
_Scheduler_priority_affinity_SMP_Get_highest_ready,
|
||||
_Scheduler_priority_SMP_Move_from_ready_to_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_exact
|
||||
_Scheduler_SMP_Allocate_processor_exact,
|
||||
_Scheduler_priority_SMP_Get_idle_thread
|
||||
);
|
||||
|
||||
/*
|
||||
@@ -303,7 +314,8 @@ static Thread_Control *_Scheduler_priority_affinity_SMP_Enqueue_fifo(
|
||||
_Scheduler_SMP_Insert_scheduled_fifo,
|
||||
_Scheduler_priority_SMP_Move_from_scheduled_to_ready,
|
||||
_Scheduler_priority_affinity_SMP_Get_lowest_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_exact
|
||||
_Scheduler_SMP_Allocate_processor_exact,
|
||||
_Scheduler_priority_SMP_Release_idle_thread
|
||||
);
|
||||
}
|
||||
|
||||
@@ -387,7 +399,8 @@ Thread_Control *_Scheduler_priority_affinity_SMP_Unblock(
|
||||
needs_help = _Scheduler_SMP_Unblock(
|
||||
context,
|
||||
thread,
|
||||
_Scheduler_priority_affinity_SMP_Enqueue_fifo
|
||||
_Scheduler_priority_affinity_SMP_Enqueue_fifo,
|
||||
_Scheduler_priority_SMP_Release_idle_thread
|
||||
);
|
||||
|
||||
/*
|
||||
@@ -420,7 +433,8 @@ static Thread_Control *_Scheduler_priority_affinity_SMP_Enqueue_ordered(
|
||||
insert_scheduled,
|
||||
_Scheduler_priority_SMP_Move_from_scheduled_to_ready,
|
||||
_Scheduler_priority_affinity_SMP_Get_lowest_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_exact
|
||||
_Scheduler_SMP_Allocate_processor_exact,
|
||||
_Scheduler_priority_SMP_Release_idle_thread
|
||||
);
|
||||
}
|
||||
|
||||
@@ -463,11 +477,14 @@ _Scheduler_priority_affinity_SMP_Enqueue_scheduled_ordered(
|
||||
context,
|
||||
node,
|
||||
order,
|
||||
_Scheduler_priority_SMP_Extract_from_ready,
|
||||
_Scheduler_priority_affinity_SMP_Get_highest_ready,
|
||||
insert_ready,
|
||||
insert_scheduled,
|
||||
_Scheduler_priority_SMP_Move_from_ready_to_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_exact
|
||||
_Scheduler_SMP_Allocate_processor_exact,
|
||||
_Scheduler_priority_SMP_Get_idle_thread,
|
||||
_Scheduler_priority_SMP_Release_idle_thread
|
||||
);
|
||||
}
|
||||
|
||||
@@ -543,6 +560,27 @@ Thread_Control *_Scheduler_priority_affinity_SMP_Change_priority(
|
||||
return displaced;
|
||||
}
|
||||
|
||||
Thread_Control *_Scheduler_priority_affinity_SMP_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *offers_help,
|
||||
Thread_Control *needs_help
|
||||
)
|
||||
{
|
||||
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
|
||||
|
||||
needs_help = _Scheduler_SMP_Ask_for_help(
|
||||
context,
|
||||
offers_help,
|
||||
needs_help,
|
||||
_Scheduler_priority_affinity_SMP_Enqueue_fifo,
|
||||
_Scheduler_priority_SMP_Release_idle_thread
|
||||
);
|
||||
|
||||
_Scheduler_priority_affinity_SMP_Check_for_migrations( context );
|
||||
|
||||
return needs_help;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the public scheduler specific Change Priority operation.
|
||||
*/
|
||||
|
||||
@@ -47,7 +47,7 @@ void _Scheduler_priority_SMP_Node_initialize(
|
||||
Thread_Control *thread
|
||||
)
|
||||
{
|
||||
Scheduler_SMP_Node *node = _Scheduler_SMP_Thread_get_node( thread );
|
||||
Scheduler_SMP_Node *node = _Scheduler_SMP_Thread_get_own_node( thread );
|
||||
|
||||
_Scheduler_SMP_Node_initialize( node, thread );
|
||||
}
|
||||
@@ -93,7 +93,8 @@ void _Scheduler_priority_SMP_Block(
|
||||
_Scheduler_priority_SMP_Extract_from_ready,
|
||||
_Scheduler_priority_SMP_Get_highest_ready,
|
||||
_Scheduler_priority_SMP_Move_from_ready_to_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_lazy
|
||||
_Scheduler_SMP_Allocate_processor_lazy,
|
||||
_Scheduler_priority_SMP_Get_idle_thread
|
||||
);
|
||||
}
|
||||
|
||||
@@ -115,7 +116,8 @@ static Thread_Control *_Scheduler_priority_SMP_Enqueue_ordered(
|
||||
insert_scheduled,
|
||||
_Scheduler_priority_SMP_Move_from_scheduled_to_ready,
|
||||
_Scheduler_SMP_Get_lowest_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_lazy
|
||||
_Scheduler_SMP_Allocate_processor_lazy,
|
||||
_Scheduler_priority_SMP_Release_idle_thread
|
||||
);
|
||||
}
|
||||
|
||||
@@ -163,11 +165,14 @@ static Thread_Control *_Scheduler_priority_SMP_Enqueue_scheduled_ordered(
|
||||
context,
|
||||
node,
|
||||
order,
|
||||
_Scheduler_priority_SMP_Extract_from_ready,
|
||||
_Scheduler_priority_SMP_Get_highest_ready,
|
||||
insert_ready,
|
||||
insert_scheduled,
|
||||
_Scheduler_priority_SMP_Move_from_ready_to_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_lazy
|
||||
_Scheduler_SMP_Allocate_processor_lazy,
|
||||
_Scheduler_priority_SMP_Get_idle_thread,
|
||||
_Scheduler_priority_SMP_Release_idle_thread
|
||||
);
|
||||
}
|
||||
|
||||
@@ -209,7 +214,8 @@ Thread_Control *_Scheduler_priority_SMP_Unblock(
|
||||
return _Scheduler_SMP_Unblock(
|
||||
context,
|
||||
thread,
|
||||
_Scheduler_priority_SMP_Enqueue_fifo
|
||||
_Scheduler_priority_SMP_Enqueue_fifo,
|
||||
_Scheduler_priority_SMP_Release_idle_thread
|
||||
);
|
||||
}
|
||||
|
||||
@@ -236,6 +242,23 @@ Thread_Control *_Scheduler_priority_SMP_Change_priority(
|
||||
);
|
||||
}
|
||||
|
||||
Thread_Control *_Scheduler_priority_SMP_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *offers_help,
|
||||
Thread_Control *needs_help
|
||||
)
|
||||
{
|
||||
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
|
||||
|
||||
return _Scheduler_SMP_Ask_for_help(
|
||||
context,
|
||||
offers_help,
|
||||
needs_help,
|
||||
_Scheduler_priority_SMP_Enqueue_fifo,
|
||||
_Scheduler_priority_SMP_Release_idle_thread
|
||||
);
|
||||
}
|
||||
|
||||
Thread_Control *_Scheduler_priority_SMP_Yield(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *thread
|
||||
|
||||
@@ -47,7 +47,7 @@ void _Scheduler_simple_SMP_Node_initialize(
|
||||
Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
Scheduler_SMP_Node *node = _Scheduler_SMP_Thread_get_node( the_thread );
|
||||
Scheduler_SMP_Node *node = _Scheduler_SMP_Thread_get_own_node( the_thread );
|
||||
|
||||
_Scheduler_SMP_Node_initialize( node, the_thread );
|
||||
}
|
||||
@@ -162,6 +162,28 @@ static void _Scheduler_simple_SMP_Extract_from_ready(
|
||||
_Chain_Extract_unprotected( &node_to_extract->Node );
|
||||
}
|
||||
|
||||
static Thread_Control *_Scheduler_simple_SMP_Get_idle_thread(
|
||||
Scheduler_Context *context
|
||||
)
|
||||
{
|
||||
return _Scheduler_SMP_Get_idle_thread(
|
||||
context,
|
||||
_Scheduler_simple_SMP_Extract_from_ready
|
||||
);
|
||||
}
|
||||
|
||||
static void _Scheduler_simple_SMP_Release_idle_thread(
|
||||
Scheduler_Context *context,
|
||||
Thread_Control *idle
|
||||
)
|
||||
{
|
||||
_Scheduler_SMP_Release_idle_thread(
|
||||
context,
|
||||
idle,
|
||||
_Scheduler_simple_SMP_Insert_ready_fifo
|
||||
);
|
||||
}
|
||||
|
||||
void _Scheduler_simple_SMP_Block(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *thread
|
||||
@@ -175,7 +197,8 @@ void _Scheduler_simple_SMP_Block(
|
||||
_Scheduler_simple_SMP_Extract_from_ready,
|
||||
_Scheduler_simple_SMP_Get_highest_ready,
|
||||
_Scheduler_simple_SMP_Move_from_ready_to_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_lazy
|
||||
_Scheduler_SMP_Allocate_processor_lazy,
|
||||
_Scheduler_simple_SMP_Get_idle_thread
|
||||
);
|
||||
}
|
||||
|
||||
@@ -197,7 +220,8 @@ static Thread_Control *_Scheduler_simple_SMP_Enqueue_ordered(
|
||||
insert_scheduled,
|
||||
_Scheduler_simple_SMP_Move_from_scheduled_to_ready,
|
||||
_Scheduler_SMP_Get_lowest_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_lazy
|
||||
_Scheduler_SMP_Allocate_processor_lazy,
|
||||
_Scheduler_simple_SMP_Release_idle_thread
|
||||
);
|
||||
}
|
||||
|
||||
@@ -245,11 +269,14 @@ static Thread_Control *_Scheduler_simple_SMP_Enqueue_scheduled_ordered(
|
||||
context,
|
||||
node,
|
||||
order,
|
||||
_Scheduler_simple_SMP_Extract_from_ready,
|
||||
_Scheduler_simple_SMP_Get_highest_ready,
|
||||
insert_ready,
|
||||
insert_scheduled,
|
||||
_Scheduler_simple_SMP_Move_from_ready_to_scheduled,
|
||||
_Scheduler_SMP_Allocate_processor_lazy
|
||||
_Scheduler_SMP_Allocate_processor_lazy,
|
||||
_Scheduler_simple_SMP_Get_idle_thread,
|
||||
_Scheduler_simple_SMP_Release_idle_thread
|
||||
);
|
||||
}
|
||||
|
||||
@@ -291,7 +318,8 @@ Thread_Control *_Scheduler_simple_SMP_Unblock(
|
||||
return _Scheduler_SMP_Unblock(
|
||||
context,
|
||||
thread,
|
||||
_Scheduler_simple_SMP_Enqueue_fifo
|
||||
_Scheduler_simple_SMP_Enqueue_fifo,
|
||||
_Scheduler_simple_SMP_Release_idle_thread
|
||||
);
|
||||
}
|
||||
|
||||
@@ -318,6 +346,23 @@ Thread_Control *_Scheduler_simple_SMP_Change_priority(
|
||||
);
|
||||
}
|
||||
|
||||
Thread_Control *_Scheduler_simple_SMP_Ask_for_help(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *offers_help,
|
||||
Thread_Control *needs_help
|
||||
)
|
||||
{
|
||||
Scheduler_Context *context = _Scheduler_Get_context( scheduler );
|
||||
|
||||
return _Scheduler_SMP_Ask_for_help(
|
||||
context,
|
||||
offers_help,
|
||||
needs_help,
|
||||
_Scheduler_simple_SMP_Enqueue_fifo,
|
||||
_Scheduler_simple_SMP_Release_idle_thread
|
||||
);
|
||||
}
|
||||
|
||||
Thread_Control *_Scheduler_simple_SMP_Yield(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *thread
|
||||
|
||||
+19
-3
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup ScoreSchedulerSMP
|
||||
* @ingroup ScoreScheduler
|
||||
*
|
||||
* @brief SMP Scheduler Implementation
|
||||
* @brief Scheduler SMP Debug Implementation
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -24,10 +24,24 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <rtems/score/schedulerimpl.h>
|
||||
#include <rtems/score/schedulerpriorityimpl.h>
|
||||
|
||||
#if defined(RTEMS_DEBUG)
|
||||
|
||||
/*
|
||||
* Table with all valid state transitions. It is used in
|
||||
* Table with all valid state transitions for _Scheduler_Thread_change_state()
|
||||
* in case RTEMS_DEBUG is defined.
|
||||
*/
|
||||
const bool _Scheduler_Thread_state_valid_state_changes[ 3 ][ 3 ] = {
|
||||
/* FROM / TO BLOCKED SCHEDULED READY */
|
||||
/* BLOCKED */ { false, true, true },
|
||||
/* SCHEDULED */ { true, false, true },
|
||||
/* READY */ { true, true, true }
|
||||
};
|
||||
|
||||
/*
|
||||
* Table with all valid state transitions for
|
||||
* _Scheduler_SMP_Node_change_state() in case RTEMS_DEBUG is defined.
|
||||
*/
|
||||
const bool _Scheduler_SMP_Node_valid_state_changes[ 3 ][ 3 ] = {
|
||||
@@ -36,3 +50,5 @@ const bool _Scheduler_SMP_Node_valid_state_changes[ 3 ][ 3 ] = {
|
||||
/* SCHEDULED */ { true, false, true },
|
||||
/* READY */ { true, true, false }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -26,4 +26,5 @@ void _Scheduler_SMP_Start_idle(
|
||||
|
||||
_Thread_Set_CPU( thread, cpu );
|
||||
_Chain_Append_unprotected( &self->Scheduled, &node->Base.Node );
|
||||
_Chain_Prepend_unprotected( &self->Idle_threads, &thread->Object.Node );
|
||||
}
|
||||
|
||||
@@ -181,7 +181,10 @@ bool _Thread_Initialize(
|
||||
}
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
the_thread->Scheduler.state = THREAD_SCHEDULER_BLOCKED;
|
||||
the_thread->Scheduler.own_control = scheduler;
|
||||
the_thread->Scheduler.control = scheduler;
|
||||
the_thread->Scheduler.own_node = the_thread->Scheduler.node;
|
||||
_Resource_Node_initialize( &the_thread->Resource_node );
|
||||
_CPU_Context_Set_is_executing( &the_thread->Registers, false );
|
||||
#endif
|
||||
|
||||
@@ -147,6 +147,84 @@ another processor. So if we enable interrupts during this transition we have
|
||||
to provide an alternative task independent stack for this time frame. This
|
||||
issue needs further investigation.
|
||||
|
||||
@subsection Scheduler Helping Protocol
|
||||
|
||||
The scheduler provides a helping protocol to support locking protocols like
|
||||
@cite{Migratory Priority Inheritance} or the @cite{Multiprocessor Resource
|
||||
Sharing Protocol}. Each ready task can use at least one scheduler node at a
|
||||
time to gain access to a processor. Each scheduler node has an owner, a user
|
||||
and an optional idle task. The owner of a scheduler node is determined a task
|
||||
creation and never changes during the life time of a scheduler node. The user
|
||||
of a scheduler node may change due to the scheduler helping protocol. A
|
||||
scheduler node is in one of the four scheduler help states:
|
||||
|
||||
@table @dfn
|
||||
|
||||
@item help yourself
|
||||
|
||||
This scheduler node is solely used by the owner task. This task 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 tasks.
|
||||
|
||||
@item help active owner
|
||||
|
||||
This scheduler node is owned by a task actively owning a resource and can be
|
||||
used to help out tasks.
|
||||
|
||||
In case this scheduler node changes its state from ready to scheduled and the
|
||||
task executes using another node, then an idle task will be provided as a user
|
||||
of this node to temporarily execute on behalf of the owner task. Thus lower
|
||||
priority tasks are denied access to the processors of this scheduler instance.
|
||||
|
||||
In case a task actively owning a resource performs a blocking operation, then
|
||||
an idle task will be used also in case this node is in the scheduled state.
|
||||
|
||||
@item help active rival
|
||||
|
||||
This scheduler node is owned by a task actively obtaining a resource currently
|
||||
owned by another task and can be used to help out tasks.
|
||||
|
||||
The task owning this node is ready and will give away its processor in case the
|
||||
task owning the resource asks for help.
|
||||
|
||||
@item help passive
|
||||
|
||||
This scheduler node is owned by a task obtaining a resource currently owned by
|
||||
another task and can be used to help out tasks.
|
||||
|
||||
The task owning this node is blocked.
|
||||
|
||||
@end table
|
||||
|
||||
The following scheduler operations return a task in need for help
|
||||
|
||||
@itemize @bullet
|
||||
@item unblock,
|
||||
@item change priority,
|
||||
@item yield, and
|
||||
@item ask for help.
|
||||
@end itemize
|
||||
|
||||
A task in need for help is a task that encounters a scheduler state change from
|
||||
scheduled to ready (this is a pre-emption by a higher priority task) or a task
|
||||
that cannot be scheduled in an unblock operation. Such a task can ask tasks
|
||||
which depend on resources owned by this task for help.
|
||||
|
||||
In case it is not possible to schedule a task in need for help, then the
|
||||
scheduler nodes available for the task will be placed into the set of ready
|
||||
scheduler nodes of the corresponding scheduler instances. Once a state change
|
||||
from ready to scheduled happens for one of scheduler nodes it will be used to
|
||||
schedule the task in need for help.
|
||||
|
||||
The ask for help scheduler operation is used to help tasks in need for help
|
||||
returned by the operations mentioned above. This operation is also used in
|
||||
case the root of a resource sub-tree owned by a task changes.
|
||||
|
||||
The run-time of the ask for help procedures depend on the size of the resource
|
||||
tree of the task needing help and other resource trees in case tasks in need
|
||||
for help are produced during this operation. Thus the worst-case latency in
|
||||
the system depends on the maximum resource tree size of the application.
|
||||
|
||||
@subsection Critical Section Techniques and SMP
|
||||
|
||||
As discussed earlier, SMP systems have opportunities for true parallelism
|
||||
|
||||
Reference in New Issue
Block a user