diff options
Diffstat (limited to 'cpukit')
41 files changed, 509 insertions, 332 deletions
diff --git a/cpukit/include/rtems/posix/pthreadimpl.h b/cpukit/include/rtems/posix/pthreadimpl.h index 723b20e8d2..0dc7d9dac5 100644 --- a/cpukit/include/rtems/posix/pthreadimpl.h +++ b/cpukit/include/rtems/posix/pthreadimpl.h @@ -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 ); /** diff --git a/cpukit/include/rtems/rtems/modesimpl.h b/cpukit/include/rtems/rtems/modesimpl.h index 924e12fbee..8fdab263f1 100644 --- a/cpukit/include/rtems/rtems/modesimpl.h +++ b/cpukit/include/rtems/rtems/modesimpl.h @@ -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; } } diff --git a/cpukit/include/rtems/score/scheduler.h b/cpukit/include/rtems/score/scheduler.h index df9477fbeb..ad9d630023 100644 --- a/cpukit/include/rtems/score/scheduler.h +++ b/cpukit/include/rtems/score/scheduler.h @@ -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 *, @@ -544,20 +541,6 @@ void _Scheduler_default_Cancel_job( ); /** - * @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. * * @param scheduler This parameter is unused. diff --git a/cpukit/include/rtems/score/schedulercbs.h b/cpukit/include/rtems/score/schedulercbs.h index 4b7efc8340..8a9a49ccd9 100644 --- a/cpukit/include/rtems/score/schedulercbs.h +++ b/cpukit/include/rtems/score/schedulercbs.h @@ -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. diff --git a/cpukit/include/rtems/score/scheduleredf.h b/cpukit/include/rtems/score/scheduleredf.h index 9e643b93eb..258563217f 100644 --- a/cpukit/include/rtems/score/scheduleredf.h +++ b/cpukit/include/rtems/score/scheduleredf.h @@ -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 \ } diff --git a/cpukit/include/rtems/score/scheduleredfsmp.h b/cpukit/include/rtems/score/scheduleredfsmp.h index 1841aa4a7b..85e438e81d 100644 --- a/cpukit/include/rtems/score/scheduleredfsmp.h +++ b/cpukit/include/rtems/score/scheduleredfsmp.h @@ -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 \ } diff --git a/cpukit/include/rtems/score/schedulerimpl.h b/cpukit/include/rtems/score/schedulerimpl.h index 50110ea6e7..2c53c05056 100644 --- a/cpukit/include/rtems/score/schedulerimpl.h +++ b/cpukit/include/rtems/score/schedulerimpl.h @@ -600,44 +600,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. * * @param scheduler The scheduler instance. diff --git a/cpukit/include/rtems/score/schedulerpriority.h b/cpukit/include/rtems/score/schedulerpriority.h index e0991f5e31..1ddbb4a8cc 100644 --- a/cpukit/include/rtems/score/schedulerpriority.h +++ b/cpukit/include/rtems/score/schedulerpriority.h @@ -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 \ } diff --git a/cpukit/include/rtems/score/schedulerpriorityaffinitysmp.h b/cpukit/include/rtems/score/schedulerpriorityaffinitysmp.h index 1b660fa296..e997e81128 100644 --- a/cpukit/include/rtems/score/schedulerpriorityaffinitysmp.h +++ b/cpukit/include/rtems/score/schedulerpriorityaffinitysmp.h @@ -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 \ } diff --git a/cpukit/include/rtems/score/schedulerprioritysmp.h b/cpukit/include/rtems/score/schedulerprioritysmp.h index 56f4aa5a5b..fe314fb05b 100644 --- a/cpukit/include/rtems/score/schedulerprioritysmp.h +++ b/cpukit/include/rtems/score/schedulerprioritysmp.h @@ -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 \ } diff --git a/cpukit/include/rtems/score/schedulersimple.h b/cpukit/include/rtems/score/schedulersimple.h index 63310e9796..15471a6498 100644 --- a/cpukit/include/rtems/score/schedulersimple.h +++ b/cpukit/include/rtems/score/schedulersimple.h @@ -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 \ } diff --git a/cpukit/include/rtems/score/schedulersimplesmp.h b/cpukit/include/rtems/score/schedulersimplesmp.h index 961e60ae73..c8394781c9 100644 --- a/cpukit/include/rtems/score/schedulersimplesmp.h +++ b/cpukit/include/rtems/score/schedulersimplesmp.h @@ -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 \ } diff --git a/cpukit/include/rtems/score/schedulerstrongapa.h b/cpukit/include/rtems/score/schedulerstrongapa.h index a3a19d80c1..bbded1b493 100644 --- a/cpukit/include/rtems/score/schedulerstrongapa.h +++ b/cpukit/include/rtems/score/schedulerstrongapa.h @@ -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 \ } diff --git a/cpukit/include/rtems/score/thread.h b/cpukit/include/rtems/score/thread.h index aff2f58d77..4c8a97c0f7 100644 --- a/cpukit/include/rtems/score/thread.h +++ b/cpukit/include/rtems/score/thread.h @@ -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. - */ - 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. + /** + * @brief This member contains the CPU budget control used to manage the CPU + * budget of the thread. */ - 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 diff --git a/cpukit/include/rtems/score/threadcpubudget.h b/cpukit/include/rtems/score/threadcpubudget.h new file mode 100644 index 0000000000..bcbaa11bdb --- /dev/null +++ b/cpukit/include/rtems/score/threadcpubudget.h @@ -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 */ diff --git a/cpukit/include/rtems/score/threadimpl.h b/cpukit/include/rtems/score/threadimpl.h index a983975568..b1ec05f1c4 100644 --- a/cpukit/include/rtems/score/threadimpl.h +++ b/cpukit/include/rtems/score/threadimpl.h @@ -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. diff --git a/cpukit/posix/src/psxtransschedparam.c b/cpukit/posix/src/psxtransschedparam.c index eba26d4932..f97924e011 100644 --- a/cpukit/posix/src/psxtransschedparam.c +++ b/cpukit/posix/src/psxtransschedparam.c @@ -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( ¶m->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 diff --git a/cpukit/posix/src/pthreadcreate.c b/cpukit/posix/src/pthreadcreate.c index 9474d07032..093ad5cfe1 100644 --- a/cpukit/posix/src/pthreadcreate.c +++ b/cpukit/posix/src/pthreadcreate.c @@ -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 diff --git a/cpukit/posix/src/pthreadgetattrnp.c b/cpukit/posix/src/pthreadgetattrnp.c index 5572fb98a5..aa34185264 100644 --- a/cpukit/posix/src/pthreadgetattrnp.c +++ b/cpukit/posix/src/pthreadgetattrnp.c @@ -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 ); } diff --git a/cpukit/posix/src/pthreadgetschedparam.c b/cpukit/posix/src/pthreadgetschedparam.c index a82d79c715..406ae8e7bb 100644 --- a/cpukit/posix/src/pthreadgetschedparam.c +++ b/cpukit/posix/src/pthreadgetschedparam.c @@ -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; } diff --git a/cpukit/posix/src/pthreadsetschedparam.c b/cpukit/posix/src/pthreadsetschedparam.c index 1c207e7887..165e1d86a8 100644 --- a/cpukit/posix/src/pthreadsetschedparam.c +++ b/cpukit/posix/src/pthreadsetschedparam.c @@ -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 ); diff --git a/cpukit/rtems/src/signalsend.c b/cpukit/rtems/src/signalsend.c index 72407e2b01..6ce59f2e74 100644 --- a/cpukit/rtems/src/signalsend.c +++ b/cpukit/rtems/src/signalsend.c @@ -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; diff --git a/cpukit/rtems/src/taskconstruct.c b/cpukit/rtems/src/taskconstruct.c index 6e03440aed..05fbf32ff5 100644 --- a/cpukit/rtems/src/taskconstruct.c +++ b/cpukit/rtems/src/taskconstruct.c @@ -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. */ diff --git a/cpukit/rtems/src/taskmode.c b/cpukit/rtems/src/taskmode.c index 96bed470f4..3300eafa28 100644 --- a/cpukit/rtems/src/taskmode.c +++ b/cpukit/rtems/src/taskmode.c @@ -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; diff --git a/cpukit/score/src/mpci.c b/cpukit/score/src/mpci.c index cb306c9763..63a7eb13ef 100644 --- a/cpukit/score/src/mpci.c +++ b/cpukit/score/src/mpci.c @@ -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 diff --git a/cpukit/score/src/schedulercbs.c b/cpukit/score/src/schedulercbs.c index 8e5bf86f27..bedaf8e1da 100644 --- a/cpukit/score/src/schedulercbs.c +++ b/cpukit/score/src/schedulercbs.c @@ -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; diff --git a/cpukit/score/src/schedulercbsattachthread.c b/cpukit/score/src/schedulercbsattachthread.c index 0cb59fa2e8..d6c5b3b9eb 100644 --- a/cpukit/score/src/schedulercbsattachthread.c +++ b/cpukit/score/src/schedulercbsattachthread.c @@ -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; diff --git a/cpukit/score/src/schedulercbsdetachthread.c b/cpukit/score/src/schedulercbsdetachthread.c index 687b37804f..5aa5eeb7a2 100644 --- a/cpukit/score/src/schedulercbsdetachthread.c +++ b/cpukit/score/src/schedulercbsdetachthread.c @@ -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; diff --git a/cpukit/score/src/schedulercbsgetexecutiontime.c b/cpukit/score/src/schedulercbsgetexecutiontime.c index 28709151c0..c8e999a788 100644 --- a/cpukit/score/src/schedulercbsgetexecutiontime.c +++ b/cpukit/score/src/schedulercbsgetexecutiontime.c @@ -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; diff --git a/cpukit/score/src/schedulercbsgetremainingbudget.c b/cpukit/score/src/schedulercbsgetremainingbudget.c index 5cb299d67e..338fd56190 100644 --- a/cpukit/score/src/schedulercbsgetremainingbudget.c +++ b/cpukit/score/src/schedulercbsgetremainingbudget.c @@ -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; diff --git a/cpukit/score/src/schedulercbsreleasejob.c b/cpukit/score/src/schedulercbsreleasejob.c index 376906b996..27ca33ad56 100644 --- a/cpukit/score/src/schedulercbsreleasejob.c +++ b/cpukit/score/src/schedulercbsreleasejob.c @@ -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; diff --git a/cpukit/score/src/schedulercbsunblock.c b/cpukit/score/src/schedulercbsunblock.c index 700d7b1202..ca985150fb 100644 --- a/cpukit/score/src/schedulercbsunblock.c +++ b/cpukit/score/src/schedulercbsunblock.c @@ -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 ) { diff --git a/cpukit/score/src/schedulerdefaulttick.c b/cpukit/score/src/schedulerdefaulttick.c deleted file mode 100644 index f4b6ba8578..0000000000 --- a/cpukit/score/src/schedulerdefaulttick.c +++ /dev/null @@ -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 - } -} diff --git a/cpukit/score/src/threadcreateidle.c b/cpukit/score/src/threadcreateidle.c index 86e117e70f..83d9bdcd8d 100644 --- a/cpukit/score/src/threadcreateidle.c +++ b/cpukit/score/src/threadcreateidle.c @@ -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; diff --git a/cpukit/score/src/threaddispatch.c b/cpukit/score/src/threaddispatch.c index 1d317ad2b1..a53c8de2b0 100644 --- a/cpukit/score/src/threaddispatch.c +++ b/cpukit/score/src/threaddispatch.c @@ -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 ); diff --git a/cpukit/score/src/threadexhausttimeslice.c b/cpukit/score/src/threadexhausttimeslice.c new file mode 100644 index 0000000000..f3f6924e44 --- /dev/null +++ b/cpukit/score/src/threadexhausttimeslice.c @@ -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 +}; diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c index 81199a7044..01ef479537 100644 --- a/cpukit/score/src/threadinitialize.c +++ b/cpukit/score/src/threadinitialize.c @@ -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 ); diff --git a/cpukit/score/src/threadloadenv.c b/cpukit/score/src/threadloadenv.c index fec2a616d8..49317421b3 100644 --- a/cpukit/score/src/threadloadenv.c +++ b/cpukit/score/src/threadloadenv.c @@ -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, diff --git a/cpukit/score/src/threadresettimeslice.c b/cpukit/score/src/threadresettimeslice.c new file mode 100644 index 0000000000..ed4d6fb3e3 --- /dev/null +++ b/cpukit/score/src/threadresettimeslice.c @@ -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 +}; diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c index 2240d8f713..15e141b51e 100644 --- a/cpukit/score/src/threadrestart.c +++ b/cpukit/score/src/threadrestart.c @@ -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, diff --git a/cpukit/score/src/watchdogtick.c b/cpukit/score/src/watchdogtick.c index e77ca4e1e1..aa2efc3626 100644 --- a/cpukit/score/src/watchdogtick.c +++ b/cpukit/score/src/watchdogtick.c @@ -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 ); + } } |