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:
Sebastian Huber
2016-09-21 08:59:26 +02:00
parent 8c83cbcc96
commit 300f6a481a
68 changed files with 2908 additions and 1566 deletions
+1 -1
View File
@@ -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;
}
/**
+3 -3
View File
@@ -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.
*
+1 -7
View File
@@ -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. */
+1 -1
View File
@@ -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 ];
+12 -1
View File
@@ -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
View File
@@ -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 );
}
/*
+15 -17
View File
@@ -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 );
}
/*
+1 -1
View File
@@ -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 );
+73 -68
View File
@@ -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;
}
+30 -62
View File
@@ -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.
+8 -4
View File
@@ -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 );
}
+2
View File
@@ -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;
+10 -5
View File
@@ -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 );
}
+13 -5
View File
@@ -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;
+40 -57
View File
@@ -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;
}
+2 -1
View File
@@ -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
+2 -2
View File
@@ -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;
}
+4 -8
View File
@@ -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.
+146 -113
View File
@@ -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 );
+142 -33
View File
@@ -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 */
+20 -8
View File
@@ -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
);
/**
+10 -16
View File
@@ -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,
&current_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,
&current_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;
}
+5 -48
View File
@@ -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;
+177 -104
View File
@@ -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)
+85 -30
View File
@@ -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.
+65 -80
View File
@@ -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.
+4
View File
@@ -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
+5 -18
View File
@@ -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
);
}
}
+13 -9
View File
@@ -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,
+1
View File
@@ -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;
}
+37 -3
View File
@@ -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
);
}
}
+14 -37
View File
@@ -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;
}
+1 -3
View File
@@ -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 );
}
+12 -8
View File
@@ -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 );
+2 -4
View File
@@ -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;
}
+34 -62
View File
@@ -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 );
}
+1 -1
View File
@@ -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 );
/*
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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