mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-09-21 11:44:17 +08:00
score: Rework thread priority management
Add priority nodes which contribute to the overall thread priority. The actual priority of a thread is now an aggregation of priority nodes. The thread priority aggregation for the home scheduler instance of a thread consists of at least one priority node, which is normally the real priority of the thread. The locking protocols (e.g. priority ceiling and priority inheritance), rate-monotonic period objects and the POSIX sporadic server add, change and remove priority nodes. A thread changes its priority now immediately, e.g. priority changes are not deferred until the thread releases its last resource. Replace the _Thread_Change_priority() function with * _Thread_Priority_perform_actions(), * _Thread_Priority_add(), * _Thread_Priority_remove(), * _Thread_Priority_change(), and * _Thread_Priority_update(). Update #2412. Update #2556.
This commit is contained in:
@@ -888,7 +888,7 @@ rtems_capture_task_start_priority (rtems_tcb* tcb)
|
||||
static inline rtems_task_priority
|
||||
rtems_capture_task_real_priority (rtems_tcb* tcb)
|
||||
{
|
||||
return tcb->real_priority;
|
||||
return tcb->Real_priority.priority;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -261,7 +261,7 @@ task_usage(Thread_Control* thread, void* arg)
|
||||
CPU_usage_Less_than(&usage, &data->usage[j]))
|
||||
continue;
|
||||
case RTEMS_TOP_SORT_REAL_PRI:
|
||||
if (thread->real_priority > data->tasks[j]->real_priority)
|
||||
if (thread->Real_priority.priority > data->tasks[j]->Real_priority.priority)
|
||||
continue;
|
||||
case RTEMS_TOP_SORT_CURRENT_PRI:
|
||||
if (
|
||||
@@ -478,10 +478,10 @@ rtems_cpuusage_top_thread (rtems_task_argument arg)
|
||||
snprintf(name, sizeof(name) - 1, "(%p)", thread->Start.Entry.Kinds.Numeric.entry);
|
||||
|
||||
rtems_printf(data->printer,
|
||||
" 0x%08" PRIx32 " | %-19s | %3" PRId32 " | %3" PRId32 " | ",
|
||||
" 0x%08" PRIx32 " | %-19s | %3" PRId64 " | %3" PRId64 " | ",
|
||||
thread->Object.id,
|
||||
name,
|
||||
thread->real_priority,
|
||||
thread->Real_priority.priority,
|
||||
_Thread_Get_priority(thread));
|
||||
|
||||
usage = data->usage[i];
|
||||
|
||||
@@ -68,6 +68,8 @@ RTEMS_INLINE_ROUTINE void _POSIX_Threads_Sporadic_timer_insert(
|
||||
);
|
||||
}
|
||||
|
||||
void _POSIX_Threads_Sporadic_timer( Watchdog_Control *watchdog );
|
||||
|
||||
/**
|
||||
* @brief POSIX threads sporadic budget callout.
|
||||
*
|
||||
|
||||
@@ -60,13 +60,7 @@ typedef struct {
|
||||
* @brief The low priority when using the sporadic server scheduling
|
||||
* policy.
|
||||
*/
|
||||
Priority_Control low_priority;
|
||||
|
||||
/**
|
||||
* @brief The high priority when using the sporadic server scheduling
|
||||
* policy.
|
||||
*/
|
||||
Priority_Control high_priority;
|
||||
Priority_Node Low_priority;
|
||||
} Sporadic;
|
||||
|
||||
/** This is the set of signals which are currently unblocked. */
|
||||
|
||||
@@ -153,7 +153,7 @@ int _POSIX_signals_Send(
|
||||
the_node = the_node->next ) {
|
||||
Scheduler_Node *scheduler_node;
|
||||
|
||||
scheduler_node = SCHEDULER_NODE_OF_WAIT_CHAIN_NODE( the_node );
|
||||
scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY_NODE( the_node );
|
||||
the_thread = _Scheduler_Node_get_owner( scheduler_node );
|
||||
api = the_thread->API_Extensions[ THREAD_API_POSIX ];
|
||||
|
||||
|
||||
@@ -64,7 +64,18 @@ int pthread_mutex_setprioceiling(
|
||||
|
||||
new_priority = _POSIX_Priority_To_core( scheduler, prioceiling, &valid );
|
||||
if ( valid ) {
|
||||
_CORE_ceiling_mutex_Set_priority( &the_mutex->Mutex, new_priority );
|
||||
Thread_queue_Context queue_context;
|
||||
Per_CPU_Control *cpu_self;
|
||||
|
||||
_Thread_queue_Context_clear_priority_updates( &queue_context );
|
||||
_CORE_ceiling_mutex_Set_priority(
|
||||
&the_mutex->Mutex,
|
||||
new_priority,
|
||||
&queue_context
|
||||
);
|
||||
cpu_self = _Thread_Dispatch_disable();
|
||||
_Thread_Priority_update( &queue_context );
|
||||
_Thread_Dispatch_enable( cpu_self );
|
||||
error = 0;
|
||||
} else {
|
||||
error = EINVAL;
|
||||
|
||||
+46
-61
@@ -82,85 +82,70 @@ pthread_attr_t _POSIX_Threads_Default_attributes = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static bool _POSIX_Threads_Sporadic_timer_filter(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Control *new_priority_p,
|
||||
void *arg
|
||||
)
|
||||
void _POSIX_Threads_Sporadic_timer( Watchdog_Control *watchdog )
|
||||
{
|
||||
POSIX_API_Control *api;
|
||||
Priority_Control current_priority;
|
||||
Priority_Control new_priority;
|
||||
|
||||
api = arg;
|
||||
|
||||
new_priority = api->Sporadic.high_priority;
|
||||
*new_priority_p = new_priority;
|
||||
|
||||
current_priority = _Thread_Get_priority( the_thread );
|
||||
the_thread->real_priority = new_priority;
|
||||
|
||||
_Watchdog_Per_CPU_remove_relative( &api->Sporadic.Timer );
|
||||
_POSIX_Threads_Sporadic_timer_insert( the_thread, api );
|
||||
|
||||
return _Thread_Priority_less_than( current_priority, new_priority )
|
||||
|| !_Thread_Owns_resources( the_thread );
|
||||
}
|
||||
|
||||
static void _POSIX_Threads_Sporadic_timer( Watchdog_Control *watchdog )
|
||||
{
|
||||
POSIX_API_Control *api;
|
||||
Thread_Control *the_thread;
|
||||
POSIX_API_Control *api;
|
||||
Thread_Control *the_thread;
|
||||
Thread_queue_Context queue_context;
|
||||
|
||||
api = RTEMS_CONTAINER_OF( watchdog, POSIX_API_Control, Sporadic.Timer );
|
||||
the_thread = api->thread;
|
||||
|
||||
_Thread_Change_priority(
|
||||
the_thread,
|
||||
0,
|
||||
api,
|
||||
_POSIX_Threads_Sporadic_timer_filter,
|
||||
true
|
||||
);
|
||||
_Thread_queue_Context_clear_priority_updates( &queue_context );
|
||||
_Thread_Wait_acquire( the_thread, &queue_context );
|
||||
|
||||
if ( _Priority_Node_is_active( &api->Sporadic.Low_priority ) ) {
|
||||
_Thread_Priority_add(
|
||||
the_thread,
|
||||
&the_thread->Real_priority,
|
||||
&queue_context
|
||||
);
|
||||
_Thread_Priority_remove(
|
||||
the_thread,
|
||||
&api->Sporadic.Low_priority,
|
||||
&queue_context
|
||||
);
|
||||
_Priority_Node_set_inactive( &api->Sporadic.Low_priority );
|
||||
}
|
||||
|
||||
_Watchdog_Per_CPU_remove_relative( &api->Sporadic.Timer );
|
||||
_POSIX_Threads_Sporadic_timer_insert( the_thread, api );
|
||||
|
||||
_Thread_Wait_release( the_thread, &queue_context );
|
||||
_Thread_Priority_update( &queue_context );
|
||||
}
|
||||
|
||||
static bool _POSIX_Threads_Sporadic_budget_callout_filter(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Control *new_priority_p,
|
||||
void *arg
|
||||
)
|
||||
void _POSIX_Threads_Sporadic_budget_callout( Thread_Control *the_thread )
|
||||
{
|
||||
POSIX_API_Control *api;
|
||||
Priority_Control current_priority;
|
||||
Priority_Control new_priority;
|
||||
POSIX_API_Control *api;
|
||||
Thread_queue_Context queue_context;
|
||||
|
||||
api = the_thread->API_Extensions[ THREAD_API_POSIX ];
|
||||
|
||||
_Thread_queue_Context_clear_priority_updates( &queue_context );
|
||||
_Thread_Wait_acquire( the_thread, &queue_context );
|
||||
|
||||
/*
|
||||
* This will prevent the thread from consuming its entire "budget"
|
||||
* while at low priority.
|
||||
*/
|
||||
the_thread->cpu_time_budget = UINT32_MAX;
|
||||
|
||||
new_priority = api->Sporadic.low_priority;
|
||||
*new_priority_p = new_priority;
|
||||
if ( !_Priority_Node_is_active( &api->Sporadic.Low_priority ) ) {
|
||||
_Thread_Priority_add(
|
||||
the_thread,
|
||||
&api->Sporadic.Low_priority,
|
||||
&queue_context
|
||||
);
|
||||
_Thread_Priority_remove(
|
||||
the_thread,
|
||||
&the_thread->Real_priority,
|
||||
&queue_context
|
||||
);
|
||||
}
|
||||
|
||||
current_priority = _Thread_Get_priority( the_thread );
|
||||
the_thread->real_priority = new_priority;
|
||||
|
||||
return _Thread_Priority_less_than( current_priority, new_priority )
|
||||
|| !_Thread_Owns_resources( the_thread );
|
||||
}
|
||||
|
||||
void _POSIX_Threads_Sporadic_budget_callout( Thread_Control *the_thread )
|
||||
{
|
||||
_Thread_Change_priority(
|
||||
the_thread,
|
||||
0,
|
||||
NULL,
|
||||
_POSIX_Threads_Sporadic_budget_callout_filter,
|
||||
true
|
||||
);
|
||||
_Thread_Wait_release( the_thread, &queue_context );
|
||||
_Thread_Priority_update( &queue_context );
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -61,11 +61,11 @@ int pthread_create(
|
||||
}
|
||||
};
|
||||
const pthread_attr_t *the_attr;
|
||||
int normal_prio;
|
||||
int low_prio;
|
||||
int high_prio;
|
||||
bool valid;
|
||||
Priority_Control core_normal_prio;
|
||||
Priority_Control core_low_prio;
|
||||
Priority_Control core_high_prio;
|
||||
Thread_CPU_budget_algorithms budget_algorithm;
|
||||
Thread_CPU_budget_algorithm_callout budget_callout;
|
||||
bool is_fp;
|
||||
@@ -149,22 +149,22 @@ int pthread_create(
|
||||
return error;
|
||||
}
|
||||
|
||||
if ( schedpolicy == SCHED_SPORADIC ) {
|
||||
low_prio = schedparam.sched_ss_low_priority;
|
||||
high_prio = schedparam.sched_priority;
|
||||
} else {
|
||||
low_prio = schedparam.sched_priority;
|
||||
high_prio = low_prio;
|
||||
}
|
||||
normal_prio = schedparam.sched_priority;
|
||||
|
||||
scheduler = _Scheduler_Get_own( executing );
|
||||
|
||||
core_low_prio = _POSIX_Priority_To_core( scheduler, low_prio, &valid );
|
||||
core_normal_prio = _POSIX_Priority_To_core( scheduler, normal_prio, &valid );
|
||||
if ( !valid ) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
core_high_prio = _POSIX_Priority_To_core( scheduler, high_prio, &valid );
|
||||
if ( schedpolicy == SCHED_SPORADIC ) {
|
||||
low_prio = schedparam.sched_ss_low_priority;
|
||||
} else {
|
||||
low_prio = normal_prio;
|
||||
}
|
||||
|
||||
core_low_prio = _POSIX_Priority_To_core( scheduler, low_prio, &valid );
|
||||
if ( !valid ) {
|
||||
return EINVAL;
|
||||
}
|
||||
@@ -205,7 +205,7 @@ int pthread_create(
|
||||
the_attr->stackaddr,
|
||||
_POSIX_Threads_Ensure_minimum_stack(the_attr->stacksize),
|
||||
is_fp,
|
||||
core_high_prio,
|
||||
core_normal_prio,
|
||||
true, /* preemptible */
|
||||
budget_algorithm,
|
||||
budget_callout,
|
||||
@@ -245,13 +245,11 @@ int pthread_create(
|
||||
api = the_thread->API_Extensions[ THREAD_API_POSIX ];
|
||||
|
||||
_POSIX_Threads_Copy_attributes( &api->Attributes, the_attr );
|
||||
api->Sporadic.low_priority = core_low_prio;
|
||||
api->Sporadic.high_priority = core_high_prio;
|
||||
_Priority_Node_initialize( &api->Sporadic.Low_priority, core_low_prio );
|
||||
_Priority_Node_set_inactive( &api->Sporadic.Low_priority );
|
||||
|
||||
if ( schedpolicy == SCHED_SPORADIC ) {
|
||||
_ISR_lock_ISR_disable( &lock_context );
|
||||
_POSIX_Threads_Sporadic_timer_insert( the_thread, api );
|
||||
_ISR_lock_ISR_enable( &lock_context );
|
||||
_POSIX_Threads_Sporadic_timer( &api->Sporadic.Timer );
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -59,7 +59,7 @@ int pthread_getschedparam(
|
||||
*param = api->Attributes.schedparam;
|
||||
|
||||
scheduler = _Scheduler_Get_own( the_thread );
|
||||
priority = the_thread->real_priority;
|
||||
priority = the_thread->Real_priority.priority;
|
||||
|
||||
_Thread_Wait_release( the_thread, &queue_context );
|
||||
|
||||
|
||||
@@ -30,36 +30,24 @@
|
||||
#include <rtems/score/threadimpl.h>
|
||||
#include <rtems/score/schedulerimpl.h>
|
||||
|
||||
typedef struct {
|
||||
int policy;
|
||||
const struct sched_param *param;
|
||||
Thread_CPU_budget_algorithms budget_algorithm;
|
||||
Thread_CPU_budget_algorithm_callout budget_callout;
|
||||
int error;
|
||||
} POSIX_Set_sched_param_context;
|
||||
|
||||
static bool _POSIX_Set_sched_param_filter(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Control *new_priority_p,
|
||||
void *arg
|
||||
static int _POSIX_Set_sched_param(
|
||||
Thread_Control *the_thread,
|
||||
int policy,
|
||||
struct sched_param *param,
|
||||
Thread_CPU_budget_algorithms budget_algorithm,
|
||||
Thread_CPU_budget_algorithm_callout budget_callout,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
POSIX_Set_sched_param_context *context;
|
||||
const struct sched_param *param;
|
||||
const Scheduler_Control *scheduler;
|
||||
POSIX_API_Control *api;
|
||||
int low_prio;
|
||||
int high_prio;
|
||||
bool valid;
|
||||
Priority_Control core_low_prio;
|
||||
Priority_Control core_high_prio;
|
||||
Priority_Control current_priority;
|
||||
const Scheduler_Control *scheduler;
|
||||
POSIX_API_Control *api;
|
||||
int low_prio;
|
||||
int high_prio;
|
||||
bool valid;
|
||||
Priority_Control core_normal_prio;
|
||||
Priority_Control core_low_prio;
|
||||
|
||||
context = arg;
|
||||
param = context->param;
|
||||
scheduler = _Scheduler_Get_own( the_thread );
|
||||
|
||||
if ( context->policy == SCHED_SPORADIC ) {
|
||||
if ( policy == SCHED_SPORADIC ) {
|
||||
low_prio = param->sched_ss_low_priority;
|
||||
high_prio = param->sched_priority;
|
||||
} else {
|
||||
@@ -67,45 +55,60 @@ static bool _POSIX_Set_sched_param_filter(
|
||||
high_prio = low_prio;
|
||||
}
|
||||
|
||||
core_low_prio = _POSIX_Priority_To_core( scheduler, low_prio, &valid );
|
||||
scheduler = _Scheduler_Get_own( the_thread );
|
||||
|
||||
core_normal_prio = _POSIX_Priority_To_core( scheduler, low_prio, &valid );
|
||||
if ( !valid ) {
|
||||
context->error = EINVAL;
|
||||
return false;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
core_high_prio = _POSIX_Priority_To_core( scheduler, high_prio, &valid );
|
||||
core_low_prio = _POSIX_Priority_To_core( scheduler, high_prio, &valid );
|
||||
if ( !valid ) {
|
||||
context->error = EINVAL;
|
||||
return false;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
*new_priority_p = core_high_prio;
|
||||
|
||||
current_priority = _Thread_Get_priority( the_thread );
|
||||
the_thread->real_priority = core_high_prio;
|
||||
|
||||
api = the_thread->API_Extensions[ THREAD_API_POSIX ];
|
||||
|
||||
_Watchdog_Per_CPU_remove_relative( &api->Sporadic.Timer );
|
||||
|
||||
api->Attributes.schedpolicy = context->policy;
|
||||
_Priority_Node_set_priority( &the_thread->Real_priority, core_normal_prio );
|
||||
|
||||
if ( _Priority_Node_is_active( &api->Sporadic.Low_priority ) ) {
|
||||
_Thread_Priority_add(
|
||||
the_thread,
|
||||
&the_thread->Real_priority,
|
||||
queue_context
|
||||
);
|
||||
_Thread_Priority_remove(
|
||||
the_thread,
|
||||
&api->Sporadic.Low_priority,
|
||||
queue_context
|
||||
);
|
||||
_Priority_Node_set_inactive( &api->Sporadic.Low_priority );
|
||||
} else {
|
||||
_Thread_Priority_changed(
|
||||
the_thread,
|
||||
&the_thread->Real_priority,
|
||||
false,
|
||||
queue_context
|
||||
);
|
||||
}
|
||||
|
||||
api->Attributes.schedpolicy = policy;
|
||||
api->Attributes.schedparam = *param;
|
||||
api->Sporadic.low_priority = core_low_prio;
|
||||
api->Sporadic.high_priority = core_high_prio;
|
||||
|
||||
the_thread->budget_algorithm = context->budget_algorithm;
|
||||
the_thread->budget_callout = context->budget_callout;
|
||||
the_thread->budget_algorithm = budget_algorithm;
|
||||
the_thread->budget_callout = budget_callout;
|
||||
|
||||
if ( context->policy == SCHED_SPORADIC ) {
|
||||
if ( policy == SCHED_SPORADIC ) {
|
||||
_Priority_Node_set_priority( &api->Sporadic.Low_priority, core_low_prio );
|
||||
_POSIX_Threads_Sporadic_timer_insert( the_thread, api );
|
||||
} else {
|
||||
the_thread->cpu_time_budget =
|
||||
rtems_configuration_get_ticks_per_timeslice();
|
||||
}
|
||||
|
||||
context->error = 0;
|
||||
return _Thread_Priority_less_than( current_priority, core_high_prio )
|
||||
|| !_Thread_Owns_resources( the_thread );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_setschedparam(
|
||||
@@ -114,11 +117,12 @@ int pthread_setschedparam(
|
||||
struct sched_param *param
|
||||
)
|
||||
{
|
||||
Thread_Control *the_thread;
|
||||
Per_CPU_Control *cpu_self;
|
||||
POSIX_Set_sched_param_context context;
|
||||
ISR_lock_Context lock_context;
|
||||
int error;
|
||||
Thread_CPU_budget_algorithms budget_algorithm;
|
||||
Thread_CPU_budget_algorithm_callout budget_callout;
|
||||
Thread_Control *the_thread;
|
||||
Per_CPU_Control *cpu_self;
|
||||
Thread_queue_Context queue_context;
|
||||
int error;
|
||||
|
||||
if ( param == NULL ) {
|
||||
return EINVAL;
|
||||
@@ -127,33 +131,34 @@ int pthread_setschedparam(
|
||||
error = _POSIX_Thread_Translate_sched_param(
|
||||
policy,
|
||||
param,
|
||||
&context.budget_algorithm,
|
||||
&context.budget_callout
|
||||
&budget_algorithm,
|
||||
&budget_callout
|
||||
);
|
||||
if ( error != 0 ) {
|
||||
return error;
|
||||
}
|
||||
|
||||
context.policy = policy;
|
||||
context.param = param;
|
||||
|
||||
the_thread = _Thread_Get( thread, &lock_context );
|
||||
the_thread = _Thread_Get( thread, &queue_context.Lock_context.Lock_context );
|
||||
|
||||
if ( the_thread == NULL ) {
|
||||
return ESRCH;
|
||||
}
|
||||
|
||||
cpu_self = _Thread_Dispatch_disable_critical( &lock_context );
|
||||
_ISR_lock_ISR_enable( &lock_context );
|
||||
|
||||
_Thread_Change_priority(
|
||||
_Thread_queue_Context_clear_priority_updates( &queue_context );
|
||||
_Thread_Wait_acquire_critical( the_thread, &queue_context );
|
||||
error = _POSIX_Set_sched_param(
|
||||
the_thread,
|
||||
0,
|
||||
&context,
|
||||
_POSIX_Set_sched_param_filter,
|
||||
false
|
||||
policy,
|
||||
param,
|
||||
budget_algorithm,
|
||||
budget_callout,
|
||||
&queue_context
|
||||
);
|
||||
|
||||
cpu_self = _Thread_Dispatch_disable_critical(
|
||||
&queue_context.Lock_context.Lock_context
|
||||
);
|
||||
_Thread_Wait_release( the_thread, &queue_context );
|
||||
_Thread_Priority_update( &queue_context );
|
||||
_Thread_Dispatch_enable( cpu_self );
|
||||
return context.error;
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -18,79 +18,47 @@
|
||||
#include <rtems/score/threadimpl.h>
|
||||
#include <rtems/score/schedulerimpl.h>
|
||||
|
||||
typedef struct {
|
||||
int prio;
|
||||
int error;
|
||||
} POSIX_Set_sched_prio_context;
|
||||
|
||||
static bool _POSIX_Set_sched_prio_filter(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Control *new_priority_p,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
POSIX_Set_sched_prio_context *context;
|
||||
int prio;
|
||||
const Scheduler_Control *scheduler;
|
||||
POSIX_API_Control *api;
|
||||
bool valid;
|
||||
Priority_Control current_priority;
|
||||
Priority_Control new_priority;
|
||||
|
||||
context = arg;
|
||||
prio = context->prio;
|
||||
scheduler = _Scheduler_Get_own( the_thread );
|
||||
|
||||
new_priority = _POSIX_Priority_To_core( scheduler, prio, &valid );
|
||||
if ( !valid ) {
|
||||
context->error = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
*new_priority_p = new_priority;
|
||||
|
||||
current_priority = _Thread_Get_priority( the_thread );
|
||||
the_thread->real_priority = new_priority;
|
||||
|
||||
api = the_thread->API_Extensions[ THREAD_API_POSIX ];
|
||||
|
||||
api->Sporadic.high_priority = new_priority;
|
||||
|
||||
if ( api->Sporadic.low_priority < new_priority ) {
|
||||
api->Sporadic.low_priority = new_priority;
|
||||
}
|
||||
|
||||
context->error = 0;
|
||||
return _Thread_Priority_less_than( current_priority, new_priority )
|
||||
|| !_Thread_Owns_resources( the_thread );
|
||||
}
|
||||
|
||||
int pthread_setschedprio( pthread_t thread, int prio )
|
||||
{
|
||||
Thread_Control *the_thread;
|
||||
Per_CPU_Control *cpu_self;
|
||||
POSIX_Set_sched_prio_context context;
|
||||
ISR_lock_Context lock_context;
|
||||
Thread_Control *the_thread;
|
||||
Per_CPU_Control *cpu_self;
|
||||
Thread_queue_Context queue_context;
|
||||
const Scheduler_Control *scheduler;
|
||||
Priority_Control new_priority;
|
||||
bool valid;
|
||||
|
||||
context.prio = prio;
|
||||
|
||||
the_thread = _Thread_Get( thread, &lock_context );
|
||||
the_thread = _Thread_Get( thread, &queue_context.Lock_context.Lock_context );
|
||||
|
||||
if ( the_thread == NULL ) {
|
||||
return ESRCH;
|
||||
}
|
||||
|
||||
cpu_self = _Thread_Dispatch_disable_critical( &lock_context );
|
||||
_ISR_lock_ISR_enable( &lock_context );
|
||||
_Thread_queue_Context_clear_priority_updates( &queue_context );
|
||||
_Thread_Wait_acquire_critical( the_thread, &queue_context );
|
||||
|
||||
_Thread_Change_priority(
|
||||
scheduler = _Scheduler_Get_own( the_thread );
|
||||
|
||||
new_priority = _POSIX_Priority_To_core( scheduler, prio, &valid );
|
||||
if ( !valid ) {
|
||||
_Thread_Wait_release( the_thread, &queue_context );
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
_Thread_Priority_change(
|
||||
the_thread,
|
||||
0,
|
||||
&context,
|
||||
_POSIX_Set_sched_prio_filter,
|
||||
true
|
||||
&the_thread->Real_priority,
|
||||
new_priority,
|
||||
true,
|
||||
&queue_context
|
||||
);
|
||||
|
||||
cpu_self = _Thread_Dispatch_disable_critical(
|
||||
&queue_context.Lock_context.Lock_context
|
||||
);
|
||||
_Thread_Wait_release( the_thread, &queue_context );
|
||||
|
||||
_Thread_Priority_update( &queue_context );
|
||||
|
||||
_Thread_Dispatch_enable( cpu_self );
|
||||
return context.error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -205,6 +205,12 @@ typedef struct {
|
||||
/** This field indicates the current state of the period. */
|
||||
rtems_rate_monotonic_period_states state;
|
||||
|
||||
/**
|
||||
* @brief A priority node for use by the scheduler job release and cancel
|
||||
* operations.
|
||||
*/
|
||||
Priority_Node Priority;
|
||||
|
||||
/**
|
||||
* This field contains the length of the next period to be
|
||||
* executed.
|
||||
|
||||
@@ -27,18 +27,22 @@ void _Rate_monotonic_Cancel(
|
||||
ISR_lock_Context *lock_context
|
||||
)
|
||||
{
|
||||
Per_CPU_Control *cpu_self;
|
||||
Thread_Control *update_priority;
|
||||
Per_CPU_Control *cpu_self;
|
||||
Thread_queue_Context queue_context;
|
||||
|
||||
_Rate_monotonic_Acquire_critical( the_period, lock_context );
|
||||
|
||||
_Watchdog_Per_CPU_remove_relative( &the_period->Timer );
|
||||
the_period->state = RATE_MONOTONIC_INACTIVE;
|
||||
update_priority = _Scheduler_Cancel_job( the_period->owner );
|
||||
_Scheduler_Cancel_job(
|
||||
the_period->owner,
|
||||
&the_period->Priority,
|
||||
&queue_context
|
||||
);
|
||||
|
||||
cpu_self = _Thread_Dispatch_disable_critical( lock_context );
|
||||
_Rate_monotonic_Release( the_period, lock_context );
|
||||
_Thread_Update_priority( update_priority );
|
||||
_Thread_Priority_update( &queue_context );
|
||||
_Thread_Dispatch_enable( cpu_self );
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,8 @@ rtems_status_code rtems_rate_monotonic_create(
|
||||
}
|
||||
|
||||
_ISR_lock_Initialize( &the_period->Lock, "Rate Monotonic Period" );
|
||||
_Priority_Node_initialize( &the_period->Priority, 0 );
|
||||
_Priority_Node_set_inactive( &the_period->Priority );
|
||||
|
||||
the_period->owner = _Thread_Get_executing();
|
||||
the_period->state = RATE_MONOTONIC_INACTIVE;
|
||||
|
||||
@@ -70,9 +70,9 @@ static void _Rate_monotonic_Release_job(
|
||||
ISR_lock_Context *lock_context
|
||||
)
|
||||
{
|
||||
Per_CPU_Control *cpu_self;
|
||||
Thread_Control *update_priority;
|
||||
uint64_t deadline;
|
||||
Per_CPU_Control *cpu_self;
|
||||
Thread_queue_Context queue_context;
|
||||
uint64_t deadline;
|
||||
|
||||
cpu_self = _Thread_Dispatch_disable_critical( lock_context );
|
||||
|
||||
@@ -81,10 +81,15 @@ static void _Rate_monotonic_Release_job(
|
||||
cpu_self,
|
||||
next_length
|
||||
);
|
||||
update_priority = _Scheduler_Release_job( owner, deadline );
|
||||
_Scheduler_Release_job(
|
||||
owner,
|
||||
&the_period->Priority,
|
||||
deadline,
|
||||
&queue_context
|
||||
);
|
||||
|
||||
_Rate_monotonic_Release( the_period, lock_context );
|
||||
_Thread_Update_priority( update_priority );
|
||||
_Thread_Priority_update( &queue_context );
|
||||
_Thread_Dispatch_enable( cpu_self );
|
||||
}
|
||||
|
||||
|
||||
@@ -42,16 +42,18 @@ static rtems_status_code _Semaphore_Set_priority(
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
bool valid;
|
||||
Priority_Control core_priority;
|
||||
Priority_Control old_priority;
|
||||
rtems_status_code sc;
|
||||
bool valid;
|
||||
Priority_Control core_priority;
|
||||
Priority_Control old_priority;
|
||||
Per_CPU_Control *cpu_self;
|
||||
|
||||
core_priority = _RTEMS_Priority_To_core( scheduler, new_priority, &valid );
|
||||
if ( new_priority != RTEMS_CURRENT_PRIORITY && !valid ) {
|
||||
return RTEMS_INVALID_PRIORITY;
|
||||
}
|
||||
|
||||
_Thread_queue_Context_clear_priority_updates( queue_context );
|
||||
_Thread_queue_Acquire_critical(
|
||||
&the_semaphore->Core_control.Wait_queue,
|
||||
queue_context
|
||||
@@ -71,7 +73,8 @@ static rtems_status_code _Semaphore_Set_priority(
|
||||
if ( sc == RTEMS_SUCCESSFUL && new_priority != RTEMS_CURRENT_PRIORITY ) {
|
||||
_CORE_ceiling_mutex_Set_priority(
|
||||
&the_semaphore->Core_control.Mutex,
|
||||
core_priority
|
||||
core_priority,
|
||||
queue_context
|
||||
);
|
||||
}
|
||||
|
||||
@@ -106,10 +109,15 @@ static rtems_status_code _Semaphore_Set_priority(
|
||||
break;
|
||||
}
|
||||
|
||||
cpu_self = _Thread_Dispatch_disable_critical(
|
||||
&queue_context->Lock_context.Lock_context
|
||||
);
|
||||
_Thread_queue_Release(
|
||||
&the_semaphore->Core_control.Wait_queue,
|
||||
queue_context
|
||||
);
|
||||
_Thread_Priority_update( queue_context );
|
||||
_Thread_Dispatch_enable( cpu_self );
|
||||
|
||||
*old_priority_p = _RTEMS_Priority_From_core( scheduler, old_priority );
|
||||
return sc;
|
||||
|
||||
@@ -22,50 +22,43 @@
|
||||
#include <rtems/score/schedulerimpl.h>
|
||||
#include <rtems/score/threadimpl.h>
|
||||
|
||||
typedef struct {
|
||||
const Scheduler_Control *scheduler;
|
||||
rtems_task_priority new_priority;
|
||||
Priority_Control old_priority;
|
||||
rtems_status_code status;
|
||||
} RTEMS_tasks_Set_priority_context;
|
||||
|
||||
static bool _RTEMS_tasks_Set_priority_filter(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Control *new_priority_p,
|
||||
void *arg
|
||||
static rtems_status_code _RTEMS_tasks_Set_priority(
|
||||
Thread_Control *the_thread,
|
||||
const Scheduler_Control *scheduler,
|
||||
Priority_Control new_priority,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
RTEMS_tasks_Set_priority_context *context;
|
||||
const Scheduler_Control *scheduler;
|
||||
bool valid;
|
||||
Priority_Control current_priority;
|
||||
Priority_Control new_priority;
|
||||
Priority_Control core_new_priority;
|
||||
bool valid;
|
||||
Per_CPU_Control *cpu_self;
|
||||
|
||||
context = arg;
|
||||
scheduler = _Scheduler_Get_own( the_thread );
|
||||
current_priority = _Thread_Get_priority( the_thread );
|
||||
|
||||
context->scheduler = scheduler;
|
||||
context->old_priority = current_priority;
|
||||
|
||||
new_priority = _RTEMS_Priority_To_core(
|
||||
core_new_priority = _RTEMS_Priority_To_core(
|
||||
scheduler,
|
||||
context->new_priority,
|
||||
new_priority,
|
||||
&valid
|
||||
);
|
||||
|
||||
*new_priority_p = new_priority;
|
||||
|
||||
if ( !valid ) {
|
||||
context->status = RTEMS_INVALID_PRIORITY;
|
||||
return false;
|
||||
_Thread_Wait_release( the_thread, queue_context );
|
||||
return RTEMS_INVALID_PRIORITY;
|
||||
}
|
||||
|
||||
the_thread->real_priority = new_priority;
|
||||
context->status = STATUS_SUCCESSFUL;
|
||||
|
||||
return _Thread_Priority_less_than( current_priority, new_priority )
|
||||
|| !_Thread_Owns_resources( the_thread );
|
||||
_Thread_queue_Context_clear_priority_updates( queue_context );
|
||||
_Thread_Priority_change(
|
||||
the_thread,
|
||||
&the_thread->Real_priority,
|
||||
core_new_priority,
|
||||
false,
|
||||
queue_context
|
||||
);
|
||||
cpu_self = _Thread_Dispatch_disable_critical(
|
||||
&queue_context->Lock_context.Lock_context
|
||||
);
|
||||
_Thread_Wait_release( the_thread, queue_context );
|
||||
_Thread_Priority_update( queue_context );
|
||||
_Thread_Dispatch_enable( cpu_self );
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
rtems_status_code rtems_task_set_priority(
|
||||
@@ -75,7 +68,7 @@ rtems_status_code rtems_task_set_priority(
|
||||
)
|
||||
{
|
||||
Thread_Control *the_thread;
|
||||
ISR_lock_Context lock_context;
|
||||
Thread_queue_Context queue_context;
|
||||
const Scheduler_Control *scheduler;
|
||||
Priority_Control old_priority;
|
||||
rtems_status_code status;
|
||||
@@ -84,7 +77,8 @@ rtems_status_code rtems_task_set_priority(
|
||||
return RTEMS_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
the_thread = _Thread_Get( id, &lock_context );
|
||||
_Thread_queue_Context_initialize( &queue_context );
|
||||
the_thread = _Thread_Get( id, &queue_context.Lock_context.Lock_context );
|
||||
|
||||
if ( the_thread == NULL ) {
|
||||
#if defined(RTEMS_MULTIPROCESSING)
|
||||
@@ -94,31 +88,20 @@ rtems_status_code rtems_task_set_priority(
|
||||
#endif
|
||||
}
|
||||
|
||||
_Thread_Wait_acquire_critical( the_thread, &queue_context );
|
||||
|
||||
scheduler = _Scheduler_Get_own( the_thread );
|
||||
old_priority = _Thread_Get_priority( the_thread );
|
||||
|
||||
if ( new_priority != RTEMS_CURRENT_PRIORITY ) {
|
||||
RTEMS_tasks_Set_priority_context context;
|
||||
Per_CPU_Control *cpu_self;
|
||||
|
||||
cpu_self = _Thread_Dispatch_disable_critical( &lock_context );
|
||||
_ISR_lock_ISR_enable( &lock_context );
|
||||
|
||||
context.new_priority = new_priority;
|
||||
_Thread_Change_priority(
|
||||
status = _RTEMS_tasks_Set_priority(
|
||||
the_thread,
|
||||
0,
|
||||
&context,
|
||||
_RTEMS_tasks_Set_priority_filter,
|
||||
false
|
||||
scheduler,
|
||||
new_priority,
|
||||
&queue_context
|
||||
);
|
||||
|
||||
_Thread_Dispatch_enable( cpu_self );
|
||||
scheduler = context.scheduler;
|
||||
old_priority = context.old_priority;
|
||||
status = context.status;
|
||||
} else {
|
||||
_Thread_State_acquire_critical( the_thread, &lock_context );
|
||||
scheduler = _Scheduler_Get_own( the_thread );
|
||||
old_priority = _Thread_Get_priority( the_thread );
|
||||
_Thread_State_release( the_thread, &lock_context );
|
||||
_Thread_Wait_release( the_thread, &queue_context );
|
||||
status = RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ include_rtems_score_HEADERS += include/rtems/score/objectimpl.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/onceimpl.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/percpu.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/priority.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/priorityimpl.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/prioritybitmap.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/prioritybitmapimpl.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/profiling.h
|
||||
@@ -300,7 +301,7 @@ libscore_a_SOURCES += src/thread.c src/threadchangepriority.c \
|
||||
src/threaddispatch.c \
|
||||
src/threadget.c src/threadhandler.c src/threadinitialize.c \
|
||||
src/threadloadenv.c \
|
||||
src/threadrestart.c src/threadsetpriority.c \
|
||||
src/threadrestart.c \
|
||||
src/threadsetstate.c \
|
||||
src/threadstackallocate.c src/threadstackfree.c src/threadstart.c \
|
||||
src/threadstartmultitasking.c src/iterateoverthreads.c
|
||||
|
||||
@@ -82,9 +82,9 @@ typedef struct {
|
||||
CORE_recursive_mutex_Control Recursive;
|
||||
|
||||
/**
|
||||
* @brief The priority ceiling value for the mutex owner.
|
||||
* @brief The priority ceiling node for the mutex owner.
|
||||
*/
|
||||
Priority_Control priority_ceiling;
|
||||
Priority_Node Priority_ceiling;
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
/**
|
||||
|
||||
@@ -124,32 +124,6 @@ RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_owner(
|
||||
return _CORE_mutex_Get_owner( the_mutex ) == the_thread;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _CORE_mutex_Restore_priority(
|
||||
Thread_Control *executing
|
||||
)
|
||||
{
|
||||
/*
|
||||
* Whether or not someone is waiting for the mutex, an
|
||||
* inherited priority must be lowered if this is the last
|
||||
* mutex (i.e. resource) this task has.
|
||||
*/
|
||||
if ( !_Thread_Owns_resources( executing ) ) {
|
||||
/*
|
||||
* Ensure that the executing resource count is visible to all other
|
||||
* processors and that we read the latest priority restore hint.
|
||||
*/
|
||||
_Atomic_Fence( ATOMIC_ORDER_ACQ_REL );
|
||||
|
||||
if ( executing->priority_restore_hint ) {
|
||||
Per_CPU_Control *cpu_self;
|
||||
|
||||
cpu_self = _Thread_Dispatch_disable();
|
||||
_Thread_Restore_priority( executing );
|
||||
_Thread_Dispatch_enable( cpu_self );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _CORE_recursive_mutex_Initialize(
|
||||
CORE_recursive_mutex_Control *the_mutex
|
||||
)
|
||||
@@ -212,7 +186,6 @@ RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Surrender(
|
||||
{
|
||||
unsigned int nest_level;
|
||||
Thread_queue_Heads *heads;
|
||||
bool keep_priority;
|
||||
|
||||
_CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context );
|
||||
|
||||
@@ -232,29 +205,19 @@ RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Surrender(
|
||||
--executing->resource_count;
|
||||
_CORE_mutex_Set_owner( &the_mutex->Mutex, NULL );
|
||||
|
||||
/*
|
||||
* Ensure that the owner resource count is visible to all other
|
||||
* processors and that we read the latest priority restore
|
||||
* hint.
|
||||
*/
|
||||
_Atomic_Fence( ATOMIC_ORDER_ACQ_REL );
|
||||
|
||||
heads = the_mutex->Mutex.Wait_queue.Queue.heads;
|
||||
keep_priority = _Thread_Owns_resources( executing )
|
||||
|| !executing->priority_restore_hint;
|
||||
|
||||
if ( heads == NULL && keep_priority ) {
|
||||
if ( heads == NULL ) {
|
||||
_CORE_mutex_Release( &the_mutex->Mutex, queue_context );
|
||||
return STATUS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
_Thread_queue_Surrender(
|
||||
&the_mutex->Mutex.Wait_queue.Queue,
|
||||
CORE_MUTEX_TQ_PRIORITY_INHERIT_OPERATIONS,
|
||||
heads,
|
||||
executing,
|
||||
keep_priority,
|
||||
queue_context
|
||||
queue_context,
|
||||
CORE_MUTEX_TQ_PRIORITY_INHERIT_OPERATIONS
|
||||
);
|
||||
return STATUS_SUCCESSFUL;
|
||||
}
|
||||
@@ -349,7 +312,7 @@ RTEMS_INLINE_ROUTINE void _CORE_ceiling_mutex_Initialize(
|
||||
)
|
||||
{
|
||||
_CORE_recursive_mutex_Initialize( &the_mutex->Recursive );
|
||||
the_mutex->priority_ceiling = priority_ceiling;
|
||||
_Priority_Node_initialize( &the_mutex->Priority_ceiling, priority_ceiling );
|
||||
#if defined(RTEMS_SMP)
|
||||
the_mutex->scheduler = scheduler;
|
||||
#endif
|
||||
@@ -369,17 +332,34 @@ _CORE_ceiling_mutex_Get_scheduler(
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _CORE_ceiling_mutex_Set_priority(
|
||||
CORE_ceiling_mutex_Control *the_mutex,
|
||||
Priority_Control priority_ceiling
|
||||
Priority_Control priority_ceiling,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
the_mutex->priority_ceiling = priority_ceiling;
|
||||
Thread_Control *owner;
|
||||
|
||||
owner = _CORE_mutex_Get_owner( &the_mutex->Recursive.Mutex );
|
||||
|
||||
if ( owner != NULL ) {
|
||||
_Thread_Wait_acquire( owner, queue_context );
|
||||
_Thread_Priority_change(
|
||||
owner,
|
||||
&the_mutex->Priority_ceiling,
|
||||
priority_ceiling,
|
||||
false,
|
||||
queue_context
|
||||
);
|
||||
_Thread_Wait_release( owner, queue_context );
|
||||
} else {
|
||||
the_mutex->Priority_ceiling.priority = priority_ceiling;
|
||||
}
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE Priority_Control _CORE_ceiling_mutex_Get_priority(
|
||||
const CORE_ceiling_mutex_Control *the_mutex
|
||||
)
|
||||
{
|
||||
return the_mutex->priority_ceiling;
|
||||
return the_mutex->Priority_ceiling.priority;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Set_owner(
|
||||
@@ -388,31 +368,38 @@ RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Set_owner(
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
Priority_Control priority_ceiling;
|
||||
Priority_Control current_priority;
|
||||
ISR_lock_Context lock_context;
|
||||
Scheduler_Node *own_node;
|
||||
Per_CPU_Control *cpu_self;
|
||||
|
||||
priority_ceiling = the_mutex->priority_ceiling;
|
||||
current_priority = _Thread_Get_priority( owner );
|
||||
_Thread_queue_Context_clear_priority_updates( queue_context );
|
||||
_Thread_Wait_acquire_default_critical( owner, &lock_context );
|
||||
|
||||
if ( current_priority < priority_ceiling ) {
|
||||
own_node = _Thread_Scheduler_get_own_node( owner );
|
||||
|
||||
if (
|
||||
own_node->Wait.Priority.Node.priority
|
||||
< the_mutex->Priority_ceiling.priority
|
||||
) {
|
||||
_Thread_Wait_release_default_critical( owner, &lock_context );
|
||||
_CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
|
||||
return STATUS_MUTEX_CEILING_VIOLATED;
|
||||
}
|
||||
|
||||
_CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, owner );
|
||||
++owner->resource_count;
|
||||
|
||||
if ( current_priority == priority_ceiling ) {
|
||||
_CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
|
||||
return STATUS_SUCCESSFUL;
|
||||
}
|
||||
_Thread_Priority_add(
|
||||
owner,
|
||||
&the_mutex->Priority_ceiling,
|
||||
queue_context
|
||||
);
|
||||
_Thread_Wait_release_default_critical( owner, &lock_context );
|
||||
|
||||
cpu_self = _Thread_Dispatch_disable_critical(
|
||||
&queue_context->Lock_context.Lock_context
|
||||
);
|
||||
_CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
|
||||
_Thread_Raise_priority( owner, priority_ceiling );
|
||||
_Thread_Priority_update( queue_context );
|
||||
_Thread_Dispatch_enable( cpu_self );
|
||||
return STATUS_SUCCESSFUL;
|
||||
}
|
||||
@@ -472,8 +459,10 @@ RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Surrender(
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
unsigned int nest_level;
|
||||
Thread_Control *new_owner;
|
||||
unsigned int nest_level;
|
||||
ISR_lock_Context lock_context;
|
||||
Per_CPU_Control *cpu_self;
|
||||
Thread_Control *new_owner;
|
||||
|
||||
_CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context );
|
||||
|
||||
@@ -492,47 +481,50 @@ RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Surrender(
|
||||
|
||||
--executing->resource_count;
|
||||
|
||||
_Thread_queue_Context_clear_priority_updates( queue_context );
|
||||
_Thread_Wait_acquire_default_critical( executing, &lock_context );
|
||||
_Thread_Priority_remove(
|
||||
executing,
|
||||
&the_mutex->Priority_ceiling,
|
||||
queue_context
|
||||
);
|
||||
_Thread_Wait_release_default_critical( executing, &lock_context );
|
||||
|
||||
new_owner = _Thread_queue_First_locked(
|
||||
&the_mutex->Recursive.Mutex.Wait_queue,
|
||||
CORE_MUTEX_TQ_OPERATIONS
|
||||
);
|
||||
_CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, new_owner );
|
||||
|
||||
cpu_self = _Thread_Dispatch_disable_critical(
|
||||
&queue_context->Lock_context.Lock_context
|
||||
);
|
||||
|
||||
if ( new_owner != NULL ) {
|
||||
bool unblock;
|
||||
|
||||
/*
|
||||
* We must extract the thread now since this will restore its default
|
||||
* thread lock. This is necessary to avoid a deadlock in the
|
||||
* _Thread_Change_priority() below due to a recursive thread queue lock
|
||||
* acquire.
|
||||
*/
|
||||
unblock = _Thread_queue_Extract_locked(
|
||||
&the_mutex->Recursive.Mutex.Wait_queue.Queue,
|
||||
CORE_MUTEX_TQ_OPERATIONS,
|
||||
new_owner,
|
||||
queue_context
|
||||
);
|
||||
|
||||
#if defined(RTEMS_MULTIPROCESSING)
|
||||
if ( _Objects_Is_local_id( new_owner->Object.id ) )
|
||||
#endif
|
||||
{
|
||||
++new_owner->resource_count;
|
||||
_Thread_Raise_priority( new_owner, the_mutex->priority_ceiling );
|
||||
_Thread_Priority_add(
|
||||
new_owner,
|
||||
&the_mutex->Priority_ceiling,
|
||||
queue_context
|
||||
);
|
||||
}
|
||||
|
||||
_Thread_queue_Unblock_critical(
|
||||
unblock,
|
||||
_Thread_queue_Extract_critical(
|
||||
&the_mutex->Recursive.Mutex.Wait_queue.Queue,
|
||||
CORE_MUTEX_TQ_OPERATIONS,
|
||||
new_owner,
|
||||
&queue_context->Lock_context.Lock_context
|
||||
queue_context
|
||||
);
|
||||
} else {
|
||||
_CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context );
|
||||
}
|
||||
|
||||
_CORE_mutex_Restore_priority( executing );
|
||||
_Thread_Priority_update( queue_context );
|
||||
_Thread_Dispatch_enable( cpu_self );
|
||||
return STATUS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,12 +80,9 @@ typedef struct {
|
||||
Thread_Control *thread;
|
||||
|
||||
/**
|
||||
* @brief The initial priority of the thread at the begin of the resource
|
||||
* obtain sequence.
|
||||
*
|
||||
* Used to restore the priority after a release of this resource or timeout.
|
||||
* @brief The ceiling priority used by the rival thread.
|
||||
*/
|
||||
Priority_Control initial_priority;
|
||||
Priority_Node Ceiling_priority;
|
||||
|
||||
/**
|
||||
* @brief The initial help state of the thread at the begin of the resource
|
||||
@@ -135,10 +132,9 @@ struct MRSP_Control {
|
||||
Chain_Control Rivals;
|
||||
|
||||
/**
|
||||
* @brief The initial priority of the owner before it was elevated to the
|
||||
* ceiling priority.
|
||||
* @brief The ceiling priority used by the owner thread.
|
||||
*/
|
||||
Priority_Control initial_priority_of_owner;
|
||||
Priority_Node Ceiling_priority;
|
||||
|
||||
/**
|
||||
* @brief One ceiling priority per scheduler instance.
|
||||
|
||||
@@ -77,53 +77,115 @@ RTEMS_INLINE_ROUTINE void _MRSP_Release(
|
||||
_Thread_queue_Release( &mrsp->Wait_queue, queue_context );
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _MRSP_Restore_priority_filter(
|
||||
Thread_Control *thread,
|
||||
Priority_Control *new_priority,
|
||||
void *arg
|
||||
RTEMS_INLINE_ROUTINE Priority_Control _MRSP_Get_priority(
|
||||
const MRSP_Control *mrsp,
|
||||
const Scheduler_Control *scheduler
|
||||
)
|
||||
{
|
||||
*new_priority = _Thread_Priority_highest(
|
||||
thread->real_priority,
|
||||
*new_priority
|
||||
);
|
||||
uint32_t scheduler_index;
|
||||
|
||||
return *new_priority != _Thread_Get_priority( thread );
|
||||
scheduler_index = _Scheduler_Get_index( scheduler );
|
||||
return mrsp->ceiling_priorities[ scheduler_index ];
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _MRSP_Restore_priority(
|
||||
Thread_Control *thread,
|
||||
Priority_Control initial_priority
|
||||
RTEMS_INLINE_ROUTINE void _MRSP_Set_priority(
|
||||
MRSP_Control *mrsp,
|
||||
const Scheduler_Control *scheduler,
|
||||
Priority_Control new_priority
|
||||
)
|
||||
{
|
||||
/*
|
||||
* The Thread_Control::resource_count is used by the normal priority ceiling
|
||||
* or priority inheritance semaphores.
|
||||
*/
|
||||
if ( thread->resource_count == 0 ) {
|
||||
_Thread_Change_priority(
|
||||
thread,
|
||||
initial_priority,
|
||||
NULL,
|
||||
_MRSP_Restore_priority_filter,
|
||||
true
|
||||
);
|
||||
}
|
||||
uint32_t scheduler_index;
|
||||
|
||||
scheduler_index = _Scheduler_Get_index( scheduler );
|
||||
mrsp->ceiling_priorities[ scheduler_index ] = new_priority;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _MRSP_Claim_ownership(
|
||||
RTEMS_INLINE_ROUTINE Status_Control _MRSP_Raise_priority(
|
||||
MRSP_Control *mrsp,
|
||||
Thread_Control *new_owner,
|
||||
Priority_Control initial_priority,
|
||||
Priority_Control ceiling_priority,
|
||||
Thread_Control *thread,
|
||||
Priority_Node *priority_node,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
Status_Control status;
|
||||
ISR_lock_Context lock_context;
|
||||
const Scheduler_Control *scheduler;
|
||||
Priority_Control ceiling_priority;
|
||||
Scheduler_Node *own_node;
|
||||
|
||||
_Thread_queue_Context_clear_priority_updates( queue_context );
|
||||
_Thread_Wait_acquire_default_critical( thread, &lock_context );
|
||||
|
||||
scheduler = _Scheduler_Get_own( thread );
|
||||
own_node = _Thread_Scheduler_get_own_node( thread );
|
||||
ceiling_priority = _MRSP_Get_priority( mrsp, scheduler );
|
||||
|
||||
if ( ceiling_priority <= own_node->Wait.Priority.Node.priority ) {
|
||||
_Priority_Node_initialize( priority_node, ceiling_priority );
|
||||
_Thread_Priority_add( thread, priority_node, queue_context );
|
||||
status = STATUS_SUCCESSFUL;
|
||||
} else {
|
||||
status = STATUS_MUTEX_CEILING_VIOLATED;
|
||||
}
|
||||
|
||||
_Thread_Wait_release_default_critical( thread, &lock_context );
|
||||
return status;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _MRSP_Remove_priority(
|
||||
Thread_Control *thread,
|
||||
Priority_Node *priority_node,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
ISR_lock_Context lock_context;
|
||||
|
||||
_Thread_queue_Context_clear_priority_updates( queue_context );
|
||||
_Thread_Wait_acquire_default_critical( thread, &lock_context );
|
||||
_Thread_Priority_remove( thread, priority_node, queue_context );
|
||||
_Thread_Wait_release_default_critical( thread, &lock_context );
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _MRSP_Replace_priority(
|
||||
MRSP_Control *mrsp,
|
||||
Thread_Control *thread,
|
||||
MRSP_Rival *rival
|
||||
)
|
||||
{
|
||||
ISR_lock_Context lock_context;
|
||||
|
||||
_Thread_Wait_acquire_default_critical( thread, &lock_context );
|
||||
_Thread_Priority_replace(
|
||||
thread,
|
||||
&rival->Ceiling_priority,
|
||||
&mrsp->Ceiling_priority
|
||||
);
|
||||
_Thread_Wait_release_default_critical( thread, &lock_context );
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE Status_Control _MRSP_Claim_ownership(
|
||||
MRSP_Control *mrsp,
|
||||
Thread_Control *new_owner,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
Status_Control status;
|
||||
Per_CPU_Control *cpu_self;
|
||||
|
||||
status = _MRSP_Raise_priority(
|
||||
mrsp,
|
||||
new_owner,
|
||||
&mrsp->Ceiling_priority,
|
||||
queue_context
|
||||
);
|
||||
|
||||
if ( status != STATUS_SUCCESSFUL ) {
|
||||
_MRSP_Release( mrsp, queue_context );
|
||||
return status;
|
||||
}
|
||||
|
||||
_Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource );
|
||||
_Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node );
|
||||
mrsp->initial_priority_of_owner = initial_priority;
|
||||
_Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER );
|
||||
|
||||
cpu_self = _Thread_Dispatch_disable_critical(
|
||||
@@ -131,9 +193,10 @@ RTEMS_INLINE_ROUTINE void _MRSP_Claim_ownership(
|
||||
);
|
||||
_MRSP_Release( mrsp, queue_context );
|
||||
|
||||
_Thread_Raise_priority( new_owner, ceiling_priority );
|
||||
_Thread_Priority_update( queue_context );
|
||||
|
||||
_Thread_Dispatch_enable( cpu_self );
|
||||
return STATUS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE Status_Control _MRSP_Initialize(
|
||||
@@ -178,35 +241,16 @@ RTEMS_INLINE_ROUTINE Status_Control _MRSP_Initialize(
|
||||
return STATUS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE Priority_Control _MRSP_Get_priority(
|
||||
const MRSP_Control *mrsp,
|
||||
const Scheduler_Control *scheduler
|
||||
)
|
||||
{
|
||||
uint32_t scheduler_index;
|
||||
|
||||
scheduler_index = _Scheduler_Get_index( scheduler );
|
||||
return mrsp->ceiling_priorities[ scheduler_index ];
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _MRSP_Set_priority(
|
||||
MRSP_Control *mrsp,
|
||||
const Scheduler_Control *scheduler,
|
||||
Priority_Control new_priority
|
||||
)
|
||||
{
|
||||
uint32_t scheduler_index;
|
||||
|
||||
scheduler_index = _Scheduler_Get_index( scheduler );
|
||||
mrsp->ceiling_priorities[ scheduler_index ] = new_priority;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _MRSP_Timeout( Watchdog_Control *watchdog )
|
||||
{
|
||||
MRSP_Rival *rival = RTEMS_CONTAINER_OF( watchdog, MRSP_Rival, Watchdog );
|
||||
MRSP_Control *mrsp = rival->resource;
|
||||
Thread_Control *thread = rival->thread;
|
||||
Thread_queue_Context queue_context;
|
||||
MRSP_Rival *rival;
|
||||
MRSP_Control *mrsp;
|
||||
Thread_Control *thread;
|
||||
Thread_queue_Context queue_context;
|
||||
|
||||
rival = RTEMS_CONTAINER_OF( watchdog, MRSP_Rival, Watchdog );
|
||||
mrsp = rival->resource;
|
||||
thread = rival->thread;
|
||||
|
||||
_Thread_queue_Context_initialize( &queue_context );
|
||||
_ISR_lock_ISR_disable( &queue_context.Lock_context.Lock_context );
|
||||
@@ -215,6 +259,8 @@ RTEMS_INLINE_ROUTINE void _MRSP_Timeout( Watchdog_Control *watchdog )
|
||||
if ( rival->status == MRSP_WAIT_FOR_OWNERSHIP ) {
|
||||
ISR_lock_Context giant_lock_context;
|
||||
|
||||
_MRSP_Remove_priority( thread, &rival->Ceiling_priority, &queue_context );
|
||||
|
||||
_MRSP_Giant_acquire( &giant_lock_context );
|
||||
|
||||
_Chain_Extract_unprotected( &rival->Node );
|
||||
@@ -228,6 +274,8 @@ RTEMS_INLINE_ROUTINE void _MRSP_Timeout( Watchdog_Control *watchdog )
|
||||
rival->status = STATUS_TIMEOUT;
|
||||
|
||||
_MRSP_Release( mrsp, &queue_context );
|
||||
|
||||
_Thread_Priority_update( &queue_context );
|
||||
} else {
|
||||
_MRSP_Release( mrsp, &queue_context );
|
||||
}
|
||||
@@ -237,23 +285,34 @@ RTEMS_INLINE_ROUTINE Status_Control _MRSP_Wait_for_ownership(
|
||||
MRSP_Control *mrsp,
|
||||
Resource_Node *owner,
|
||||
Thread_Control *executing,
|
||||
Priority_Control initial_priority,
|
||||
Priority_Control ceiling_priority,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
Status_Control status;
|
||||
MRSP_Rival rival;
|
||||
Thread_Life_state life_state;
|
||||
Per_CPU_Control *cpu_self;
|
||||
ISR_lock_Context giant_lock_context;
|
||||
ISR_Level level;
|
||||
Watchdog_Interval timeout = queue_context->timeout;
|
||||
Status_Control status;
|
||||
MRSP_Rival rival;
|
||||
Thread_Life_state life_state;
|
||||
Per_CPU_Control *cpu_self;
|
||||
ISR_lock_Context giant_lock_context;
|
||||
ISR_Level level;
|
||||
Watchdog_Interval timeout;
|
||||
|
||||
_Assert( queue_context->timeout_discipline == WATCHDOG_RELATIVE );
|
||||
|
||||
status = _MRSP_Raise_priority(
|
||||
mrsp,
|
||||
executing,
|
||||
&rival.Ceiling_priority,
|
||||
queue_context
|
||||
);
|
||||
|
||||
if ( status != STATUS_SUCCESSFUL ) {
|
||||
_MRSP_Release( mrsp, queue_context );
|
||||
return status;
|
||||
}
|
||||
|
||||
rival.thread = executing;
|
||||
rival.resource = mrsp;
|
||||
rival.initial_priority = initial_priority;
|
||||
_Chain_Initialize_node( &rival.Node );
|
||||
|
||||
_MRSP_Giant_acquire( &giant_lock_context );
|
||||
|
||||
@@ -277,7 +336,9 @@ RTEMS_INLINE_ROUTINE Status_Control _MRSP_Wait_for_ownership(
|
||||
);
|
||||
_MRSP_Release( mrsp, queue_context );
|
||||
|
||||
_Thread_Raise_priority( executing, ceiling_priority );
|
||||
_Thread_Priority_update( queue_context );
|
||||
|
||||
timeout = (Watchdog_Interval) queue_context->timeout;
|
||||
|
||||
if ( timeout > 0 ) {
|
||||
_Watchdog_Preinitialize( &rival.Watchdog, cpu_self );
|
||||
@@ -307,10 +368,6 @@ RTEMS_INLINE_ROUTINE Status_Control _MRSP_Wait_for_ownership(
|
||||
&cpu_self->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ]
|
||||
);
|
||||
_ISR_Local_enable( level );
|
||||
|
||||
if ( status == STATUS_TIMEOUT ) {
|
||||
_MRSP_Restore_priority( executing, initial_priority );
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -323,44 +380,20 @@ RTEMS_INLINE_ROUTINE Status_Control _MRSP_Seize(
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
Status_Control status;
|
||||
const Scheduler_Control *scheduler = _Scheduler_Get_own( executing );
|
||||
Priority_Control initial_priority = _Thread_Get_priority( executing );
|
||||
Priority_Control ceiling_priority = _MRSP_Get_priority( mrsp, scheduler );
|
||||
bool priority_ok = !_Thread_Priority_less_than(
|
||||
ceiling_priority,
|
||||
initial_priority
|
||||
);
|
||||
Resource_Node *owner;
|
||||
|
||||
if ( !priority_ok) {
|
||||
_ISR_lock_ISR_enable( &queue_context->Lock_context.Lock_context );
|
||||
return STATUS_MUTEX_CEILING_VIOLATED;
|
||||
}
|
||||
Status_Control status;
|
||||
Resource_Node *owner;
|
||||
|
||||
_MRSP_Acquire_critical( mrsp, queue_context );
|
||||
|
||||
owner = _Resource_Get_owner( &mrsp->Resource );
|
||||
|
||||
if ( owner == NULL ) {
|
||||
_MRSP_Claim_ownership(
|
||||
mrsp,
|
||||
executing,
|
||||
initial_priority,
|
||||
ceiling_priority,
|
||||
queue_context
|
||||
);
|
||||
status = STATUS_SUCCESSFUL;
|
||||
status = _MRSP_Claim_ownership( mrsp, executing, queue_context );
|
||||
} else if (
|
||||
wait
|
||||
&& _Resource_Node_get_root( owner ) != &executing->Resource_node
|
||||
) {
|
||||
status = _MRSP_Wait_for_ownership(
|
||||
mrsp,
|
||||
owner,
|
||||
executing,
|
||||
initial_priority,
|
||||
ceiling_priority,
|
||||
queue_context
|
||||
);
|
||||
status = _MRSP_Wait_for_ownership( mrsp, owner, executing, queue_context );
|
||||
} else {
|
||||
_MRSP_Release( mrsp, queue_context );
|
||||
/* Not available, nested access or deadlock */
|
||||
@@ -376,9 +409,8 @@ RTEMS_INLINE_ROUTINE Status_Control _MRSP_Surrender(
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
Priority_Control initial_priority;
|
||||
Per_CPU_Control *cpu_self;
|
||||
ISR_lock_Context giant_lock_context;
|
||||
ISR_lock_Context giant_lock_context;
|
||||
Per_CPU_Control *cpu_self;
|
||||
|
||||
if ( _Resource_Get_owner( &mrsp->Resource ) != &executing->Resource_node ) {
|
||||
_ISR_lock_ISR_enable( &queue_context->Lock_context.Lock_context );
|
||||
@@ -395,10 +427,8 @@ RTEMS_INLINE_ROUTINE Status_Control _MRSP_Surrender(
|
||||
return STATUS_RELEASE_ORDER_VIOLATION;
|
||||
}
|
||||
|
||||
initial_priority = mrsp->initial_priority_of_owner;
|
||||
|
||||
_MRSP_Acquire_critical( mrsp, queue_context );
|
||||
|
||||
_MRSP_Remove_priority( executing, &mrsp->Ceiling_priority, queue_context );
|
||||
_MRSP_Giant_acquire( &giant_lock_context );
|
||||
|
||||
_Resource_Extract( &mrsp->Resource );
|
||||
@@ -406,10 +436,11 @@ RTEMS_INLINE_ROUTINE Status_Control _MRSP_Surrender(
|
||||
if ( _Chain_Is_empty( &mrsp->Rivals ) ) {
|
||||
_Resource_Set_owner( &mrsp->Resource, NULL );
|
||||
} else {
|
||||
MRSP_Rival *rival = (MRSP_Rival *)
|
||||
_Chain_Get_first_unprotected( &mrsp->Rivals );
|
||||
MRSP_Rival *rival;
|
||||
Thread_Control *new_owner;
|
||||
|
||||
rival = (MRSP_Rival *) _Chain_Get_first_unprotected( &mrsp->Rivals );
|
||||
|
||||
/*
|
||||
* This must be inside the critical section since the status prevents a
|
||||
* potential double extraction in _MRSP_Timeout().
|
||||
@@ -417,7 +448,9 @@ RTEMS_INLINE_ROUTINE Status_Control _MRSP_Surrender(
|
||||
rival->status = STATUS_SUCCESSFUL;
|
||||
|
||||
new_owner = rival->thread;
|
||||
mrsp->initial_priority_of_owner = rival->initial_priority;
|
||||
|
||||
_MRSP_Replace_priority( mrsp, new_owner, rival );
|
||||
|
||||
_Resource_Node_extract( &new_owner->Resource_node );
|
||||
_Resource_Node_set_dependency( &new_owner->Resource_node, NULL );
|
||||
_Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource );
|
||||
@@ -437,7 +470,7 @@ RTEMS_INLINE_ROUTINE Status_Control _MRSP_Surrender(
|
||||
);
|
||||
_MRSP_Release( mrsp, queue_context );
|
||||
|
||||
_MRSP_Restore_priority( executing, initial_priority );
|
||||
_Thread_Priority_update( queue_context );
|
||||
|
||||
_Thread_Dispatch_enable( cpu_self );
|
||||
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
/**
|
||||
* @file rtems/score/priority.h
|
||||
* @file
|
||||
*
|
||||
* @brief Thread Priority Manipulation Routines
|
||||
*
|
||||
* This include file contains all thread priority manipulation routines.
|
||||
* This Handler provides mechanisms which can be used to
|
||||
* initialize and manipulate thread priorities.
|
||||
* @brief Priority Handler API
|
||||
*/
|
||||
|
||||
/*
|
||||
* COPYRIGHT (c) 1989-2011.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* Copyright (c) 2016 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.
|
||||
@@ -20,58 +18,169 @@
|
||||
#ifndef _RTEMS_SCORE_PRIORITY_H
|
||||
#define _RTEMS_SCORE_PRIORITY_H
|
||||
|
||||
/**
|
||||
* @defgroup ScorePriority Priority Handler
|
||||
*
|
||||
* @ingroup Score
|
||||
*
|
||||
* This handler encapsulates functionality which is used to manage
|
||||
* thread priorities. At the SuperCore level 256 priority levels
|
||||
* are supported with lower numbers representing logically more important
|
||||
* threads. The priority level 0 is reserved for internal RTEMS use.
|
||||
* Typically it is assigned to threads which defer internal RTEMS
|
||||
* actions from an interrupt to thread level to improve interrupt response.
|
||||
* Priority level 255 is assigned to the IDLE thread and really should not
|
||||
* be used by application threads. The default IDLE thread implementation
|
||||
* is an infinite "branch to self" loop which never yields to other threads
|
||||
* at the same priority.
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/*
|
||||
* Processor specific information.
|
||||
*/
|
||||
#include <rtems/score/chain.h>
|
||||
#include <rtems/score/cpu.h>
|
||||
#include <rtems/score/rbtree.h>
|
||||
|
||||
struct Scheduler_Control;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The following type defines the control block used to manage
|
||||
* thread priorities.
|
||||
* @defgroup ScorePriority Priority Handler
|
||||
*
|
||||
* @note Priority 0 is reserved for internal threads only.
|
||||
* @ingroup Score
|
||||
*
|
||||
* This handler encapsulates functionality which is used to manage thread
|
||||
* priorities. The actual priority of a thread is an aggregation of priority
|
||||
* nodes. The thread priority aggregation for the home scheduler instance of a
|
||||
* thread consists of at least one priority node, which is normally the real
|
||||
* priority of the thread. The locking protocols (e.g. priority ceiling and
|
||||
* priority inheritance), rate-monotonic period objects and the POSIX sporadic
|
||||
* server add, change and remove priority nodes.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief A plain thread priority value.
|
||||
*
|
||||
* Lower values represent higher priorities. So, a priority value of zero
|
||||
* represents the highest priority thread. This value is reserved for internal
|
||||
* threads and the priority ceiling protocol.
|
||||
*/
|
||||
typedef uint64_t Priority_Control;
|
||||
|
||||
/** This defines the highest (most important) thread priority. */
|
||||
/**
|
||||
* @brief The highest (most important) thread priority value.
|
||||
*/
|
||||
#define PRIORITY_MINIMUM 0
|
||||
|
||||
/**
|
||||
* @brief This defines the priority of pseudo-ISR threads.
|
||||
* @brief The priority value of pseudo-ISR threads.
|
||||
*
|
||||
* Examples are the MPCI and timer server threads.
|
||||
*/
|
||||
#define PRIORITY_PSEUDO_ISR PRIORITY_MINIMUM
|
||||
|
||||
/** This defines the default lowest (least important) thread priority. */
|
||||
/**
|
||||
* @brief The default lowest (least important) thread priority value.
|
||||
*
|
||||
* This value is CPU port dependent.
|
||||
*/
|
||||
#if defined (CPU_PRIORITY_MAXIMUM)
|
||||
#define PRIORITY_DEFAULT_MAXIMUM CPU_PRIORITY_MAXIMUM
|
||||
#else
|
||||
#define PRIORITY_DEFAULT_MAXIMUM 255
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief The priority node to build up a priority aggregation.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Node component for a chain or red-black tree.
|
||||
*/
|
||||
union {
|
||||
Chain_Node Chain;
|
||||
RBTree_Node RBTree;
|
||||
} Node;
|
||||
|
||||
/**
|
||||
* @brief The priority value of this node.
|
||||
*/
|
||||
Priority_Control priority;
|
||||
} Priority_Node;
|
||||
|
||||
/**
|
||||
* @brief The priority action type.
|
||||
*/
|
||||
typedef enum {
|
||||
PRIORITY_ACTION_ADD,
|
||||
PRIORITY_ACTION_CHANGE,
|
||||
PRIORITY_ACTION_REMOVE,
|
||||
PRIORITY_ACTION_INVALID
|
||||
} Priority_Action_type;
|
||||
|
||||
typedef struct Priority_Aggregation Priority_Aggregation;
|
||||
|
||||
/**
|
||||
* @brief The priority aggregation.
|
||||
*
|
||||
* This structure serves two purposes. Firstly, it provides a place to
|
||||
* register priority nodes and reflects the overall priority of its
|
||||
* contributors. Secondly, it provides an action block to signal addition,
|
||||
* change and removal of a priority node.
|
||||
*/
|
||||
struct Priority_Aggregation {
|
||||
/**
|
||||
* @brief This priority node reflects the overall priority of the aggregation.
|
||||
*
|
||||
* The overall priority of the aggregation is the minimum priority of the
|
||||
* priority nodes in the contributors tree.
|
||||
*
|
||||
* This priority node may be used to add this aggregation to another
|
||||
* aggregation to build up a recursive priority scheme.
|
||||
*
|
||||
* In case priority nodes of the contributors tree are added, changed or
|
||||
* removed the priority of this node may change. To signal such changes to a
|
||||
* priority aggregation the action block may be used.
|
||||
*/
|
||||
Priority_Node Node;
|
||||
|
||||
/**
|
||||
* @brief A red-black tree to contain priority nodes contributing to the
|
||||
* overall priority of this priority aggregation.
|
||||
*/
|
||||
RBTree_Control Contributors;
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
/**
|
||||
* @brief The scheduler instance of this priority aggregation.
|
||||
*/
|
||||
const struct Scheduler_Control *scheduler;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief A priority action block to manage priority node additions, changes
|
||||
* and removals.
|
||||
*/
|
||||
struct {
|
||||
#if defined(RTEMS_SMP)
|
||||
/**
|
||||
* @brief The next priority aggregation in the action list.
|
||||
*/
|
||||
Priority_Aggregation *next;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief The priority node of the action.
|
||||
*/
|
||||
Priority_Node *node;
|
||||
|
||||
/**
|
||||
* @brief The type of the action.
|
||||
*/
|
||||
Priority_Action_type type;
|
||||
} Action;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A list of priority actions.
|
||||
*
|
||||
* Actions are only added to the list. The action lists reside on the stack
|
||||
* and have a short life-time. They are moved, processed or destroyed as a
|
||||
* whole.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief The first action of a priority action list.
|
||||
*/
|
||||
Priority_Aggregation *actions;
|
||||
} Priority_Actions;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
|
||||
#ifndef _RTEMS_SCORE_PRIORITYIMPL_H
|
||||
#define _RTEMS_SCORE_PRIORITYIMPL_H
|
||||
|
||||
#include <rtems/score/priority.h>
|
||||
#include <rtems/score/scheduler.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Actions_initialize_empty(
|
||||
Priority_Actions *actions
|
||||
)
|
||||
{
|
||||
actions->actions = NULL;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Actions_initialize_one(
|
||||
Priority_Actions *actions,
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Node *node,
|
||||
Priority_Action_type type
|
||||
)
|
||||
{
|
||||
#if defined(RTEMS_SMP)
|
||||
aggregation->Action.next = NULL;
|
||||
#endif
|
||||
aggregation->Action.node = node;
|
||||
aggregation->Action.type = type;
|
||||
|
||||
actions->actions = aggregation;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _Priority_Actions_is_empty(
|
||||
const Priority_Actions *actions
|
||||
)
|
||||
{
|
||||
return actions->actions == NULL;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _Priority_Actions_is_valid(
|
||||
const Priority_Aggregation *aggregation
|
||||
)
|
||||
{
|
||||
#if defined(RTEMS_SMP)
|
||||
return aggregation != NULL;
|
||||
#else
|
||||
(void) aggregation;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE Priority_Aggregation *_Priority_Actions_move(
|
||||
Priority_Actions *actions
|
||||
)
|
||||
{
|
||||
Priority_Aggregation *aggregation;
|
||||
|
||||
aggregation = actions->actions;
|
||||
actions->actions = NULL;
|
||||
|
||||
return aggregation;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Actions_add(
|
||||
Priority_Actions *actions,
|
||||
Priority_Aggregation *aggregation
|
||||
)
|
||||
{
|
||||
#if defined(RTEMS_SMP)
|
||||
/*
|
||||
* Priority aggregations are only added to action lists, so do not care about
|
||||
* the current next pointer value.
|
||||
*/
|
||||
aggregation->Action.next = actions->actions;
|
||||
#endif
|
||||
actions->actions = aggregation;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Node_initialize(
|
||||
Priority_Node *node,
|
||||
Priority_Control priority
|
||||
)
|
||||
{
|
||||
node->priority = priority;
|
||||
_RBTree_Initialize_node( &node->Node.RBTree );
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Node_set_priority(
|
||||
Priority_Node *node,
|
||||
Priority_Control priority
|
||||
)
|
||||
{
|
||||
node->priority = priority;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Node_set_inactive(
|
||||
Priority_Node *node
|
||||
)
|
||||
{
|
||||
_RBTree_Set_off_tree( &node->Node.RBTree );
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _Priority_Node_is_active(
|
||||
const Priority_Node *node
|
||||
)
|
||||
{
|
||||
return !_RBTree_Is_node_off_tree( &node->Node.RBTree );
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Initialize_empty(
|
||||
Priority_Aggregation *aggregation
|
||||
)
|
||||
{
|
||||
#if defined(RTEMS_DEBUG)
|
||||
#if defined(RTEMS_SMP)
|
||||
aggregation->Action.next = NULL;
|
||||
#endif
|
||||
aggregation->Action.node = NULL;
|
||||
aggregation->Action.type = PRIORITY_ACTION_INVALID;
|
||||
#endif
|
||||
_RBTree_Initialize_node( &aggregation->Node.Node.RBTree );
|
||||
_RBTree_Initialize_empty( &aggregation->Contributors );
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Initialize_one(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Node *node
|
||||
)
|
||||
{
|
||||
#if defined(RTEMS_DEBUG)
|
||||
#if defined(RTEMS_SMP)
|
||||
aggregation->Action.next = NULL;
|
||||
#endif
|
||||
aggregation->Action.node = NULL;
|
||||
aggregation->Action.type = PRIORITY_ACTION_INVALID;
|
||||
#endif
|
||||
_Priority_Node_initialize( &aggregation->Node, node->priority );
|
||||
_RBTree_Initialize_one( &aggregation->Contributors, &node->Node.RBTree );
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _Priority_Is_empty(
|
||||
const Priority_Aggregation *aggregation
|
||||
)
|
||||
{
|
||||
return _RBTree_Is_empty( &aggregation->Contributors );
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE Priority_Control _Priority_Get_priority(
|
||||
const Priority_Aggregation *aggregation
|
||||
)
|
||||
{
|
||||
return aggregation->Node.priority;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE const Scheduler_Control *_Priority_Get_scheduler(
|
||||
const Priority_Aggregation *aggregation
|
||||
)
|
||||
{
|
||||
#if defined(RTEMS_SMP)
|
||||
return aggregation->scheduler;
|
||||
#else
|
||||
return &_Scheduler_Table[ 0 ];
|
||||
#endif
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE Priority_Node *_Priority_Get_minimum_node(
|
||||
const Priority_Aggregation *aggregation
|
||||
)
|
||||
{
|
||||
return (Priority_Node *) _RBTree_Minimum( &aggregation->Contributors );
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Set_action_node(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Node *node
|
||||
)
|
||||
{
|
||||
aggregation->Action.node = node;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Set_action_type(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Action_type type
|
||||
)
|
||||
{
|
||||
aggregation->Action.type = type;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Set_action(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Node *node,
|
||||
Priority_Action_type type
|
||||
)
|
||||
{
|
||||
aggregation->Action.node = node;
|
||||
aggregation->Action.type = type;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE Priority_Aggregation *_Priority_Get_next_action(
|
||||
const Priority_Aggregation *aggregation
|
||||
)
|
||||
{
|
||||
#if defined(RTEMS_SMP)
|
||||
return aggregation->Action.next;
|
||||
#else
|
||||
(void) aggregation;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _Priority_Less(
|
||||
const void *left,
|
||||
const RBTree_Node *right
|
||||
)
|
||||
{
|
||||
const Priority_Control *the_left;
|
||||
const Priority_Node *the_right;
|
||||
|
||||
the_left = left;
|
||||
the_right = RTEMS_CONTAINER_OF( right, Priority_Node, Node.RBTree );
|
||||
|
||||
return *the_left < the_right->priority;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _Priority_Plain_insert(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Node *node,
|
||||
Priority_Control priority
|
||||
)
|
||||
{
|
||||
return _RBTree_Insert_inline(
|
||||
&aggregation->Contributors,
|
||||
&node->Node.RBTree,
|
||||
&priority,
|
||||
_Priority_Less
|
||||
);
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Plain_extract(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Node *node
|
||||
)
|
||||
{
|
||||
_RBTree_Extract( &aggregation->Contributors, &node->Node.RBTree );
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Plain_changed(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Node *node
|
||||
)
|
||||
{
|
||||
_Priority_Plain_extract( aggregation, node );
|
||||
_Priority_Plain_insert( aggregation, node, node->priority );
|
||||
}
|
||||
|
||||
typedef void ( *Priority_Add_handler )(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Actions *actions,
|
||||
void *arg
|
||||
);
|
||||
|
||||
typedef void ( *Priority_Change_handler )(
|
||||
Priority_Aggregation *aggregation,
|
||||
bool prepend_it,
|
||||
Priority_Actions *actions,
|
||||
void *arg
|
||||
);
|
||||
|
||||
typedef void ( *Priority_Remove_handler )(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Actions *actions,
|
||||
void *arg
|
||||
);
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Change_nothing(
|
||||
Priority_Aggregation *aggregation,
|
||||
bool prepend_it,
|
||||
Priority_Actions *actions,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
(void) aggregation;
|
||||
(void) prepend_it;
|
||||
(void) actions;
|
||||
(void) arg;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Remove_nothing(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Actions *actions,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
(void) aggregation;
|
||||
(void) actions;
|
||||
(void) arg;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Non_empty_insert(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Node *node,
|
||||
Priority_Actions *actions,
|
||||
Priority_Change_handler change,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
bool is_new_minimum;
|
||||
|
||||
_Assert( !_Priority_Is_empty( aggregation ) );
|
||||
is_new_minimum = _Priority_Plain_insert( aggregation, node, node->priority );
|
||||
|
||||
if ( is_new_minimum ) {
|
||||
aggregation->Node.priority = node->priority;
|
||||
( *change )( aggregation, false, actions, arg );
|
||||
}
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Insert(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Node *node,
|
||||
Priority_Actions *actions,
|
||||
Priority_Add_handler add,
|
||||
Priority_Change_handler change,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
if ( _Priority_Is_empty( aggregation ) ) {
|
||||
_Priority_Initialize_one( aggregation, node );
|
||||
( *add )( aggregation, actions, arg );
|
||||
} else {
|
||||
_Priority_Non_empty_insert( aggregation, node, actions, change, arg );
|
||||
}
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Extract(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Node *node,
|
||||
Priority_Actions *actions,
|
||||
Priority_Remove_handler remove,
|
||||
Priority_Change_handler change,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
_Priority_Plain_extract( aggregation, node );
|
||||
|
||||
if ( _Priority_Is_empty( aggregation ) ) {
|
||||
( *remove )( aggregation, actions, arg );
|
||||
} else {
|
||||
Priority_Node *min;
|
||||
|
||||
min = _Priority_Get_minimum_node( aggregation );
|
||||
|
||||
if ( node->priority < min->priority ) {
|
||||
aggregation->Node.priority = min->priority;
|
||||
( *change )( aggregation, true, actions, arg );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Extract_non_empty(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Node *node,
|
||||
Priority_Actions *actions,
|
||||
Priority_Change_handler change,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
Priority_Node *min;
|
||||
|
||||
_Priority_Plain_extract( aggregation, node );
|
||||
_Assert( !_Priority_Is_empty( aggregation ) );
|
||||
|
||||
min = _Priority_Get_minimum_node( aggregation );
|
||||
|
||||
if ( node->priority < min->priority ) {
|
||||
aggregation->Node.priority = min->priority;
|
||||
( *change )( aggregation, true, actions, arg );
|
||||
}
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Changed(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Node *node,
|
||||
bool prepend_it,
|
||||
Priority_Actions *actions,
|
||||
Priority_Change_handler change,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
Priority_Node *min;
|
||||
|
||||
_Priority_Plain_changed( aggregation, node );
|
||||
|
||||
min = _Priority_Get_minimum_node( aggregation );
|
||||
|
||||
if ( min->priority != aggregation->Node.priority ) {
|
||||
aggregation->Node.priority = min->priority;
|
||||
( *change )( aggregation, prepend_it, actions, arg );
|
||||
}
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Priority_Replace(
|
||||
Priority_Aggregation *aggregation,
|
||||
Priority_Node *victim,
|
||||
Priority_Node *replacement
|
||||
)
|
||||
{
|
||||
replacement->priority = victim->priority;
|
||||
_RBTree_Replace_node(
|
||||
&aggregation->Contributors,
|
||||
&victim->Node.RBTree,
|
||||
&replacement->Node.RBTree
|
||||
);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _RTEMS_SCORE_PRIORITYIMPL_H */
|
||||
@@ -135,16 +135,20 @@ typedef struct {
|
||||
void ( *node_destroy )( const Scheduler_Control *, Scheduler_Node * );
|
||||
|
||||
/** @see _Scheduler_Release_job() */
|
||||
Thread_Control *( *release_job ) (
|
||||
void ( *release_job ) (
|
||||
const Scheduler_Control *,
|
||||
Thread_Control *,
|
||||
uint64_t
|
||||
Priority_Node *,
|
||||
uint64_t,
|
||||
Thread_queue_Context *
|
||||
);
|
||||
|
||||
/** @see _Scheduler_Cancel_job() */
|
||||
Thread_Control *( *cancel_job ) (
|
||||
void ( *cancel_job ) (
|
||||
const Scheduler_Control *,
|
||||
Thread_Control *
|
||||
Thread_Control *,
|
||||
Priority_Node *,
|
||||
Thread_queue_Context *
|
||||
);
|
||||
|
||||
/** @see _Scheduler_Tick() */
|
||||
@@ -373,14 +377,18 @@ void _Scheduler_default_Node_destroy(
|
||||
*
|
||||
* @param[in] scheduler Unused.
|
||||
* @param[in] the_thread Unused.
|
||||
* @param[in] priority_node Unused.
|
||||
* @param[in] deadline Unused.
|
||||
* @param[in] queue_context Unused.
|
||||
*
|
||||
* @retval NULL Always.
|
||||
*/
|
||||
Thread_Control *_Scheduler_default_Release_job(
|
||||
void _Scheduler_default_Release_job(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
uint64_t deadline
|
||||
Priority_Node *priority_node,
|
||||
uint64_t deadline,
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -388,12 +396,16 @@ Thread_Control *_Scheduler_default_Release_job(
|
||||
*
|
||||
* @param[in] scheduler Unused.
|
||||
* @param[in] the_thread Unused.
|
||||
* @param[in] priority_node Unused.
|
||||
* @param[in] queue_context Unused.
|
||||
*
|
||||
* @retval NULL Always.
|
||||
*/
|
||||
Thread_Control *_Scheduler_default_Cancel_job(
|
||||
void _Scheduler_default_Cancel_job(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread
|
||||
Thread_Control *the_thread,
|
||||
Priority_Node *priority_node,
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,7 +61,7 @@ extern "C" {
|
||||
_Scheduler_CBS_Node_initialize, /* node initialize entry point */ \
|
||||
_Scheduler_default_Node_destroy, /* node destroy entry point */ \
|
||||
_Scheduler_CBS_Release_job, /* new period of task */ \
|
||||
_Scheduler_EDF_Cancel_job, /* cancel period of task */ \
|
||||
_Scheduler_CBS_Cancel_job, /* cancel period of task */ \
|
||||
_Scheduler_default_Tick, /* tick entry point */ \
|
||||
_Scheduler_default_Start_idle /* start idle entry point */ \
|
||||
SCHEDULER_OPERATION_DEFAULT_GET_SET_AFFINITY \
|
||||
@@ -135,6 +135,8 @@ typedef struct {
|
||||
Scheduler_EDF_Node Base;
|
||||
/** CBS server specific data of a task. */
|
||||
Scheduler_CBS_Server *cbs_server;
|
||||
|
||||
Priority_Node *deadline_node;
|
||||
} Scheduler_CBS_Node;
|
||||
|
||||
|
||||
@@ -163,10 +165,19 @@ Scheduler_Void_or_thread _Scheduler_CBS_Unblock(
|
||||
Thread_Control *the_thread
|
||||
);
|
||||
|
||||
Thread_Control *_Scheduler_CBS_Release_job(
|
||||
void _Scheduler_CBS_Release_job(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
uint64_t length
|
||||
Priority_Node *priority_node,
|
||||
uint64_t deadline,
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
void _Scheduler_CBS_Cancel_job(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Priority_Node *priority_node,
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -88,25 +88,15 @@ typedef struct {
|
||||
*/
|
||||
Scheduler_Node Base;
|
||||
|
||||
/**
|
||||
* Pointer to corresponding Thread Control Block.
|
||||
*/
|
||||
Thread_Control *thread;
|
||||
/**
|
||||
* Rbtree node related to this thread.
|
||||
*/
|
||||
RBTree_Node Node;
|
||||
|
||||
/**
|
||||
* @brief The thread priority used by this scheduler instance in case no job
|
||||
* is released.
|
||||
* @brief The thread priority currently used for this scheduler instance.
|
||||
*/
|
||||
Priority_Control background_priority;
|
||||
|
||||
/**
|
||||
* @brief The thread priority currently used by this scheduler instance.
|
||||
*/
|
||||
Priority_Control current_priority;
|
||||
Priority_Control priority;
|
||||
} Scheduler_EDF_Node;
|
||||
|
||||
/**
|
||||
@@ -215,15 +205,19 @@ Scheduler_Void_or_thread _Scheduler_EDF_Yield(
|
||||
Thread_Control *the_thread
|
||||
);
|
||||
|
||||
Thread_Control *_Scheduler_EDF_Release_job(
|
||||
void _Scheduler_EDF_Release_job(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
uint64_t deadline
|
||||
Priority_Node *priority_node,
|
||||
uint64_t deadline,
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
Thread_Control *_Scheduler_EDF_Cancel_job(
|
||||
void _Scheduler_EDF_Cancel_job(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread
|
||||
Thread_Control *the_thread,
|
||||
Priority_Node *priority_node,
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -74,7 +74,7 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_EDF_Less(
|
||||
the_right = RTEMS_CONTAINER_OF( right, Scheduler_EDF_Node, Node );
|
||||
|
||||
prio_left = *the_left;
|
||||
prio_right = the_right->current_priority;
|
||||
prio_right = the_right->priority;
|
||||
|
||||
return prio_left < prio_right;
|
||||
}
|
||||
@@ -93,7 +93,7 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_EDF_Less_or_equal(
|
||||
the_right = RTEMS_CONTAINER_OF( right, Scheduler_EDF_Node, Node );
|
||||
|
||||
prio_left = *the_left;
|
||||
prio_right = the_right->current_priority;
|
||||
prio_right = the_right->priority;
|
||||
|
||||
return prio_left <= prio_right;
|
||||
}
|
||||
@@ -101,13 +101,13 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_EDF_Less_or_equal(
|
||||
RTEMS_INLINE_ROUTINE void _Scheduler_EDF_Enqueue(
|
||||
Scheduler_EDF_Context *context,
|
||||
Scheduler_EDF_Node *node,
|
||||
Priority_Control current_priority
|
||||
Priority_Control priority
|
||||
)
|
||||
{
|
||||
_RBTree_Insert_inline(
|
||||
&context->Ready,
|
||||
&node->Node,
|
||||
¤t_priority,
|
||||
&priority,
|
||||
_Scheduler_EDF_Less
|
||||
);
|
||||
}
|
||||
@@ -115,13 +115,13 @@ RTEMS_INLINE_ROUTINE void _Scheduler_EDF_Enqueue(
|
||||
RTEMS_INLINE_ROUTINE void _Scheduler_EDF_Enqueue_first(
|
||||
Scheduler_EDF_Context *context,
|
||||
Scheduler_EDF_Node *node,
|
||||
Priority_Control current_priority
|
||||
Priority_Control priority
|
||||
)
|
||||
{
|
||||
_RBTree_Insert_inline(
|
||||
&context->Ready,
|
||||
&node->Node,
|
||||
¤t_priority,
|
||||
&priority,
|
||||
_Scheduler_EDF_Less_or_equal
|
||||
);
|
||||
}
|
||||
@@ -164,7 +164,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_EDF_Schedule_body(
|
||||
first = _RBTree_Minimum( &context->Ready );
|
||||
node = RTEMS_CONTAINER_OF( first, Scheduler_EDF_Node, Node );
|
||||
|
||||
_Scheduler_Update_heir( node->thread, force_dispatch );
|
||||
_Scheduler_Update_heir( node->Base.owner, force_dispatch );
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <rtems/score/scheduler.h>
|
||||
#include <rtems/score/cpusetimpl.h>
|
||||
#include <rtems/score/priorityimpl.h>
|
||||
#include <rtems/score/smpimpl.h>
|
||||
#include <rtems/score/status.h>
|
||||
#include <rtems/score/threadimpl.h>
|
||||
@@ -99,17 +100,6 @@ RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_CPU(
|
||||
return _Scheduler_Get_by_CPU_index( cpu_index );
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE Scheduler_Node *_Scheduler_Thread_get_own_node(
|
||||
const Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
#if defined(RTEMS_SMP)
|
||||
return the_thread->Scheduler.own_node;
|
||||
#else
|
||||
return the_thread->Scheduler.node;
|
||||
#endif
|
||||
}
|
||||
|
||||
ISR_LOCK_DECLARE( extern, _Scheduler_Lock )
|
||||
|
||||
/**
|
||||
@@ -264,7 +254,7 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Ask_for_help_if_necessary(
|
||||
needs_help != NULL
|
||||
&& _Resource_Node_owns_resources( &needs_help->Resource_node )
|
||||
) {
|
||||
Scheduler_Node *node = _Scheduler_Thread_get_own_node( needs_help );
|
||||
Scheduler_Node *node = _Thread_Scheduler_get_own_node( needs_help );
|
||||
|
||||
if (
|
||||
node->help_state != SCHEDULER_HELP_ACTIVE_RIVAL
|
||||
@@ -486,21 +476,27 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Node_destroy(
|
||||
* @brief Releases a job of a thread with respect to the scheduler.
|
||||
*
|
||||
* @param[in] the_thread The thread.
|
||||
* @param[in] priority_node The priority node of the job.
|
||||
* @param[in] deadline The deadline in watchdog ticks since boot.
|
||||
*
|
||||
* @return The thread to hand over to _Thread_Update_priority().
|
||||
* @param[in] queue_context The thread queue context to provide the set of
|
||||
* threads for _Thread_Priority_update().
|
||||
*/
|
||||
RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Release_job(
|
||||
Thread_Control *the_thread,
|
||||
uint64_t deadline
|
||||
RTEMS_INLINE_ROUTINE void _Scheduler_Release_job(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Node *priority_node,
|
||||
uint64_t deadline,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
const Scheduler_Control *scheduler = _Scheduler_Get( the_thread );
|
||||
|
||||
return ( *scheduler->Operations.release_job )(
|
||||
_Thread_queue_Context_clear_priority_updates( queue_context );
|
||||
( *scheduler->Operations.release_job )(
|
||||
scheduler,
|
||||
the_thread,
|
||||
deadline
|
||||
priority_node,
|
||||
deadline,
|
||||
queue_context
|
||||
);
|
||||
}
|
||||
|
||||
@@ -508,16 +504,25 @@ RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Release_job(
|
||||
* @brief Cancels a job of a thread with respect to the scheduler.
|
||||
*
|
||||
* @param[in] the_thread The thread.
|
||||
*
|
||||
* @return The thread to hand over to _Thread_Update_priority().
|
||||
* @param[in] priority_node The priority node of the job.
|
||||
* @param[in] queue_context The thread queue context to provide the set of
|
||||
* threads for _Thread_Priority_update().
|
||||
*/
|
||||
RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Cancel_job(
|
||||
Thread_Control *the_thread
|
||||
RTEMS_INLINE_ROUTINE void _Scheduler_Cancel_job(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Node *priority_node,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
const Scheduler_Control *scheduler = _Scheduler_Get( the_thread );
|
||||
|
||||
return ( *scheduler->Operations.cancel_job )( scheduler, the_thread );
|
||||
_Thread_queue_Context_clear_priority_updates( queue_context );
|
||||
( *scheduler->Operations.cancel_job )(
|
||||
scheduler,
|
||||
the_thread,
|
||||
priority_node,
|
||||
queue_context
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -776,12 +781,10 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Thread_set_priority(
|
||||
bool prepend_it
|
||||
)
|
||||
{
|
||||
Scheduler_Node *own_node;
|
||||
Scheduler_Node *scheduler_node;
|
||||
|
||||
own_node = _Scheduler_Thread_get_own_node( the_thread );
|
||||
_Scheduler_Node_set_priority( own_node, new_priority, prepend_it );
|
||||
|
||||
the_thread->current_priority = new_priority;
|
||||
scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
|
||||
_Scheduler_Node_set_priority( scheduler_node, new_priority, prepend_it );
|
||||
}
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
@@ -857,7 +860,7 @@ RTEMS_INLINE_ROUTINE Scheduler_Help_state _Scheduler_Thread_change_help_state(
|
||||
Scheduler_Help_state new_help_state
|
||||
)
|
||||
{
|
||||
Scheduler_Node *node = _Scheduler_Thread_get_own_node( the_thread );
|
||||
Scheduler_Node *node = _Thread_Scheduler_get_own_node( the_thread );
|
||||
Scheduler_Help_state previous_help_state = node->help_state;
|
||||
|
||||
node->help_state = new_help_state;
|
||||
@@ -1294,7 +1297,7 @@ RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Ask_scheduled_node_for_help(
|
||||
_Scheduler_Thread_change_state( old_user, THREAD_SCHEDULER_READY );
|
||||
_Scheduler_Thread_set_scheduler_and_node(
|
||||
old_user,
|
||||
_Scheduler_Thread_get_own_node( old_user ),
|
||||
_Thread_Scheduler_get_own_node( old_user ),
|
||||
old_user
|
||||
);
|
||||
|
||||
@@ -1383,11 +1386,24 @@ RTEMS_INLINE_ROUTINE Status_Control _Scheduler_Set(
|
||||
return STATUS_RESOURCE_IN_USE;
|
||||
}
|
||||
|
||||
the_thread->current_priority = priority;
|
||||
the_thread->real_priority = priority;
|
||||
the_thread->Start.initial_priority = priority;
|
||||
own_node = _Thread_Scheduler_get_own_node( the_thread );
|
||||
_Priority_Plain_extract( &own_node->Wait.Priority, &the_thread->Real_priority );
|
||||
|
||||
own_node = _Scheduler_Thread_get_own_node( the_thread );
|
||||
if ( !_Priority_Is_empty( &own_node->Wait.Priority ) ) {
|
||||
_Priority_Plain_insert(
|
||||
&own_node->Wait.Priority,
|
||||
&the_thread->Real_priority,
|
||||
the_thread->Real_priority.priority
|
||||
);
|
||||
return STATUS_RESOURCE_IN_USE;
|
||||
}
|
||||
|
||||
the_thread->Start.initial_priority = priority;
|
||||
_Priority_Node_set_priority( &the_thread->Real_priority, priority );
|
||||
_Priority_Initialize_one(
|
||||
&own_node->Wait.Priority,
|
||||
&the_thread->Real_priority
|
||||
);
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
{
|
||||
|
||||
@@ -98,7 +98,7 @@ typedef enum {
|
||||
/**
|
||||
* @brief Scheduler node for per-thread data.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct Scheduler_Node {
|
||||
#if defined(RTEMS_SMP)
|
||||
/**
|
||||
* @brief Chain node for usage in various scheduler data structures.
|
||||
@@ -144,24 +144,7 @@ typedef struct {
|
||||
* @brief Thread wait support block.
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
* @brief Node for thread queues.
|
||||
*
|
||||
* Each scheduler node can be enqueued on a thread queue on behalf of the
|
||||
* thread owning the scheduler node. The scheduler node reflects the
|
||||
* priority of the thread within the corresponding scheduler instance.
|
||||
*/
|
||||
union {
|
||||
/**
|
||||
* @brief A node for chains.
|
||||
*/
|
||||
Chain_Node Chain;
|
||||
|
||||
/**
|
||||
* @brief A node for red-black trees.
|
||||
*/
|
||||
RBTree_Node RBTree;
|
||||
} Node;
|
||||
Priority_Aggregation Priority;
|
||||
} Wait;
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,20 +17,23 @@
|
||||
|
||||
#include <rtems/score/schedulernode.h>
|
||||
|
||||
struct Scheduler_Control;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define SCHEDULER_NODE_OF_WAIT_CHAIN_NODE( node ) \
|
||||
RTEMS_CONTAINER_OF( node, Scheduler_Node, Wait.Node.Chain )
|
||||
#define SCHEDULER_NODE_OF_WAIT_PRIORITY_NODE( node ) \
|
||||
RTEMS_CONTAINER_OF( node, Scheduler_Node, Wait.Priority.Node.Node.Chain )
|
||||
|
||||
#define SCHEDULER_NODE_OF_WAIT_RBTREE_NODE( node ) \
|
||||
RTEMS_CONTAINER_OF( node, Scheduler_Node, Wait.Node.RBTree )
|
||||
#define SCHEDULER_NODE_OF_WAIT_PRIORITY( node ) \
|
||||
RTEMS_CONTAINER_OF( node, Scheduler_Node, Wait.Priority )
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Scheduler_Node_do_initialize(
|
||||
Scheduler_Node *node,
|
||||
Thread_Control *the_thread,
|
||||
Priority_Control priority
|
||||
const struct Scheduler_Control *scheduler,
|
||||
Scheduler_Node *node,
|
||||
Thread_Control *the_thread,
|
||||
Priority_Control priority
|
||||
)
|
||||
{
|
||||
node->owner = the_thread;
|
||||
@@ -39,12 +42,14 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Node_do_initialize(
|
||||
node->Priority.prepend_it = false;
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
node->Wait.Priority.scheduler = scheduler;
|
||||
node->user = the_thread;
|
||||
node->help_state = SCHEDULER_HELP_YOURSELF;
|
||||
node->idle = NULL;
|
||||
node->accepts_help = the_thread;
|
||||
_SMP_sequence_lock_Initialize( &node->Priority.Lock );
|
||||
#else
|
||||
(void) scheduler;
|
||||
(void) the_thread;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -375,7 +375,7 @@ static inline Scheduler_SMP_Node *_Scheduler_SMP_Thread_get_own_node(
|
||||
Thread_Control *thread
|
||||
)
|
||||
{
|
||||
return (Scheduler_SMP_Node *) _Scheduler_Thread_get_own_node( thread );
|
||||
return (Scheduler_SMP_Node *) _Thread_Scheduler_get_own_node( thread );
|
||||
}
|
||||
|
||||
static inline Scheduler_SMP_Node *_Scheduler_SMP_Node_downcast(
|
||||
@@ -386,12 +386,13 @@ static inline Scheduler_SMP_Node *_Scheduler_SMP_Node_downcast(
|
||||
}
|
||||
|
||||
static inline void _Scheduler_SMP_Node_initialize(
|
||||
Scheduler_SMP_Node *node,
|
||||
Thread_Control *thread,
|
||||
Priority_Control priority
|
||||
const Scheduler_Control *scheduler,
|
||||
Scheduler_SMP_Node *node,
|
||||
Thread_Control *thread,
|
||||
Priority_Control priority
|
||||
)
|
||||
{
|
||||
_Scheduler_Node_do_initialize( &node->Base, thread, priority );
|
||||
_Scheduler_Node_do_initialize( scheduler, &node->Base, thread, priority );
|
||||
node->state = SCHEDULER_SMP_NODE_BLOCKED;
|
||||
node->priority = priority;
|
||||
}
|
||||
|
||||
@@ -373,7 +373,7 @@ typedef struct {
|
||||
*
|
||||
* The thread wait lock mechanism protects the following thread variables
|
||||
* - POSIX_API_Control::Attributes,
|
||||
* - Thread_Control::current_priority,
|
||||
* - Scheduler_Node::Wait,
|
||||
* - Thread_Control::Wait::Lock::Pending_requests,
|
||||
* - Thread_Control::Wait::queue, and
|
||||
* - Thread_Control::Wait::operations.
|
||||
@@ -461,32 +461,11 @@ typedef struct {
|
||||
|
||||
/** This field is the current execution state of this proxy. */
|
||||
States_Control current_state;
|
||||
/**
|
||||
* @brief This field is the current priority state of this thread.
|
||||
*
|
||||
* Writes to this field are only allowed in _Thread_Initialize() or via
|
||||
* _Thread_Change_priority().
|
||||
*/
|
||||
Priority_Control current_priority;
|
||||
|
||||
/**
|
||||
* @brief This field is the base priority of this thread.
|
||||
*
|
||||
* Writes to this field are only allowed in _Thread_Initialize() or via
|
||||
* _Thread_Change_priority().
|
||||
* @brief The base priority of this thread in its home scheduler instance.
|
||||
*/
|
||||
Priority_Control real_priority;
|
||||
|
||||
/**
|
||||
* @brief Hints if a priority restore is necessary once the resource count
|
||||
* changes from one to zero.
|
||||
*
|
||||
* This is an optimization to speed up the mutex surrender sequence in case
|
||||
* no attempt to change the priority was made during the mutex ownership. On
|
||||
* SMP configurations atomic fences must synchronize writes to
|
||||
* Thread_Control::priority_restore_hint and Thread_Control::resource_count.
|
||||
*/
|
||||
bool priority_restore_hint;
|
||||
Priority_Node Real_priority;
|
||||
|
||||
/** This field is the number of mutexes currently held by this proxy. */
|
||||
uint32_t resource_count;
|
||||
@@ -708,31 +687,9 @@ struct _Thread_Control {
|
||||
States_Control current_state;
|
||||
|
||||
/**
|
||||
* @brief This field is the current priority state of this thread.
|
||||
*
|
||||
* Writes to this field are only allowed in _Thread_Initialize() or via
|
||||
* _Thread_Change_priority().
|
||||
* @brief The base priority of this thread in its home scheduler instance.
|
||||
*/
|
||||
Priority_Control current_priority;
|
||||
|
||||
/**
|
||||
* @brief This field is the base priority of this thread.
|
||||
*
|
||||
* Writes to this field are only allowed in _Thread_Initialize() or via
|
||||
* _Thread_Change_priority().
|
||||
*/
|
||||
Priority_Control real_priority;
|
||||
|
||||
/**
|
||||
* @brief Hints if a priority restore is necessary once the resource count
|
||||
* changes from one to zero.
|
||||
*
|
||||
* This is an optimization to speed up the mutex surrender sequence in case
|
||||
* no attempt to change the priority was made during the mutex ownership. On
|
||||
* SMP configurations atomic fences must synchronize writes to
|
||||
* Thread_Control::priority_restore_hint and Thread_Control::resource_count.
|
||||
*/
|
||||
bool priority_restore_hint;
|
||||
Priority_Node Real_priority;
|
||||
|
||||
/** This field is the number of mutexes currently held by this thread. */
|
||||
uint32_t resource_count;
|
||||
|
||||
@@ -414,6 +414,163 @@ RTEMS_INLINE_ROUTINE bool _Thread_State_is_owner(
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Performs the priority actions specified by the thread queue context
|
||||
* along the thread queue path.
|
||||
*
|
||||
* The caller must be the owner of the thread wait lock.
|
||||
*
|
||||
* @param start_of_path The start thread of the thread queue path.
|
||||
* @param queue_context The thread queue context specifying the thread queue
|
||||
* path and initial thread priority actions.
|
||||
*
|
||||
* @see _Thread_queue_Path_acquire_critical().
|
||||
*/
|
||||
void _Thread_Priority_perform_actions(
|
||||
Thread_Control *start_of_path,
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Adds the specified thread priority node to the corresponding thread
|
||||
* priority aggregation.
|
||||
*
|
||||
* The caller must be the owner of the thread wait lock.
|
||||
*
|
||||
* @param the_thread The thread.
|
||||
* @param priority_node The thread priority node to add.
|
||||
* @param queue_context The thread queue context to return an updated set of
|
||||
* threads for _Thread_Priority_update(). The thread queue context must be
|
||||
* initialized via _Thread_queue_Context_clear_priority_updates() before a
|
||||
* call of this function.
|
||||
*
|
||||
* @see _Thread_Wait_acquire().
|
||||
*/
|
||||
void _Thread_Priority_add(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Node *priority_node,
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Removes the specified thread priority node from the corresponding
|
||||
* thread priority aggregation.
|
||||
*
|
||||
* The caller must be the owner of the thread wait lock.
|
||||
*
|
||||
* @param the_thread The thread.
|
||||
* @param priority_node The thread priority node to remove.
|
||||
* @param queue_context The thread queue context to return an updated set of
|
||||
* threads for _Thread_Priority_update(). The thread queue context must be
|
||||
* initialized via _Thread_queue_Context_clear_priority_updates() before a
|
||||
* call of this function.
|
||||
*
|
||||
* @see _Thread_Wait_acquire().
|
||||
*/
|
||||
void _Thread_Priority_remove(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Node *priority_node,
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Propagates a thread priority value change in the specified thread
|
||||
* priority node to the corresponding thread priority aggregation.
|
||||
*
|
||||
* The caller must be the owner of the thread wait lock.
|
||||
*
|
||||
* @param the_thread The thread.
|
||||
* @param priority_node The thread priority node to change.
|
||||
* @param prepend_it In case this is true, then the thread is prepended to
|
||||
* its priority group in its home scheduler instance, otherwise it is
|
||||
* appended.
|
||||
* @param queue_context The thread queue context to return an updated set of
|
||||
* threads for _Thread_Priority_update(). The thread queue context must be
|
||||
* initialized via _Thread_queue_Context_clear_priority_updates() before a
|
||||
* call of this function.
|
||||
*
|
||||
* @see _Thread_Wait_acquire().
|
||||
*/
|
||||
void _Thread_Priority_changed(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Node *priority_node,
|
||||
bool prepend_it,
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Changes the thread priority value of the specified thread priority
|
||||
* node in the corresponding thread priority aggregation.
|
||||
*
|
||||
* The caller must be the owner of the thread wait lock.
|
||||
*
|
||||
* @param the_thread The thread.
|
||||
* @param priority_node The thread priority node to change.
|
||||
* @param new_priority The new thread priority value of the thread priority
|
||||
* node to change.
|
||||
* @param prepend_it In case this is true, then the thread is prepended to
|
||||
* its priority group in its home scheduler instance, otherwise it is
|
||||
* appended.
|
||||
* @param queue_context The thread queue context to return an updated set of
|
||||
* threads for _Thread_Priority_update(). The thread queue context must be
|
||||
* initialized via _Thread_queue_Context_clear_priority_updates() before a
|
||||
* call of this function.
|
||||
*
|
||||
* @see _Thread_Wait_acquire().
|
||||
*/
|
||||
RTEMS_INLINE_ROUTINE void _Thread_Priority_change(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Node *priority_node,
|
||||
Priority_Control new_priority,
|
||||
bool prepend_it,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
_Priority_Node_set_priority( priority_node, new_priority );
|
||||
_Thread_Priority_changed(
|
||||
the_thread,
|
||||
priority_node,
|
||||
prepend_it,
|
||||
queue_context
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replaces the victim priority node with the replacement priority node
|
||||
* in the corresponding thread priority aggregation.
|
||||
*
|
||||
* The caller must be the owner of the thread wait lock.
|
||||
*
|
||||
* @param the_thread The thread.
|
||||
* @param victim_node The victim thread priority node.
|
||||
* @param replacement_node The replacement thread priority node.
|
||||
*
|
||||
* @see _Thread_Wait_acquire().
|
||||
*/
|
||||
void _Thread_Priority_replace(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Node *victim_node,
|
||||
Priority_Node *replacement_node
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Adds a priority node to the corresponding thread priority
|
||||
* aggregation.
|
||||
*
|
||||
* The caller must be the owner of the thread wait lock.
|
||||
*
|
||||
* @param the_thread The thread.
|
||||
* @param priority_node The thread priority node to add.
|
||||
* @param queue_context The thread queue context to return an updated set of
|
||||
* threads for _Thread_Priority_update(). The thread queue context must be
|
||||
* initialized via _Thread_queue_Context_clear_priority_updates() before a
|
||||
* call of this function.
|
||||
*
|
||||
* @see _Thread_Priority_add(), _Thread_Priority_change(),
|
||||
* _Thread_Priority_changed() and _Thread_Priority_remove().
|
||||
*/
|
||||
void _Thread_Priority_update( Thread_queue_Context *queue_context );
|
||||
|
||||
/**
|
||||
* @brief Returns true if the left thread priority is less than the right
|
||||
* thread priority in the intuitive sense of priority and false otherwise.
|
||||
@@ -438,106 +595,6 @@ RTEMS_INLINE_ROUTINE Priority_Control _Thread_Priority_highest(
|
||||
return _Thread_Priority_less_than( left, right ) ? right : left;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Filters a thread priority change.
|
||||
*
|
||||
* Called by _Thread_Change_priority() under the protection of the thread lock.
|
||||
*
|
||||
* @param[in] the_thread The thread.
|
||||
* @param[in, out] new_priority The new priority of the thread. The filter may
|
||||
* alter this value.
|
||||
* @param[in] arg The argument passed to _Thread_Change_priority().
|
||||
*
|
||||
* @retval true Change the current priority.
|
||||
* @retval false Otherwise.
|
||||
*/
|
||||
typedef bool ( *Thread_Change_priority_filter )(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Control *new_priority,
|
||||
void *arg
|
||||
);
|
||||
|
||||
Thread_Control *_Thread_Apply_priority(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Control new_priority,
|
||||
void *arg,
|
||||
Thread_Change_priority_filter filter,
|
||||
bool prepend_it
|
||||
);
|
||||
|
||||
void _Thread_Update_priority( Thread_Control *the_thread );
|
||||
|
||||
/**
|
||||
* @brief Changes the priority of a thread if allowed by the filter function.
|
||||
*
|
||||
* It changes current priority of the thread to the new priority in case the
|
||||
* filter function returns true. In this case the scheduler is notified of the
|
||||
* priority change as well.
|
||||
*
|
||||
* @param[in] the_thread The thread.
|
||||
* @param[in] new_priority The new priority of the thread.
|
||||
* @param[in] arg The argument for the filter function.
|
||||
* @param[in] filter The filter function to determine if a priority change is
|
||||
* allowed and optionally perform other actions under the protection of the
|
||||
* thread lock simultaneously with the update of the current priority.
|
||||
* @param[in] prepend_it In case this is true, then the thread is prepended to
|
||||
* its priority group in its scheduler instance, otherwise it is appended.
|
||||
*/
|
||||
void _Thread_Change_priority(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Control new_priority,
|
||||
void *arg,
|
||||
Thread_Change_priority_filter filter,
|
||||
bool prepend_it
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Raises the priority of a thread.
|
||||
*
|
||||
* It changes the current priority of the thread to the new priority if the new
|
||||
* priority is higher than the current priority. In this case the thread is
|
||||
* appended to its new priority group in its scheduler instance.
|
||||
*
|
||||
* @param[in] the_thread The thread.
|
||||
* @param[in] new_priority The new priority of the thread.
|
||||
*
|
||||
* @see _Thread_Change_priority().
|
||||
*/
|
||||
void _Thread_Raise_priority(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Control new_priority
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Sets the current to the real priority of a thread.
|
||||
*
|
||||
* Sets the priority restore hint to false.
|
||||
*/
|
||||
void _Thread_Restore_priority( Thread_Control *the_thread );
|
||||
|
||||
/**
|
||||
* @brief Sets the priority of a thread.
|
||||
*
|
||||
* It sets the real priority of the thread. In addition it changes the current
|
||||
* priority of the thread if the new priority is higher than the current
|
||||
* priority or the thread owns no resources.
|
||||
*
|
||||
* @param[in] the_thread The thread.
|
||||
* @param[in] new_priority The new priority of the thread.
|
||||
* @param[out] old_priority The old real priority of the thread. This pointer
|
||||
* must not be @c NULL.
|
||||
* @param[in] prepend_it In case this is true, then the thread is prepended to
|
||||
* its priority group in its scheduler instance, otherwise it is appended.
|
||||
*
|
||||
* @see _Thread_Change_priority().
|
||||
*/
|
||||
void _Thread_Set_priority(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Control new_priority,
|
||||
Priority_Control *old_priority,
|
||||
bool prepend_it
|
||||
);
|
||||
|
||||
RTEMS_INLINE_ROUTINE Objects_Information *_Thread_Get_objects_information(
|
||||
Objects_Id id
|
||||
)
|
||||
@@ -929,6 +986,17 @@ RTEMS_INLINE_ROUTINE bool _Thread_Owns_resources(
|
||||
return owns_resources;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE Scheduler_Node *_Thread_Scheduler_get_own_node(
|
||||
const Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
#if defined(RTEMS_SMP)
|
||||
return the_thread->Scheduler.own_node;
|
||||
#else
|
||||
return the_thread->Scheduler.node;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the priority of the thread.
|
||||
*
|
||||
@@ -937,14 +1005,15 @@ RTEMS_INLINE_ROUTINE bool _Thread_Owns_resources(
|
||||
* protocols, a job release or the POSIX sporadic server for example.
|
||||
*
|
||||
* @return The priority of the thread.
|
||||
*
|
||||
* @see _Scheduler_Node_get_priority().
|
||||
*/
|
||||
RTEMS_INLINE_ROUTINE Priority_Control _Thread_Get_priority(
|
||||
const Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
return the_thread->current_priority;
|
||||
Scheduler_Node *scheduler_node;
|
||||
|
||||
scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
|
||||
return _Priority_Get_priority( &scheduler_node->Wait.Priority );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1389,7 +1458,11 @@ RTEMS_INLINE_ROUTINE void _Thread_Wait_cancel(
|
||||
_Assert( queue_context->Lock_context.Wait.queue == queue );
|
||||
#endif
|
||||
|
||||
( *the_thread->Wait.operations->extract )( queue, the_thread );
|
||||
( *the_thread->Wait.operations->extract )(
|
||||
queue,
|
||||
the_thread,
|
||||
queue_context
|
||||
);
|
||||
_Thread_Wait_restore_default( the_thread );
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Scheduler_Node;
|
||||
|
||||
/**
|
||||
* @defgroup ScoreThreadQueue Thread Queue Handler
|
||||
*
|
||||
@@ -47,8 +49,6 @@ typedef struct Thread_queue_Queue Thread_queue_Queue;
|
||||
|
||||
typedef struct Thread_queue_Operations Thread_queue_Operations;
|
||||
|
||||
typedef struct Thread_queue_Path Thread_queue_Path;
|
||||
|
||||
/**
|
||||
* @brief Thread queue deadlock callout.
|
||||
*
|
||||
@@ -195,6 +195,56 @@ typedef struct {
|
||||
*/
|
||||
uint64_t timeout;
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
/**
|
||||
* @brief Representation of a thread queue path from a start thread queue to
|
||||
* the terminal thread queue.
|
||||
*
|
||||
* The start thread queue is determined by the object on which a thread intends
|
||||
* to block. The terminal thread queue is the thread queue reachable via
|
||||
* thread queue links whose owner is not blocked on a thread queue. The thread
|
||||
* queue links are determined by the thread queue owner and thread wait queue
|
||||
* relationships.
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
* @brief The chain of thread queue links defining the thread queue path.
|
||||
*/
|
||||
Chain_Control Links;
|
||||
|
||||
/**
|
||||
* @brief The start of a thread queue path.
|
||||
*/
|
||||
Thread_queue_Link Start;
|
||||
} Path;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Block to manage thread priority changes due to a thread queue
|
||||
* operation.
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
* @brief A priority action list.
|
||||
*/
|
||||
Priority_Actions Actions;
|
||||
|
||||
/**
|
||||
* @brief Count of threads to update the priority via
|
||||
* _Thread_Priority_update().
|
||||
*/
|
||||
size_t update_count;
|
||||
|
||||
/**
|
||||
* @brief Threads to update the priority via _Thread_Priority_update().
|
||||
*
|
||||
* Currently, a maximum of two threads need an update in one rush, for
|
||||
* example the thread of the thread queue operation and the owner of the
|
||||
* thread queue.
|
||||
*/
|
||||
Thread_Control *update[ 2 ];
|
||||
} Priority;
|
||||
|
||||
/**
|
||||
* @brief Invoked in case of a detected deadlock.
|
||||
*
|
||||
@@ -237,7 +287,13 @@ typedef struct {
|
||||
/**
|
||||
* @brief The actual thread priority queue.
|
||||
*/
|
||||
RBTree_Control Queue;
|
||||
Priority_Aggregation Queue;
|
||||
|
||||
/**
|
||||
* @brief This priority queue is added to a scheduler node of the owner in
|
||||
* case of priority inheritance.
|
||||
*/
|
||||
struct Scheduler_Node *scheduler_node;
|
||||
} Thread_queue_Priority_queue;
|
||||
|
||||
/**
|
||||
@@ -288,6 +344,11 @@ typedef struct _Thread_queue_Heads {
|
||||
Chain_Node Free_node;
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
/**
|
||||
* @brief Boost priority.
|
||||
*/
|
||||
Priority_Node Boost_priority;
|
||||
|
||||
/**
|
||||
* @brief One priority queue per scheduler instance.
|
||||
*/
|
||||
@@ -337,34 +398,33 @@ struct Thread_queue_Queue {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Thread queue priority change operation.
|
||||
* @brief Thread queue action operation.
|
||||
*
|
||||
* @param[in] queue The actual thread queue.
|
||||
* @param[in] the_thread The thread.
|
||||
* @param[in] new_priority The new priority value.
|
||||
*
|
||||
* @see Thread_queue_Operations.
|
||||
* @param[in] queue_context The thread queue context providing the thread queue
|
||||
* action set to perform. Returns the thread queue action set to perform on
|
||||
* the thread queue owner or the empty set in case there is nothing to do.
|
||||
*/
|
||||
typedef void ( *Thread_queue_Priority_change_operation )(
|
||||
Thread_queue_Queue *queue,
|
||||
Thread_Control *the_thread,
|
||||
Priority_Control new_priority
|
||||
typedef void ( *Thread_queue_Priority_actions_operation )(
|
||||
Thread_queue_Queue *queue,
|
||||
Priority_Actions *priority_actions
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Thread queue enqueue operation.
|
||||
*
|
||||
* A potential thread to update the priority due to priority inheritance is
|
||||
* returned via the thread queue path. This thread is handed over to
|
||||
* _Thread_Update_priority().
|
||||
* returned via the thread queue context. This thread is handed over to
|
||||
* _Thread_Priority_update().
|
||||
*
|
||||
* @param[in] queue The actual thread queue.
|
||||
* @param[in] the_thread The thread to enqueue on the queue.
|
||||
*/
|
||||
typedef void ( *Thread_queue_Enqueue_operation )(
|
||||
Thread_queue_Queue *queue,
|
||||
Thread_Control *the_thread,
|
||||
Thread_queue_Path *path
|
||||
Thread_queue_Queue *queue,
|
||||
Thread_Control *the_thread,
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -374,8 +434,9 @@ typedef void ( *Thread_queue_Enqueue_operation )(
|
||||
* @param[in] the_thread The thread to extract from the thread queue.
|
||||
*/
|
||||
typedef void ( *Thread_queue_Extract_operation )(
|
||||
Thread_queue_Queue *queue,
|
||||
Thread_Control *the_thread
|
||||
Thread_queue_Queue *queue,
|
||||
Thread_Control *the_thread,
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -390,9 +451,10 @@ typedef void ( *Thread_queue_Extract_operation )(
|
||||
* @return The previous first thread on the queue.
|
||||
*/
|
||||
typedef Thread_Control *( *Thread_queue_Surrender_operation )(
|
||||
Thread_queue_Queue *queue,
|
||||
Thread_queue_Heads *heads,
|
||||
Thread_Control *previous_owner
|
||||
Thread_queue_Queue *queue,
|
||||
Thread_queue_Heads *heads,
|
||||
Thread_Control *previous_owner,
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -415,16 +477,9 @@ typedef Thread_Control *( *Thread_queue_First_operation )(
|
||||
*/
|
||||
struct Thread_queue_Operations {
|
||||
/**
|
||||
* @brief Thread queue priority change operation.
|
||||
*
|
||||
* Called by _Thread_Change_priority() to notify a thread about a priority
|
||||
* change. In case this thread waits currently for a resource the handler
|
||||
* may adjust its data structures according to the new priority value. This
|
||||
* handler must not be NULL, instead the default handler
|
||||
* _Thread_Do_nothing_priority_change() should be used in case nothing needs
|
||||
* to be done during a priority change.
|
||||
* @brief Thread queue priority actions operation.
|
||||
*/
|
||||
Thread_queue_Priority_change_operation priority_change;
|
||||
Thread_queue_Priority_actions_operation priority_actions;
|
||||
|
||||
/**
|
||||
* @brief Thread queue enqueue operation.
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include <rtems/score/threadq.h>
|
||||
#include <rtems/score/chainimpl.h>
|
||||
#include <rtems/score/rbtreeimpl.h>
|
||||
#include <rtems/score/priorityimpl.h>
|
||||
#include <rtems/score/scheduler.h>
|
||||
#include <rtems/score/smp.h>
|
||||
#include <rtems/score/thread.h>
|
||||
@@ -39,38 +39,8 @@ extern "C" {
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/**
|
||||
* @brief Representation of a thread queue path from a start thread queue to
|
||||
* the terminal thread queue.
|
||||
*
|
||||
* The start thread queue is determined by the object on which a thread intends
|
||||
* to block. The terminal thread queue is the thread queue reachable via
|
||||
* thread queue links those owner is not blocked on a thread queue. The thread
|
||||
* queue links are determined by the thread queue owner and thread wait queue
|
||||
* relationships.
|
||||
*/
|
||||
struct Thread_queue_Path {
|
||||
#if defined(RTEMS_SMP)
|
||||
/**
|
||||
* @brief The chain of thread queue links defining the thread queue path.
|
||||
*/
|
||||
Chain_Control Links;
|
||||
|
||||
/**
|
||||
* @brief The start of a thread queue path.
|
||||
*/
|
||||
Thread_queue_Link Start;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief A potential thread to update the priority via
|
||||
* _Thread_Update_priority().
|
||||
*
|
||||
* This thread is determined by thread queues which support priority
|
||||
* inheritance.
|
||||
*/
|
||||
Thread_Control *update_priority;
|
||||
};
|
||||
#define THREAD_QUEUE_LINK_OF_PATH_NODE( node ) \
|
||||
RTEMS_CONTAINER_OF( node, Thread_queue_Link, Path_node );
|
||||
|
||||
/**
|
||||
* @brief Thread queue with a layout compatible to struct _Thread_queue_Queue
|
||||
@@ -210,6 +180,42 @@ RTEMS_INLINE_ROUTINE void _Thread_queue_Context_set_deadlock_callout(
|
||||
queue_context->deadlock_callout = deadlock_callout;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Thread_queue_Context_clear_priority_updates(
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
queue_context->Priority.update_count = 0;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE size_t _Thread_queue_Context_save_priority_updates(
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
return queue_context->Priority.update_count;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Thread_queue_Context_restore_priority_updates(
|
||||
Thread_queue_Context *queue_context,
|
||||
size_t update_count
|
||||
)
|
||||
{
|
||||
queue_context->Priority.update_count = update_count;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Thread_queue_Context_add_priority_update(
|
||||
Thread_queue_Context *queue_context,
|
||||
Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
n = queue_context->Priority.update_count;
|
||||
_Assert( n < RTEMS_ARRAY_SIZE( queue_context->Priority.update ) );
|
||||
|
||||
queue_context->Priority.update_count = n + 1;
|
||||
queue_context->Priority.update[ n ] = the_thread;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the MP callout in the thread queue context.
|
||||
*
|
||||
@@ -274,9 +280,12 @@ RTEMS_INLINE_ROUTINE void _Thread_queue_Heads_initialize(
|
||||
#if defined(RTEMS_SMP)
|
||||
size_t i;
|
||||
|
||||
_Priority_Node_initialize( &heads->Boost_priority, 0 );
|
||||
_Priority_Node_set_inactive( &heads->Boost_priority );
|
||||
|
||||
for ( i = 0; i < _Scheduler_Count; ++i ) {
|
||||
_Chain_Initialize_node( &heads->Priority[ i ].Node );
|
||||
_RBTree_Initialize_empty( &heads->Priority[ i ].Queue );
|
||||
_Priority_Initialize_empty( &heads->Priority[ i ].Queue );
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -579,16 +588,6 @@ RTEMS_INLINE_ROUTINE void _Thread_queue_Enqueue(
|
||||
);
|
||||
}
|
||||
|
||||
bool _Thread_queue_Do_extract_locked(
|
||||
Thread_queue_Queue *queue,
|
||||
const Thread_queue_Operations *operations,
|
||||
Thread_Control *the_thread
|
||||
#if defined(RTEMS_MULTIPROCESSING)
|
||||
,
|
||||
const Thread_queue_Context *queue_context
|
||||
#endif
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Extracts the thread from the thread queue, restores the default wait
|
||||
* operations and restores the default thread lock.
|
||||
@@ -599,8 +598,7 @@ bool _Thread_queue_Do_extract_locked(
|
||||
* @param[in] queue The actual thread queue.
|
||||
* @param[in] operations The thread queue operations.
|
||||
* @param[in] the_thread The thread to extract.
|
||||
* @param[in] queue_context The thread queue context. This parameter is only
|
||||
* used on multiprocessing configurations.
|
||||
* @param[in] queue_context The thread queue context.
|
||||
*
|
||||
* @return Returns the unblock indicator for _Thread_queue_Unblock_critical().
|
||||
* True indicates, that this thread must be unblocked by the scheduler later in
|
||||
@@ -610,32 +608,12 @@ bool _Thread_queue_Do_extract_locked(
|
||||
* since this thread may already block on another resource in an SMP
|
||||
* configuration.
|
||||
*/
|
||||
#if defined(RTEMS_MULTIPROCESSING)
|
||||
#define _Thread_queue_Extract_locked( \
|
||||
unblock, \
|
||||
queue, \
|
||||
the_thread, \
|
||||
queue_context \
|
||||
) \
|
||||
_Thread_queue_Do_extract_locked( \
|
||||
unblock, \
|
||||
queue, \
|
||||
the_thread, \
|
||||
queue_context \
|
||||
)
|
||||
#else
|
||||
#define _Thread_queue_Extract_locked( \
|
||||
unblock, \
|
||||
queue, \
|
||||
the_thread, \
|
||||
queue_context \
|
||||
) \
|
||||
_Thread_queue_Do_extract_locked( \
|
||||
unblock, \
|
||||
queue, \
|
||||
the_thread \
|
||||
)
|
||||
#endif
|
||||
bool _Thread_queue_Extract_locked(
|
||||
Thread_queue_Queue *queue,
|
||||
const Thread_queue_Operations *operations,
|
||||
Thread_Control *the_thread,
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Unblocks the thread which was on the thread queue before.
|
||||
@@ -735,7 +713,7 @@ void _Thread_queue_Extract_with_proxy(
|
||||
|
||||
/**
|
||||
* @brief Surrenders the thread queue previously owned by the thread to the
|
||||
* first enqueued thread if it exists.
|
||||
* first enqueued thread.
|
||||
*
|
||||
* The owner of the thread queue must be set to NULL by the caller.
|
||||
*
|
||||
@@ -743,21 +721,18 @@ void _Thread_queue_Extract_with_proxy(
|
||||
* thread dispatch if necessary.
|
||||
*
|
||||
* @param[in] queue The actual thread queue.
|
||||
* @param[in] operations The thread queue operations.
|
||||
* @param[in] heads The thread queue heads.
|
||||
* @param[in] heads The thread queue heads. It must not be NULL.
|
||||
* @param[in] previous_owner The previous owner thread surrendering the thread
|
||||
* queue.
|
||||
* @param[in] keep_priority Indicates if the previous owner thread should keep
|
||||
* its current priority.
|
||||
* @param[in] queue_context The thread queue context of the lock acquire.
|
||||
* @param[in] operations The thread queue operations.
|
||||
*/
|
||||
void _Thread_queue_Surrender(
|
||||
Thread_queue_Queue *queue,
|
||||
const Thread_queue_Operations *operations,
|
||||
Thread_queue_Heads *heads,
|
||||
Thread_Control *previous_owner,
|
||||
bool keep_priority,
|
||||
Thread_queue_Context *queue_context
|
||||
Thread_queue_Context *queue_context,
|
||||
const Thread_queue_Operations *operations
|
||||
);
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _Thread_queue_Is_empty(
|
||||
@@ -980,6 +955,16 @@ void _Thread_queue_Unblock_proxy(
|
||||
);
|
||||
#endif
|
||||
|
||||
bool _Thread_queue_Path_acquire_critical(
|
||||
Thread_queue_Queue *queue,
|
||||
Thread_Control *the_thread,
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
void _Thread_queue_Path_release_critical(
|
||||
Thread_queue_Context *queue_context
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Helper structure to ensure that all objects containing a thread queue
|
||||
* have the right layout.
|
||||
|
||||
@@ -200,6 +200,10 @@ $(PROJECT_INCLUDE)/rtems/score/priority.h: include/rtems/score/priority.h $(PROJ
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/priority.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/priority.h
|
||||
|
||||
$(PROJECT_INCLUDE)/rtems/score/priorityimpl.h: include/rtems/score/priorityimpl.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/priorityimpl.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/priorityimpl.h
|
||||
|
||||
$(PROJECT_INCLUDE)/rtems/score/prioritybitmap.h: include/rtems/score/prioritybitmap.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/prioritybitmap.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/prioritybitmap.h
|
||||
|
||||
@@ -128,33 +128,20 @@ static void _Mutex_Release_critical(
|
||||
)
|
||||
{
|
||||
Thread_queue_Heads *heads;
|
||||
bool keep_priority;
|
||||
|
||||
mutex->Queue.Queue.owner = NULL;
|
||||
|
||||
--executing->resource_count;
|
||||
|
||||
/*
|
||||
* Ensure that the owner resource count is visible to all other
|
||||
* processors and that we read the latest priority restore
|
||||
* hint.
|
||||
*/
|
||||
_Atomic_Fence( ATOMIC_ORDER_ACQ_REL );
|
||||
|
||||
heads = mutex->Queue.Queue.heads;
|
||||
keep_priority = _Thread_Owns_resources( executing )
|
||||
|| !executing->priority_restore_hint;
|
||||
mutex->Queue.Queue.owner = NULL;
|
||||
--executing->resource_count;
|
||||
|
||||
if ( __predict_true( heads == NULL && keep_priority ) ) {
|
||||
if ( __predict_true( heads == NULL ) ) {
|
||||
_Mutex_Queue_release( mutex, queue_context );
|
||||
} else {
|
||||
_Thread_queue_Surrender(
|
||||
&mutex->Queue.Queue,
|
||||
MUTEX_TQ_OPERATIONS,
|
||||
heads,
|
||||
executing,
|
||||
keep_priority,
|
||||
queue_context
|
||||
queue_context,
|
||||
MUTEX_TQ_OPERATIONS
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,24 +19,28 @@
|
||||
#endif
|
||||
|
||||
#include <rtems/score/schedulercbsimpl.h>
|
||||
#include <rtems/score/threadimpl.h>
|
||||
#include <rtems/score/wkspace.h>
|
||||
|
||||
void _Scheduler_CBS_Budget_callout(
|
||||
Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
Priority_Control new_priority;
|
||||
Priority_Control unused;
|
||||
Scheduler_CBS_Node *node;
|
||||
Scheduler_CBS_Server_id server_id;
|
||||
Scheduler_CBS_Node *node;
|
||||
Scheduler_CBS_Server_id server_id;
|
||||
Thread_queue_Context queue_context;
|
||||
|
||||
node = _Scheduler_CBS_Thread_get_node( the_thread );
|
||||
|
||||
/* Put violating task to background until the end of period. */
|
||||
new_priority = the_thread->Start.initial_priority;
|
||||
_Thread_Set_priority( the_thread, new_priority, &unused, true );
|
||||
_Thread_queue_Context_clear_priority_updates( &queue_context );
|
||||
_Scheduler_CBS_Cancel_job(
|
||||
NULL,
|
||||
the_thread,
|
||||
node->deadline_node,
|
||||
&queue_context
|
||||
);
|
||||
_Thread_Priority_update( &queue_context );
|
||||
|
||||
/* Invoke callback function if any. */
|
||||
node = _Scheduler_CBS_Thread_get_node( the_thread );
|
||||
if ( node->cbs_server->cbs_budget_overrun ) {
|
||||
_Scheduler_CBS_Get_server_id(
|
||||
node->cbs_server->task_id,
|
||||
|
||||
@@ -33,4 +33,5 @@ void _Scheduler_CBS_Node_initialize(
|
||||
|
||||
the_node = _Scheduler_CBS_Node_downcast( node );
|
||||
the_node->cbs_server = NULL;
|
||||
the_node->deadline_node = NULL;
|
||||
}
|
||||
|
||||
@@ -21,10 +21,12 @@
|
||||
|
||||
#include <rtems/score/schedulercbsimpl.h>
|
||||
|
||||
Thread_Control *_Scheduler_CBS_Release_job(
|
||||
void _Scheduler_CBS_Release_job(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
uint64_t deadline
|
||||
Priority_Node *priority_node,
|
||||
uint64_t deadline,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
Scheduler_CBS_Node *node;
|
||||
@@ -38,5 +40,37 @@ Thread_Control *_Scheduler_CBS_Release_job(
|
||||
the_thread->cpu_time_budget = serv_info->parameters.budget;
|
||||
}
|
||||
|
||||
return _Scheduler_EDF_Release_job( scheduler, the_thread, deadline );
|
||||
node->deadline_node = priority_node;
|
||||
|
||||
_Scheduler_EDF_Release_job(
|
||||
scheduler,
|
||||
the_thread,
|
||||
priority_node,
|
||||
deadline,
|
||||
queue_context
|
||||
);
|
||||
}
|
||||
|
||||
void _Scheduler_CBS_Cancel_job(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
Priority_Node *priority_node,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
Scheduler_CBS_Node *node;
|
||||
|
||||
node = _Scheduler_CBS_Thread_get_node( the_thread );
|
||||
|
||||
if ( node->deadline_node != NULL ) {
|
||||
_Assert( node->deadline_node == priority_node );
|
||||
node->deadline_node = NULL;
|
||||
|
||||
_Scheduler_EDF_Cancel_job(
|
||||
scheduler,
|
||||
the_thread,
|
||||
priority_node,
|
||||
queue_context
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,13 +30,11 @@ Scheduler_Void_or_thread _Scheduler_CBS_Unblock(
|
||||
Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
Scheduler_EDF_Context *context;
|
||||
Scheduler_CBS_Node *node;
|
||||
Scheduler_CBS_Server *serv_info;
|
||||
Priority_Control priority;
|
||||
bool prepend_it;
|
||||
Scheduler_CBS_Node *node;
|
||||
Scheduler_CBS_Server *serv_info;
|
||||
Priority_Control priority;
|
||||
bool prepend_it;
|
||||
|
||||
context = _Scheduler_EDF_Get_context( scheduler );
|
||||
node = _Scheduler_CBS_Thread_get_node( the_thread );
|
||||
serv_info = node->cbs_server;
|
||||
priority = _Scheduler_Node_get_priority( &node->Base.Base, &prepend_it );
|
||||
@@ -55,40 +53,19 @@ Scheduler_Void_or_thread _Scheduler_CBS_Unblock(
|
||||
Priority_Control budget_left = priority - _Watchdog_Ticks_since_boot;
|
||||
|
||||
if ( deadline * budget_left > budget * deadline_left ) {
|
||||
Thread_queue_Context queue_context;
|
||||
|
||||
/* Put late unblocked task to background until the end of period. */
|
||||
|
||||
priority = node->Base.background_priority;
|
||||
the_thread->real_priority = priority;
|
||||
|
||||
if (
|
||||
_Thread_Priority_less_than(
|
||||
_Thread_Get_priority( the_thread ),
|
||||
priority
|
||||
) || !_Thread_Owns_resources( the_thread )
|
||||
) {
|
||||
the_thread->current_priority = priority;
|
||||
}
|
||||
_Thread_queue_Context_clear_priority_updates( &queue_context );
|
||||
_Scheduler_CBS_Cancel_job(
|
||||
scheduler,
|
||||
the_thread,
|
||||
node->deadline_node,
|
||||
&queue_context
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
node->Base.current_priority = priority;
|
||||
_Scheduler_EDF_Enqueue( context, &node->Base, priority );
|
||||
|
||||
/*
|
||||
* If the thread that was unblocked is more important than the heir,
|
||||
* then we have a new heir. This may or may not result in a
|
||||
* context switch.
|
||||
*
|
||||
* Normal case:
|
||||
* If the current thread is preemptible, then we need to do
|
||||
* a context switch.
|
||||
* Pseudo-ISR case:
|
||||
* Even if the thread isn't preemptible, if the new heir is
|
||||
* a pseudo-ISR system task, we need to do a context switch.
|
||||
*/
|
||||
if ( priority < _Thread_Get_priority( _Thread_Heir ) ) {
|
||||
_Scheduler_Update_heir( the_thread, priority == PRIORITY_PSEUDO_ISR );
|
||||
}
|
||||
|
||||
_Scheduler_EDF_Unblock( scheduler, the_thread );
|
||||
SCHEDULER_RETURN_VOID_OR_NULL;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,5 @@ void _Scheduler_default_Node_initialize(
|
||||
Priority_Control priority
|
||||
)
|
||||
{
|
||||
(void) scheduler;
|
||||
|
||||
_Scheduler_Node_do_initialize( node, the_thread, priority );
|
||||
_Scheduler_Node_do_initialize( scheduler, node, the_thread, priority );
|
||||
}
|
||||
|
||||
@@ -21,26 +21,30 @@
|
||||
|
||||
#include <rtems/score/scheduler.h>
|
||||
|
||||
Thread_Control *_Scheduler_default_Release_job(
|
||||
void _Scheduler_default_Release_job(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
uint64_t deadline
|
||||
Priority_Node *priority_node,
|
||||
uint64_t deadline,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
(void) scheduler;
|
||||
(void) the_thread;
|
||||
(void) priority_node;
|
||||
(void) deadline;
|
||||
|
||||
return NULL;
|
||||
(void) queue_context;
|
||||
}
|
||||
|
||||
Thread_Control *_Scheduler_default_Cancel_job(
|
||||
void _Scheduler_default_Cancel_job(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread
|
||||
Thread_Control *the_thread,
|
||||
Priority_Node *priority_node,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
(void) scheduler;
|
||||
(void) the_thread;
|
||||
|
||||
return NULL;
|
||||
(void) priority_node;
|
||||
(void) queue_context;
|
||||
}
|
||||
|
||||
@@ -54,16 +54,12 @@ Scheduler_Void_or_thread _Scheduler_EDF_Update_priority(
|
||||
node = _Scheduler_EDF_Thread_get_node( the_thread );
|
||||
priority = _Scheduler_Node_get_priority( &node->Base, &prepend_it );
|
||||
|
||||
if ( priority == node->current_priority ) {
|
||||
if ( priority == node->priority ) {
|
||||
/* Nothing to do */
|
||||
SCHEDULER_RETURN_VOID_OR_NULL;
|
||||
}
|
||||
|
||||
if ( ( priority & SCHEDULER_EDF_PRIO_MSB ) != 0 ) {
|
||||
node->background_priority = priority;
|
||||
}
|
||||
|
||||
node->current_priority = priority;
|
||||
node->priority = priority;
|
||||
context = _Scheduler_EDF_Get_context( scheduler );
|
||||
|
||||
_Scheduler_EDF_Extract( context, node );
|
||||
|
||||
@@ -29,11 +29,9 @@ void _Scheduler_EDF_Node_initialize(
|
||||
{
|
||||
Scheduler_EDF_Node *the_node;
|
||||
|
||||
(void) scheduler;
|
||||
|
||||
_Scheduler_Node_do_initialize( node, the_thread, priority );
|
||||
_Scheduler_Node_do_initialize( scheduler, node, the_thread, priority );
|
||||
|
||||
the_node = _Scheduler_EDF_Node_downcast( node );
|
||||
the_node->thread = the_thread;
|
||||
_RBTree_Initialize_node( &the_node->Node );
|
||||
the_node->priority = priority;
|
||||
}
|
||||
|
||||
@@ -20,75 +20,47 @@
|
||||
|
||||
#include <rtems/score/scheduleredfimpl.h>
|
||||
|
||||
static bool _Scheduler_EDF_Release_job_filter(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Control *new_priority_p,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
Scheduler_EDF_Node *node;
|
||||
Priority_Control current_priority;
|
||||
Priority_Control new_priority;
|
||||
|
||||
node = _Scheduler_EDF_Thread_get_node( the_thread );
|
||||
|
||||
current_priority = _Thread_Get_priority( the_thread );
|
||||
new_priority = *new_priority_p;
|
||||
|
||||
node->current_priority = new_priority;
|
||||
the_thread->real_priority = new_priority;
|
||||
|
||||
return _Thread_Priority_less_than( current_priority, new_priority )
|
||||
|| !_Thread_Owns_resources( the_thread );
|
||||
}
|
||||
|
||||
Thread_Control *_Scheduler_EDF_Release_job(
|
||||
void _Scheduler_EDF_Release_job(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
uint64_t deadline
|
||||
Priority_Node *priority_node,
|
||||
uint64_t deadline,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
return _Thread_Apply_priority(
|
||||
the_thread,
|
||||
deadline,
|
||||
NULL,
|
||||
_Scheduler_EDF_Release_job_filter,
|
||||
true
|
||||
);
|
||||
(void) scheduler;
|
||||
|
||||
_Thread_Wait_acquire_critical( the_thread, queue_context );
|
||||
|
||||
_Priority_Node_set_priority( priority_node, deadline );
|
||||
|
||||
if ( _Priority_Node_is_active( priority_node ) ) {
|
||||
_Thread_Priority_changed(
|
||||
the_thread,
|
||||
priority_node,
|
||||
false,
|
||||
queue_context
|
||||
);
|
||||
} else {
|
||||
_Thread_Priority_add( the_thread, priority_node, queue_context );
|
||||
}
|
||||
|
||||
_Thread_Wait_release_critical( the_thread, queue_context );
|
||||
}
|
||||
|
||||
static bool _Scheduler_EDF_Cancel_job_filter(
|
||||
Thread_Control *the_thread,
|
||||
Priority_Control *new_priority_p,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
Scheduler_EDF_Node *node;
|
||||
Priority_Control current_priority;
|
||||
Priority_Control new_priority;
|
||||
|
||||
node = _Scheduler_EDF_Thread_get_node( the_thread );
|
||||
|
||||
current_priority = _Thread_Get_priority( the_thread );
|
||||
new_priority = node->background_priority;
|
||||
|
||||
node->current_priority = new_priority;
|
||||
the_thread->real_priority = new_priority;
|
||||
|
||||
return _Thread_Priority_less_than( current_priority, new_priority )
|
||||
|| !_Thread_Owns_resources( the_thread );
|
||||
}
|
||||
|
||||
Thread_Control *_Scheduler_EDF_Cancel_job(
|
||||
void _Scheduler_EDF_Cancel_job(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread
|
||||
Thread_Control *the_thread,
|
||||
Priority_Node *priority_node,
|
||||
Thread_queue_Context *queue_context
|
||||
)
|
||||
{
|
||||
return _Thread_Apply_priority(
|
||||
the_thread,
|
||||
0,
|
||||
NULL,
|
||||
_Scheduler_EDF_Cancel_job_filter,
|
||||
true
|
||||
);
|
||||
(void) scheduler;
|
||||
|
||||
_Thread_Wait_acquire_critical( the_thread, queue_context );
|
||||
|
||||
_Thread_Priority_remove( the_thread, priority_node, queue_context );
|
||||
_Priority_Node_set_inactive( priority_node );
|
||||
|
||||
_Thread_Wait_release_critical( the_thread, queue_context );
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ Scheduler_Void_or_thread _Scheduler_EDF_Unblock(
|
||||
priority = _Scheduler_Node_get_priority( &node->Base, &prepend_it );
|
||||
(void) prepend_it;
|
||||
|
||||
node->current_priority = priority;
|
||||
node->priority = priority;
|
||||
_Scheduler_EDF_Enqueue( context, node, priority );
|
||||
|
||||
/*
|
||||
|
||||
@@ -33,7 +33,7 @@ Scheduler_Void_or_thread _Scheduler_EDF_Yield(
|
||||
node = _Scheduler_EDF_Thread_get_node( the_thread );
|
||||
|
||||
_Scheduler_EDF_Extract( context, node );
|
||||
_Scheduler_EDF_Enqueue( context, node, node->current_priority );
|
||||
_Scheduler_EDF_Enqueue( context, node, node->priority );
|
||||
_Scheduler_EDF_Schedule_body( scheduler, the_thread, true );
|
||||
|
||||
SCHEDULER_RETURN_VOID_OR_NULL;
|
||||
|
||||
@@ -43,7 +43,7 @@ void _Scheduler_priority_Node_initialize(
|
||||
Scheduler_priority_Context *context;
|
||||
Scheduler_priority_Node *the_node;
|
||||
|
||||
_Scheduler_Node_do_initialize( node, the_thread, priority );
|
||||
_Scheduler_Node_do_initialize( scheduler, node, the_thread, priority );
|
||||
|
||||
context = _Scheduler_priority_Get_context( scheduler );
|
||||
the_node = _Scheduler_priority_Node_downcast( node );
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user