score: Introduce CPU budget operations

This patch set replaces the CPU budget algorithm enumeration with a set of CPU
budget operations which implement a particular CPU budget algorithm.  This
helps to hide the CPU budget algorithm implementation details from the general
thread handling.  The CPU budget callouts are turned into CPU budget
operations.  This slightly reduces the size of the thread control block.

All schedulers used the default scheduler tick implementation.  The tick
scheduler operation is removed and the CPU budget operations are directly used
in _Watchdog_Tick() if the executing thread uses a CPU budget algorithm.  This
is performance improvement for all threads which do not use a CPU budget
algorithm (default behaviour).
This commit is contained in:
Sebastian Huber
2021-11-15 08:56:53 +01:00
parent 6cef3f16b6
commit 240a1f79b1
43 changed files with 520 additions and 333 deletions
+4 -11
View File
@@ -47,7 +47,7 @@ RTEMS_INLINE_ROUTINE void _POSIX_Threads_Sporadic_timer_insert(
POSIX_API_Control *api
)
{
the_thread->cpu_time_budget =
the_thread->CPU_budget.available =
_Timespec_To_ticks( &api->Sporadic.sched_ss_init_budget );
_Watchdog_Per_CPU_insert_ticks(
@@ -61,19 +61,12 @@ RTEMS_INLINE_ROUTINE void _POSIX_Threads_Sporadic_timer_insert(
void _POSIX_Threads_Sporadic_timer( Watchdog_Control *watchdog );
/**
* @brief POSIX threads sporadic budget callout.
*
* This routine handles the sporadic scheduling algorithm.
*
* @param[in] the_thread is a pointer to the thread whose budget
* has been exceeded.
* @brief The POSIX threads sporadic budget operations.
*/
void _POSIX_Threads_Sporadic_budget_callout(
Thread_Control *the_thread
);
extern const Thread_CPU_budget_operations _POSIX_Threads_Sporadic_budget;
int _POSIX_Thread_Translate_to_sched_policy(
Thread_CPU_budget_algorithms budget_algorithm
const Thread_CPU_budget_operations *operations
);
/**
+5 -3
View File
@@ -22,6 +22,7 @@
#include <rtems/score/schedulerimpl.h>
#include <rtems/score/smpimpl.h>
#include <rtems/score/threadimpl.h>
#include <rtems/score/threadcpubudget.h>
#include <rtems/config.h>
#ifdef __cplusplus
@@ -148,10 +149,11 @@ RTEMS_INLINE_ROUTINE void _Modes_Apply_timeslice_to_thread(
)
{
if ( _Modes_Is_timeslice( mode_set ) ) {
the_thread->budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE;
the_thread->cpu_time_budget = rtems_configuration_get_ticks_per_timeslice();
the_thread->CPU_budget.operations = &_Thread_CPU_budget_reset_timeslice;
the_thread->CPU_budget.available =
rtems_configuration_get_ticks_per_timeslice();
} else {
the_thread->budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE;
the_thread->CPU_budget.operations = NULL;
}
}
-17
View File
@@ -217,9 +217,6 @@ typedef struct {
Thread_queue_Context *
);
/** @see _Scheduler_Tick() */
void ( *tick )( const Scheduler_Control *, Thread_Control * );
/** @see _Scheduler_Start_idle() */
void ( *start_idle )(
const Scheduler_Control *,
@@ -543,20 +540,6 @@ void _Scheduler_default_Cancel_job(
Thread_queue_Context *queue_context
);
/**
* @brief Performs tick operations depending on the CPU budget algorithm for
* each executing thread.
*
* This routine is invoked as part of processing each clock tick.
*
* @param scheduler The scheduler.
* @param[in, out] executing An executing thread.
*/
void _Scheduler_default_Tick(
const Scheduler_Control *scheduler,
Thread_Control *executing
);
/**
* @brief Starts an idle thread.
*
+2 -9
View File
@@ -67,7 +67,6 @@ extern "C" {
_Scheduler_default_Node_destroy, /* node destroy entry point */ \
_Scheduler_CBS_Release_job, /* new 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_DEFAULT_SET_AFFINITY_OPERATION \
}
@@ -394,15 +393,9 @@ int _Scheduler_CBS_Set_parameters (
);
/**
* @brief Invoked when a limited time quantum is exceeded.
*
* This routine is invoked when a limited time quantum is exceeded.
*
* @param the_thread The thread that exceeded a limited time quantum.
* @brief These are the CBS CPU budget operations.
*/
void _Scheduler_CBS_Budget_callout(
Thread_Control *the_thread
);
extern const Thread_CPU_budget_operations _Scheduler_CBS_Budget;
/**
* @brief Initializes a CBS specific scheduler node of @a the_thread.
@@ -66,7 +66,6 @@ extern "C" {
_Scheduler_default_Node_destroy, /* node destroy entry point */ \
_Scheduler_EDF_Release_job, /* new period of task */ \
_Scheduler_EDF_Cancel_job, /* cancel period of task */ \
_Scheduler_default_Tick, /* tick entry point */ \
_Scheduler_default_Start_idle /* start idle entry point */ \
SCHEDULER_DEFAULT_SET_AFFINITY_OPERATION \
}
@@ -128,7 +128,6 @@ typedef struct {
_Scheduler_default_Node_destroy, \
_Scheduler_EDF_Release_job, \
_Scheduler_EDF_Cancel_job, \
_Scheduler_default_Tick, \
_Scheduler_EDF_SMP_Start_idle, \
_Scheduler_EDF_SMP_Set_affinity \
}
@@ -599,44 +599,6 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Cancel_job(
);
}
/**
* @brief Scheduler method invoked at each clock tick.
*
* This method is invoked at each clock tick to allow the scheduler
* implementation to perform any activities required. For the
* scheduler which support standard RTEMS features, this includes
* time-slicing management.
*
* @param cpu The cpu control for the operation.
*/
RTEMS_INLINE_ROUTINE void _Scheduler_Tick( const Per_CPU_Control *cpu )
{
const Scheduler_Control *scheduler;
Thread_Control *executing;
scheduler = _Scheduler_Get_by_CPU( cpu );
#if defined(RTEMS_SMP)
if ( scheduler == NULL ) {
/*
* In SMP configurations, processors may be removed/added at runtime
* from/to a scheduler. There may be still clock interrupts on currently
* unassigned processors.
*/
return;
}
#endif
/*
* Each online processor has at least an idle thread as the executing thread
* even in case it has currently no scheduler assigned. Clock interrupts on
* processors which are not online would be a severe bug of the Clock Driver.
*/
executing = _Per_CPU_Get_executing( cpu );
_Assert( executing != NULL );
( *scheduler->Operations.tick )( scheduler, executing );
}
/**
* @brief Starts the idle thread for a particular processor.
*
@@ -57,7 +57,6 @@ extern "C" {
_Scheduler_default_Node_destroy, /* node destroy entry point */ \
_Scheduler_default_Release_job, /* new period of task */ \
_Scheduler_default_Cancel_job, /* cancel period of task */ \
_Scheduler_default_Tick, /* tick entry point */ \
_Scheduler_default_Start_idle /* start idle entry point */ \
SCHEDULER_DEFAULT_SET_AFFINITY_OPERATION \
}
@@ -73,7 +73,6 @@ extern "C" {
_Scheduler_default_Node_destroy, \
_Scheduler_default_Release_job, \
_Scheduler_default_Cancel_job, \
_Scheduler_default_Tick, \
_Scheduler_SMP_Start_idle, \
_Scheduler_priority_affinity_SMP_Set_affinity \
}
@@ -101,7 +101,6 @@ typedef struct {
_Scheduler_default_Node_destroy, \
_Scheduler_default_Release_job, \
_Scheduler_default_Cancel_job, \
_Scheduler_default_Tick, \
_Scheduler_SMP_Start_idle \
SCHEDULER_DEFAULT_SET_AFFINITY_OPERATION \
}
@@ -56,7 +56,6 @@ extern "C" {
_Scheduler_default_Node_destroy, /* node destroy entry point */ \
_Scheduler_default_Release_job, /* new period of task */ \
_Scheduler_default_Cancel_job, /* cancel period of task */ \
_Scheduler_default_Tick, /* tick entry point */ \
_Scheduler_default_Start_idle /* start idle entry point */ \
SCHEDULER_DEFAULT_SET_AFFINITY_OPERATION \
}
@@ -83,7 +83,6 @@ typedef struct {
_Scheduler_default_Node_destroy, \
_Scheduler_default_Release_job, \
_Scheduler_default_Cancel_job, \
_Scheduler_default_Tick, \
_Scheduler_SMP_Start_idle \
SCHEDULER_DEFAULT_SET_AFFINITY_OPERATION \
}
@@ -169,7 +169,6 @@ typedef struct {
_Scheduler_default_Node_destroy, \
_Scheduler_default_Release_job, \
_Scheduler_default_Cancel_job, \
_Scheduler_default_Tick, \
_Scheduler_strong_APA_Start_idle, \
_Scheduler_strong_APA_Set_affinity \
}
+49 -45
View File
@@ -76,14 +76,6 @@ extern "C" {
*@{
*/
#define RTEMS_SCORE_THREAD_ENABLE_EXHAUST_TIMESLICE
/*
* With the addition of the Constant Block Scheduler (CBS),
* this feature is needed even when POSIX is disabled.
*/
#define RTEMS_SCORE_THREAD_ENABLE_SCHEDULER_CALLOUT
#if defined(RTEMS_DEBUG)
#define RTEMS_SCORE_THREAD_ENABLE_RESOURCE_COUNT
#endif
@@ -148,27 +140,47 @@ typedef struct {
} Thread_Entry_information;
/**
* The following lists the algorithms used to manage the thread cpu budget.
*
* Reset Timeslice: At each context switch, reset the time quantum.
* Exhaust Timeslice: Only reset the quantum once it is consumed.
* Callout: Execute routine when budget is consumed.
* @brief This structure contains operations which manage the CPU budget of a
* thread.
*/
typedef enum {
THREAD_CPU_BUDGET_ALGORITHM_NONE,
THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE,
#if defined(RTEMS_SCORE_THREAD_ENABLE_EXHAUST_TIMESLICE)
THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE,
#endif
#if defined(RTEMS_SCORE_THREAD_ENABLE_SCHEDULER_CALLOUT)
THREAD_CPU_BUDGET_ALGORITHM_CALLOUT
#endif
} Thread_CPU_budget_algorithms;
typedef struct {
/**
* @brief This operation is called at each clock tick for the executing
* thread.
*/
void ( *at_tick )( Thread_Control * );
/** This defines thes the entry point for the thread specific timeslice
* budget management algorithm.
/**
* @brief This operation is called right before a context switch to the
* thread is performed.
*/
void ( *at_context_switch )( Thread_Control * );
/**
* @brief This operation is called to initialize the CPU budget of the
* thread.
*/
void ( *initialize )( Thread_Control * );
} Thread_CPU_budget_operations;
/**
* @brief This structure is used to control the CPU budget of a thread.
*/
typedef void (*Thread_CPU_budget_algorithm_callout )( Thread_Control * );
typedef struct {
/**
* @brief If this member is not NULL, then it references the CPU budget
* operations used to manage the CPU budget of the thread, otherwise it is
* NULL.
*/
const Thread_CPU_budget_operations *operations;
/**
* @brief This member contains the count of the time quantum that this thread
* is allowed to consume until an action takes place defined by the CPU
* budget operations.
*/
uint32_t available;
} Thread_CPU_budget_control;
/**
* The following structure contains the information which defines
@@ -182,12 +194,13 @@ typedef struct {
* it started.
*/
bool is_preemptible;
/** This field indicates the CPU budget algorith. */
Thread_CPU_budget_algorithms budget_algorithm;
/** This field is the routine to invoke when the CPU allotment is
* consumed.
/**
* @brief This member may provide the CPU budget operations activated when a
* thread is initialized before it is started or restarted.
*/
Thread_CPU_budget_algorithm_callout budget_callout;
const Thread_CPU_budget_operations *cpu_budget_operations;
/** This field is the initial ISR disable level of this thread. */
uint32_t isr_level;
/** This field is the initial priority. */
@@ -772,9 +785,7 @@ struct _Thread_Control {
* the following fields
*
* - RTEMS_API_Control::Signal,
* - Thread_Control::budget_algorithm,
* - Thread_Control::budget_callout,
* - Thread_Control::cpu_time_budget,
* - Thread_Control::CPU_budget,
* - Thread_Control::current_state,
* - Thread_Control::Post_switch_actions,
* - Thread_Control::Scheduler::control, and
@@ -841,18 +852,11 @@ struct _Thread_Control {
*/
bool was_created_with_inherited_scheduler;
/** This field is the length of the time quantum that this thread is
* allowed to consume. The algorithm used to manage limits on CPU usage
* is specified by budget_algorithm.
/**
* @brief This member contains the CPU budget control used to manage the CPU
* budget of the thread.
*/
uint32_t cpu_time_budget;
/** This field is the algorithm used to manage this thread's time
* quantum. The algorithm may be specified as none which case,
* no limit is in place.
*/
Thread_CPU_budget_algorithms budget_algorithm;
/** This field is the method invoked with the budgeted time is consumed. */
Thread_CPU_budget_algorithm_callout budget_callout;
Thread_CPU_budget_control CPU_budget;
/**
* @brief This member contains the amount of CPU time consumed by this thread
@@ -0,0 +1,102 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup RTEMSScoreThread
*
* @brief This header file provides interfaces used to implement the CPU budget
* management of threads.
*/
/*
* Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _RTEMS_SCORE_THREADCPUBUDGET_H
#define _RTEMS_SCORE_THREADCPUBUDGET_H
#include <rtems/score/thread.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup RTEMSScoreThread
*
* @{
*/
/**
* @brief Does nothing.
*
* @param the_thread is an unused parameter.
*/
void _Thread_CPU_budget_do_nothing( Thread_Control *the_thread );
/**
* @brief Sets the available CPU budget of the thread to the configured clock
* ticks per timeslice.
*
* @param the_thread is the thread to set the available CPU budget.
*/
void _Thread_CPU_budget_set_to_ticks_per_timeslice(
Thread_Control *the_thread
);
/**
* @brief Consumes one time quantum of the available CPU budget of the thread
* and yields the thread if the available CPU budget is fully consumed.
*
* While the thread enabled the non-preemptive mode or is not ready, no time
* quantum is consumed.
*
* @param the_thread is the thread to operate on.
*/
void _Thread_CPU_budget_consume_and_yield( Thread_Control *the_thread );
/**
* @brief These CPU budget operations allocate timeslices to the thread.
*
* The timeslice is not reset at a context switch to the thread. Once a
* timeslice is consumed, the thread yields.
*/
extern const Thread_CPU_budget_operations _Thread_CPU_budget_exhaust_timeslice;
/**
* @brief These CPU budget operations allocate timeslices to the thread.
*
* The timeslice is reset at a context switch to the thread. Once a timeslice
* is consumed, the thread yields.
*/
extern const Thread_CPU_budget_operations _Thread_CPU_budget_reset_timeslice;
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* _RTEMS_SCORE_THREADCPUBUDGET_H */
+2 -12
View File
@@ -176,19 +176,9 @@ typedef struct {
Priority_Control priority;
/**
* @brief The thread's budget algorithm.
* @brief The thread's initial CPU budget operations.
*/
Thread_CPU_budget_algorithms budget_algorithm;
/**
* @brief The thread's initial budget callout.
*/
Thread_CPU_budget_algorithm_callout budget_callout;
/**
* @brief The thread's initial CPU time budget.
*/
uint32_t cpu_time_budget;
const Thread_CPU_budget_operations *cpu_budget_operations;
/**
* @brief 32-bit unsigned integer name of the object for the thread.
+22 -22
View File
@@ -23,22 +23,27 @@
#include <errno.h>
#include <rtems/posix/pthreadimpl.h>
#include <rtems/score/threadcpubudget.h>
int _POSIX_Thread_Translate_to_sched_policy(
Thread_CPU_budget_algorithms budget_algorithm
const Thread_CPU_budget_operations *operations
)
{
switch ( budget_algorithm ) {
case THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE:
return SCHED_OTHER;
case THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE:
return SCHED_RR;
case THREAD_CPU_BUDGET_ALGORITHM_CALLOUT:
return SCHED_SPORADIC;
default:
_Assert( budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_NONE );
return SCHED_FIFO;
if ( operations == NULL ) {
return SCHED_FIFO;
}
if ( operations == &_Thread_CPU_budget_exhaust_timeslice ) {
return SCHED_RR;
}
#if defined(RTEMS_POSIX_API)
if ( operations == &_POSIX_Threads_Sporadic_budget ) {
return SCHED_SPORADIC;
}
#endif
return SCHED_OTHER;
}
int _POSIX_Thread_Translate_sched_param(
@@ -47,23 +52,19 @@ int _POSIX_Thread_Translate_sched_param(
Thread_Configuration *config
)
{
config->budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE;
config->budget_callout = NULL;
config->cpu_time_budget = 0;
config->cpu_budget_operations = NULL;
if ( policy == SCHED_OTHER ) {
config->budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE;
if ( policy == SCHED_FIFO ) {
return 0;
}
if ( policy == SCHED_FIFO ) {
config->budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE;
if ( policy == SCHED_OTHER ) {
config->cpu_budget_operations = &_Thread_CPU_budget_reset_timeslice;
return 0;
}
if ( policy == SCHED_RR ) {
config->budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE;
config->cpu_time_budget = rtems_configuration_get_ticks_per_timeslice();
config->cpu_budget_operations = &_Thread_CPU_budget_exhaust_timeslice;
return 0;
}
@@ -81,8 +82,7 @@ int _POSIX_Thread_Translate_sched_param(
_Timespec_To_ticks( &param->sched_ss_init_budget ) )
return EINVAL;
config->budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_CALLOUT;
config->budget_callout = _POSIX_Threads_Sporadic_budget_callout;
config->cpu_budget_operations = &_POSIX_Threads_Sporadic_budget;
return 0;
}
#endif
+34 -2
View File
@@ -34,9 +34,11 @@
#include <rtems/posix/pthreadimpl.h>
#include <rtems/posix/pthreadattrimpl.h>
#include <rtems/score/assert.h>
#include <rtems/score/threadcpubudget.h>
#include <rtems/score/threadimpl.h>
#include <rtems/score/apimutex.h>
#include <rtems/score/stackimpl.h>
#include <rtems/score/statesimpl.h>
#include <rtems/score/schedulerimpl.h>
#include <rtems/score/userextimpl.h>
#include <rtems/sysinit.h>
@@ -348,7 +350,9 @@ void _POSIX_Threads_Sporadic_timer( Watchdog_Control *watchdog )
_Thread_Priority_update( &queue_context );
}
void _POSIX_Threads_Sporadic_budget_callout( Thread_Control *the_thread )
static void _POSIX_Threads_Sporadic_budget_callout(
Thread_Control *the_thread
)
{
POSIX_API_Control *api;
Thread_queue_Context queue_context;
@@ -363,7 +367,7 @@ void _POSIX_Threads_Sporadic_budget_callout( Thread_Control *the_thread )
* This will prevent the thread from consuming its entire "budget"
* while at low priority.
*/
the_thread->cpu_time_budget = UINT32_MAX;
the_thread->CPU_budget.available = UINT32_MAX;
if ( !_Priority_Node_is_active( &api->Sporadic.Low_priority ) ) {
_Thread_Priority_add(
@@ -382,6 +386,34 @@ void _POSIX_Threads_Sporadic_budget_callout( Thread_Control *the_thread )
_Thread_Priority_update( &queue_context );
}
static void _POSIX_Threads_Sporadic_budget_at_tick( Thread_Control *the_thread )
{
uint32_t budget_available;
if ( !the_thread->is_preemptible ) {
return;
}
if ( !_States_Is_ready( the_thread->current_state ) ) {
return;
}
budget_available = the_thread->CPU_budget.available;
if ( budget_available == 1 ) {
the_thread->CPU_budget.available = 0;
_POSIX_Threads_Sporadic_budget_callout ( the_thread );
} else {
the_thread->CPU_budget.available = budget_available - 1;
}
}
const Thread_CPU_budget_operations _POSIX_Threads_Sporadic_budget = {
.at_tick = _POSIX_Threads_Sporadic_budget_at_tick,
.at_context_switch = _Thread_CPU_budget_do_nothing,
.initialize = _Thread_CPU_budget_do_nothing
};
static bool _POSIX_Threads_Create_extension(
Thread_Control *executing,
Thread_Control *created
+8 -8
View File
@@ -37,12 +37,12 @@ int pthread_getattr_np(
pthread_attr_t *attr
)
{
Thread_Control *the_thread;
ISR_lock_Context lock_context;
Thread_CPU_budget_algorithms budget_algorithm;
const Scheduler_Control *scheduler;
Priority_Control priority;
Status_Control status;
Thread_Control *the_thread;
ISR_lock_Context lock_context;
const Thread_CPU_budget_operations *cpu_budget_operations;
const Scheduler_Control *scheduler;
Priority_Control priority;
Status_Control status;
if ( attr == NULL ) {
return EINVAL;
@@ -89,7 +89,7 @@ int pthread_getattr_np(
attr->affinityset
);
budget_algorithm = the_thread->budget_algorithm;
cpu_budget_operations = the_thread->CPU_budget.operations;
_Thread_State_release( the_thread, &lock_context );
@@ -101,7 +101,7 @@ int pthread_getattr_np(
priority
);
attr->schedpolicy =
_POSIX_Thread_Translate_to_sched_policy( budget_algorithm );
_POSIX_Thread_Translate_to_sched_policy( cpu_budget_operations );
return _POSIX_Get_error( status );
}
+7 -7
View File
@@ -37,11 +37,11 @@ int pthread_getschedparam(
struct sched_param *param
)
{
Thread_Control *the_thread;
Thread_queue_Context queue_context;
Thread_CPU_budget_algorithms budget_algorithm;
const Scheduler_Control *scheduler;
Priority_Control priority;
Thread_Control *the_thread;
Thread_queue_Context queue_context;
const Thread_CPU_budget_operations *cpu_budget_operations;
const Scheduler_Control *scheduler;
Priority_Control priority;
if ( policy == NULL || param == NULL ) {
return EINVAL;
@@ -59,11 +59,11 @@ int pthread_getschedparam(
scheduler = _Thread_Scheduler_get_home( the_thread );
_POSIX_Threads_Get_sched_param_sporadic( the_thread, scheduler, param );
priority = the_thread->Real_priority.priority;
budget_algorithm = the_thread->budget_algorithm;
cpu_budget_operations = the_thread->CPU_budget.operations;
_Thread_Wait_release( the_thread, &queue_context );
param->sched_priority = _POSIX_Priority_From_core( scheduler, priority );
*policy = _POSIX_Thread_Translate_to_sched_policy( budget_algorithm );
*policy = _POSIX_Thread_Translate_to_sched_policy( cpu_budget_operations );
return 0;
}
+14 -10
View File
@@ -40,14 +40,15 @@ static int _POSIX_Set_sched_param(
Thread_queue_Context *queue_context
)
{
const Scheduler_Control *scheduler;
int normal_prio;
bool valid;
Priority_Control core_normal_prio;
const Scheduler_Control *scheduler;
int normal_prio;
bool valid;
Priority_Control core_normal_prio;
const Thread_CPU_budget_operations *cpu_budget_operations;
#if defined(RTEMS_POSIX_API)
POSIX_API_Control *api;
int low_prio;
Priority_Control core_low_prio;
POSIX_API_Control *api;
int low_prio;
Priority_Control core_low_prio;
#endif
normal_prio = param->sched_priority;
@@ -103,9 +104,12 @@ static int _POSIX_Set_sched_param(
}
#endif
the_thread->cpu_time_budget = config->cpu_time_budget;
the_thread->budget_algorithm = config->budget_algorithm;
the_thread->budget_callout = config->budget_callout;
cpu_budget_operations = config->cpu_budget_operations;
the_thread->CPU_budget.operations = cpu_budget_operations;
if ( cpu_budget_operations != NULL ) {
( *cpu_budget_operations->initialize )( the_thread );
}
#if defined(RTEMS_POSIX_API)
_Priority_Node_set_priority( &api->Sporadic.Low_priority, core_low_prio );
+11 -14
View File
@@ -35,16 +35,15 @@ static void _Signal_Action_handler(
ISR_lock_Context *lock_context
)
{
RTEMS_API_Control *api;
ASR_Information *asr;
rtems_signal_set signal_set;
bool normal_is_preemptible;
uint32_t normal_cpu_time_budget;
Thread_CPU_budget_algorithms normal_budget_algorithm;
uint32_t normal_isr_level;
uint32_t before_call_isr_level;
bool after_call_is_preemptible;
bool after_call_asr_is_enabled;
RTEMS_API_Control *api;
ASR_Information *asr;
rtems_signal_set signal_set;
bool normal_is_preemptible;
Thread_CPU_budget_control normal_cpu_budget;
uint32_t normal_isr_level;
uint32_t before_call_isr_level;
bool after_call_is_preemptible;
bool after_call_asr_is_enabled;
(void) action;
@@ -69,8 +68,7 @@ static void _Signal_Action_handler(
_Assert( asr->is_enabled );
normal_is_preemptible = executing->is_preemptible;
normal_cpu_time_budget = executing->cpu_time_budget;
normal_budget_algorithm = executing->budget_algorithm;
normal_cpu_budget = executing->CPU_budget;
/* Set mode for ASR processing */
@@ -102,8 +100,7 @@ static void _Signal_Action_handler(
_Thread_State_acquire( executing, lock_context );
executing->cpu_time_budget = normal_cpu_time_budget ;
executing->budget_algorithm = normal_budget_algorithm ;
executing->CPU_budget = normal_cpu_budget;
after_call_is_preemptible = executing->is_preemptible;
executing->is_preemptible = normal_is_preemptible;
+6 -3
View File
@@ -154,14 +154,17 @@ rtems_status_code _RTEMS_tasks_Create(
attributes = _Attributes_Clear( attributes, ATTRIBUTES_NOT_SUPPORTED );
memset( &thread_config, 0, sizeof( thread_config ) );
thread_config.budget_algorithm = _Modes_Is_timeslice( config->initial_modes ) ?
THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE
: THREAD_CPU_BUDGET_ALGORITHM_NONE,
thread_config.isr_level = _Modes_Get_interrupt_level( config->initial_modes );
thread_config.name = config->name;
thread_config.is_fp = _Attributes_Is_floating_point( attributes );
thread_config.is_preemptible = _Modes_Is_preempt( config->initial_modes );
if ( _Modes_Is_timeslice( config->initial_modes ) ) {
thread_config.cpu_budget_operations = &_Thread_CPU_budget_reset_timeslice;
} else {
thread_config.cpu_budget_operations = NULL;
}
/*
* Validate the RTEMS API priority and convert it to the core priority range.
*/
+1 -1
View File
@@ -73,7 +73,7 @@ rtems_status_code rtems_task_mode(
old_mode = (executing->is_preemptible) ? RTEMS_PREEMPT : RTEMS_NO_PREEMPT;
if ( executing->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_NONE )
if ( executing->CPU_budget.operations == NULL )
old_mode |= RTEMS_NO_TIMESLICE;
else
old_mode |= RTEMS_TIMESLICE;
-1
View File
@@ -144,7 +144,6 @@ static void _MPCI_Create_server( void )
config.scheduler = &_Scheduler_Table[ 0 ];
config.name = _Objects_Build_name( 'M', 'P', 'C', 'I' );
config.priority = PRIORITY_PSEUDO_ISR;
config.budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE;
config.is_fp = CPU_ALL_TASKS_ARE_FP;
config.stack_size = _Stack_Minimum()
+ _MPCI_Configuration.extra_mpci_receive_server_stack
+38 -3
View File
@@ -21,10 +21,17 @@
#endif
#include <rtems/score/schedulercbsimpl.h>
#include <rtems/score/statesimpl.h>
#include <rtems/score/threadcpubudget.h>
void _Scheduler_CBS_Budget_callout(
Thread_Control *the_thread
)
/**
* @brief Invoked when a limited time quantum is exceeded.
*
* This routine is invoked when a limited time quantum is exceeded.
*
* @param the_thread The thread that exceeded a limited time quantum.
*/
static void _Scheduler_CBS_Budget_callout( Thread_Control *the_thread )
{
Scheduler_CBS_Node *node;
Scheduler_CBS_Server_id server_id;
@@ -52,6 +59,34 @@ void _Scheduler_CBS_Budget_callout(
}
}
static void _Scheduler_CBS_Budget_at_tick( Thread_Control *the_thread )
{
uint32_t budget_available;
if ( !the_thread->is_preemptible ) {
return;
}
if ( !_States_Is_ready( the_thread->current_state ) ) {
return;
}
budget_available = the_thread->CPU_budget.available;
if ( budget_available == 1 ) {
the_thread->CPU_budget.available = 0;
_Scheduler_CBS_Budget_callout ( the_thread );
} else {
the_thread->CPU_budget.available = budget_available - 1;
}
}
const Thread_CPU_budget_operations _Scheduler_CBS_Budget = {
.at_tick = _Scheduler_CBS_Budget_at_tick,
.at_context_switch = _Thread_CPU_budget_do_nothing,
.initialize = _Thread_CPU_budget_do_nothing
};
int _Scheduler_CBS_Initialize(void)
{
return SCHEDULER_CBS_OK;
+2 -3
View File
@@ -64,9 +64,8 @@ int _Scheduler_CBS_Attach_thread (
server->task_id = task_id;
the_thread->budget_callout = _Scheduler_CBS_Budget_callout;
the_thread->budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_CALLOUT;
the_thread->is_preemptible = true;
the_thread->is_preemptible = true;
the_thread->CPU_budget.operations = &_Scheduler_CBS_Budget;
_ISR_lock_ISR_enable( &lock_context );
return SCHEDULER_CBS_OK;
+13 -7
View File
@@ -28,10 +28,11 @@ int _Scheduler_CBS_Detach_thread (
rtems_id task_id
)
{
Scheduler_CBS_Server *server;
ISR_lock_Context lock_context;
Thread_Control *the_thread;
Scheduler_CBS_Node *node;
Scheduler_CBS_Server *server;
ISR_lock_Context lock_context;
Thread_Control *the_thread;
Scheduler_CBS_Node *node;
const Thread_CPU_budget_operations *cpu_budget_operations;
if ( server_id >= _Scheduler_CBS_Maximum_servers ) {
return SCHEDULER_CBS_ERROR_INVALID_PARAMETER;
@@ -58,9 +59,14 @@ int _Scheduler_CBS_Detach_thread (
server->task_id = -1;
the_thread->budget_algorithm = the_thread->Start.budget_algorithm;
the_thread->budget_callout = the_thread->Start.budget_callout;
the_thread->is_preemptible = the_thread->Start.is_preemptible;
the_thread->is_preemptible = the_thread->Start.is_preemptible;
cpu_budget_operations = the_thread->Start.cpu_budget_operations;
the_thread->CPU_budget.operations = cpu_budget_operations;
if ( cpu_budget_operations != NULL ) {
( *cpu_budget_operations->initialize )( the_thread );
}
_ISR_lock_ISR_enable( &lock_context );
return SCHEDULER_CBS_OK;
@@ -51,7 +51,7 @@ int _Scheduler_CBS_Get_execution_time (
the_thread = _Thread_Get( server->task_id, &lock_context );
if ( the_thread != NULL ) {
*exec_time = server->parameters.budget - the_thread->cpu_time_budget;
*exec_time = server->parameters.budget - the_thread->CPU_budget.available;
_ISR_lock_ISR_enable( &lock_context );
} else {
*exec_time = server->parameters.budget;
@@ -50,7 +50,7 @@ int _Scheduler_CBS_Get_remaining_budget (
the_thread = _Thread_Get( server->task_id, &lock_context );
if ( the_thread != NULL ) {
*remaining_budget = the_thread->cpu_time_budget;
*remaining_budget = the_thread->CPU_budget.available;
_ISR_lock_ISR_enable( &lock_context );
} else {
*remaining_budget = 0;
+1 -1
View File
@@ -38,7 +38,7 @@ void _Scheduler_CBS_Release_job(
/* Budget replenishment for the next job. */
if ( serv_info != NULL ) {
the_thread->cpu_time_budget = serv_info->parameters.budget;
the_thread->CPU_budget.available = serv_info->parameters.budget;
}
node->deadline_node = priority_node;
+1 -1
View File
@@ -50,7 +50,7 @@ void _Scheduler_CBS_Unblock(
if ( serv_info != NULL && ( priority & SCHEDULER_EDF_PRIO_MSB ) == 0 ) {
time_t deadline = serv_info->parameters.deadline;
time_t budget = serv_info->parameters.budget;
uint32_t deadline_left = the_thread->cpu_time_budget;
uint32_t deadline_left = the_thread->CPU_budget.available;
Priority_Control budget_left = priority - _Watchdog_Ticks_since_boot;
if ( deadline * budget_left > budget * deadline_left ) {
-81
View File
@@ -1,81 +0,0 @@
/**
* @file
*
* @ingroup RTEMSScoreScheduler
*
* @brief This source file contains the implementation of
* _Scheduler_default_Tick().
*/
/*
* COPYRIGHT (c) 1989-2009.
* On-Line Applications Research Corporation (OAR).
*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems/score/schedulerimpl.h>
#include <rtems/score/threadimpl.h>
#include <rtems/score/smp.h>
#include <rtems/config.h>
void _Scheduler_default_Tick(
const Scheduler_Control *scheduler,
Thread_Control *executing
)
{
(void) scheduler;
/*
* If the thread is not preemptible or is not ready, then
* just return.
*/
if ( !executing->is_preemptible )
return;
if ( !_States_Is_ready( executing->current_state ) )
return;
/*
* The cpu budget algorithm determines what happens next.
*/
switch ( executing->budget_algorithm ) {
case THREAD_CPU_BUDGET_ALGORITHM_NONE:
break;
case THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE:
#if defined(RTEMS_SCORE_THREAD_ENABLE_EXHAUST_TIMESLICE)
case THREAD_CPU_BUDGET_ALGORITHM_EXHAUST_TIMESLICE:
#endif
if ( (int)(--executing->cpu_time_budget) <= 0 ) {
/*
* A yield performs the ready chain mechanics needed when
* resetting a timeslice. If no other thread's are ready
* at the priority of the currently executing thread, then the
* executing thread's timeslice is reset. Otherwise, the
* currently executing thread is placed at the rear of the
* FIFO for this priority and a new heir is selected.
*/
_Thread_Yield( executing );
executing->cpu_time_budget =
rtems_configuration_get_ticks_per_timeslice();
}
break;
#if defined(RTEMS_SCORE_THREAD_ENABLE_SCHEDULER_CALLOUT)
case THREAD_CPU_BUDGET_ALGORITHM_CALLOUT:
if ( --executing->cpu_time_budget == 0 )
(*executing->budget_callout)( executing );
break;
#endif
}
}
-1
View File
@@ -43,7 +43,6 @@ static void _Thread_Create_idle_for_CPU( Per_CPU_Control *cpu )
config.scheduler,
config.scheduler->maximum_priority
);
config.budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE;
config.name = _Objects_Build_name( 'I', 'D', 'L', 'E' );
config.is_fp = CPU_IDLE_TASK_IS_FP;
config.is_preemptible = true;
+8 -3
View File
@@ -275,7 +275,8 @@ void _Thread_Do_dispatch( Per_CPU_Control *cpu_self, ISR_Level level )
executing = cpu_self->executing;
do {
Thread_Control *heir;
Thread_Control *heir;
const Thread_CPU_budget_operations *cpu_budget_operations;
level = _Thread_Preemption_intervention( executing, cpu_self, level );
heir = _Thread_Get_heir_and_make_it_executing( cpu_self );
@@ -292,8 +293,12 @@ void _Thread_Do_dispatch( Per_CPU_Control *cpu_self, ISR_Level level )
* Since heir and executing are not the same, we need to do a real
* context switch.
*/
if ( heir->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE )
heir->cpu_time_budget = rtems_configuration_get_ticks_per_timeslice();
cpu_budget_operations = heir->CPU_budget.operations;
if ( cpu_budget_operations != NULL ) {
( *cpu_budget_operations->at_context_switch )( heir );
}
_ISR_Local_enable( level );
+53
View File
@@ -0,0 +1,53 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup RTEMSScoreThread
*
* @brief This source file contains the definition of
* ::_Thread_CPU_budget_exhaust_timeslice and the implementation of
* _Thread_CPU_budget_do_nothing().
*/
/*
* Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems/score/threadcpubudget.h>
void _Thread_CPU_budget_do_nothing( Thread_Control *the_thread )
{
(void) the_thread;
}
const Thread_CPU_budget_operations _Thread_CPU_budget_exhaust_timeslice = {
.at_tick = _Thread_CPU_budget_consume_and_yield,
.at_context_switch = _Thread_CPU_budget_do_nothing,
.initialize = _Thread_CPU_budget_set_to_ticks_per_timeslice
};
+5 -7
View File
@@ -274,13 +274,11 @@ static bool _Thread_Try_initialize(
* General initialization
*/
the_thread->is_fp = config->is_fp;
the_thread->cpu_time_budget = config->cpu_time_budget;
the_thread->Start.isr_level = config->isr_level;
the_thread->Start.is_preemptible = config->is_preemptible;
the_thread->Start.budget_algorithm = config->budget_algorithm;
the_thread->Start.budget_callout = config->budget_callout;
the_thread->Start.stack_free = config->stack_free;
the_thread->is_fp = config->is_fp;
the_thread->Start.isr_level = config->isr_level;
the_thread->Start.is_preemptible = config->is_preemptible;
the_thread->Start.cpu_budget_operations = config->cpu_budget_operations;
the_thread->Start.stack_free = config->stack_free;
_Thread_Timer_initialize( &the_thread->Timer, cpu );
_Thread_Initialize_scheduler_and_wait_nodes( the_thread, config );
+9 -2
View File
@@ -26,6 +26,8 @@ void _Thread_Load_environment(
Thread_Control *the_thread
)
{
const Thread_CPU_budget_operations *cpu_budget_operations;
#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
if ( the_thread->Start.fp_context ) {
the_thread->fp_context = the_thread->Start.fp_context;
@@ -34,8 +36,13 @@ void _Thread_Load_environment(
#endif
the_thread->is_preemptible = the_thread->Start.is_preemptible;
the_thread->budget_algorithm = the_thread->Start.budget_algorithm;
the_thread->budget_callout = the_thread->Start.budget_callout;
cpu_budget_operations = the_thread->Start.cpu_budget_operations;
the_thread->CPU_budget.operations = cpu_budget_operations;
if ( cpu_budget_operations != NULL ) {
( *cpu_budget_operations->initialize )( the_thread );
}
_Context_Initialize(
&the_thread->Registers,
+91
View File
@@ -0,0 +1,91 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup RTEMSScoreThread
*
* @brief This source file contains the definition of
* ::_Thread_CPU_budget_reset_timeslice and the implementation of
* _Thread_CPU_budget_consume_and_yield() and
* _Thread_CPU_budget_set_to_ticks_per_timeslice().
*/
/*
* Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
* Copyright (C) 2010 Gedare Bloom <gedare@rtems.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems/score/threadcpubudget.h>
#include <rtems/score/threadimpl.h>
#include <rtems/score/statesimpl.h>
#include <rtems/score/watchdogticks.h>
void _Thread_CPU_budget_consume_and_yield( Thread_Control *the_thread )
{
uint32_t budget_available;
if ( !the_thread->is_preemptible ) {
return;
}
if ( !_States_Is_ready( the_thread->current_state ) ) {
return;
}
budget_available = the_thread->CPU_budget.available;
if ( budget_available == 1 ) {
the_thread->CPU_budget.available = _Watchdog_Ticks_per_timeslice;
/*
* A yield performs the ready chain mechanics needed when
* resetting a timeslice. If no other thread's are ready
* at the priority of the currently executing thread, then the
* executing thread's timeslice is reset. Otherwise, the
* currently executing thread is placed at the rear of the
* FIFO for this priority and a new heir is selected.
*/
_Thread_Yield( the_thread );
} else {
the_thread->CPU_budget.available = budget_available - 1;
}
}
void _Thread_CPU_budget_set_to_ticks_per_timeslice(
Thread_Control *the_thread
)
{
the_thread->CPU_budget.available = _Watchdog_Ticks_per_timeslice;
}
const Thread_CPU_budget_operations _Thread_CPU_budget_reset_timeslice = {
.at_tick = _Thread_CPU_budget_consume_and_yield,
.at_context_switch = _Thread_CPU_budget_set_to_ticks_per_timeslice,
.initialize = _Thread_CPU_budget_set_to_ticks_per_timeslice
};
-4
View File
@@ -217,10 +217,6 @@ static Thread_Life_state _Thread_Change_life_locked(
_Thread_Is_life_change_allowed( state )
&& _Thread_Is_life_changing( state )
) {
the_thread->is_preemptible = the_thread->Start.is_preemptible;
the_thread->budget_algorithm = the_thread->Start.budget_algorithm;
the_thread->budget_callout = the_thread->Start.budget_callout;
_Thread_Add_post_switch_action(
the_thread,
&the_thread->Life.Action,
+19 -6
View File
@@ -62,11 +62,13 @@ void _Watchdog_Do_tickle(
void _Watchdog_Tick( Per_CPU_Control *cpu )
{
ISR_lock_Context lock_context;
Watchdog_Header *header;
Watchdog_Control *first;
uint64_t ticks;
struct timespec now;
ISR_lock_Context lock_context;
Watchdog_Header *header;
Watchdog_Control *first;
uint64_t ticks;
struct timespec now;
Thread_Control *executing;
const Thread_CPU_budget_operations *cpu_budget_operations;
if ( _Per_CPU_Is_boot_processor( cpu ) ) {
++_Watchdog_Ticks_since_boot;
@@ -122,5 +124,16 @@ void _Watchdog_Tick( Per_CPU_Control *cpu )
_ISR_lock_Release_and_ISR_enable( &cpu->Watchdog.Lock, &lock_context );
_Scheduler_Tick( cpu );
/*
* Each online processor has at least an idle thread as the executing thread
* even in case it has currently no scheduler assigned. Clock interrupts on
* processors which are not online would be a severe bug of the Clock Driver.
*/
executing = _Per_CPU_Get_executing( cpu );
_Assert( executing != NULL );
cpu_budget_operations = executing->CPU_budget.operations;
if ( cpu_budget_operations != NULL ) {
( *cpu_budget_operations->at_tick )( executing );
}
}
+3 -1
View File
@@ -413,6 +413,7 @@ install:
- cpukit/include/rtems/score/status.h
- cpukit/include/rtems/score/sysstate.h
- cpukit/include/rtems/score/thread.h
- cpukit/include/rtems/score/threadcpubudget.h
- cpukit/include/rtems/score/threaddispatch.h
- cpukit/include/rtems/score/threadidledata.h
- cpukit/include/rtems/score/threadimpl.h
@@ -1506,7 +1507,6 @@ source:
- cpukit/score/src/schedulerdefaultreleasejob.c
- cpukit/score/src/schedulerdefaultschedule.c
- cpukit/score/src/schedulerdefaultstartidle.c
- cpukit/score/src/schedulerdefaulttick.c
- cpukit/score/src/scheduleredf.c
- cpukit/score/src/scheduleredfblock.c
- cpukit/score/src/scheduleredfchangepriority.c
@@ -1544,6 +1544,7 @@ source:
- cpukit/score/src/threadentryadaptoridle.c
- cpukit/score/src/threadentryadaptornumeric.c
- cpukit/score/src/threadentryadaptorpointer.c
- cpukit/score/src/threadexhausttimeslice.c
- cpukit/score/src/threadget.c
- cpukit/score/src/threadgetcputimeused.c
- cpukit/score/src/threadgetcputimeusedafterreset.c
@@ -1562,6 +1563,7 @@ source:
- cpukit/score/src/threadqgetnameandid.c
- cpukit/score/src/threadqops.c
- cpukit/score/src/threadqtimeout.c
- cpukit/score/src/threadresettimeslice.c
- cpukit/score/src/threadrestart.c
- cpukit/score/src/threadscheduler.c
- cpukit/score/src/threadselfid.c
@@ -23,6 +23,7 @@
#include <bsp/bootcard.h>
#include <rtems/score/timecounterimpl.h>
#include <rtems/score/percpu.h>
#include <rtems/score/todimpl.h>
#include <rtems/timecounter.h>
#include <rtems/bsd.h>
@@ -42,6 +43,8 @@ typedef struct {
static test_context test_instance;
static Thread_Control executing;
static uint32_t test_get_timecount(struct timecounter *tc)
{
test_context *ctx;
@@ -106,12 +109,17 @@ void boot_card(const char *cmdline)
struct bintime bt;
struct timeval tv;
struct timespec ts;
Per_CPU_Control *cpu_self;
ctx = &test_instance;
tc = &ctx->tc;
TEST_BEGIN();
cpu_self = _Per_CPU_Get();
cpu_self->executing = &executing;
cpu_self->heir = &executing;
assert(time(NULL) == TOD_SECONDS_1970_THROUGH_1988);
rtems_bsd_bintime(&bt);