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:
Sebastian Huber
2014-07-09 10:05:17 +02:00
parent 52f8e90d7f
commit 5c3d250959
28 changed files with 1399 additions and 127 deletions
+3 -1
View File
@@ -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
+6 -24
View File
@@ -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
+60 -2
View File
@@ -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
+2
View File
@@ -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;
+85
View File
@@ -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;
}
+5 -2
View File
@@ -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 );
}
+2
View File
@@ -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.
*/
+28 -5
View File
@@ -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
+50 -5
View File
@@ -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
@@ -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
+1
View File
@@ -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 );
}
+3
View File
@@ -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
+78
View File
@@ -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