Three additional functions: RM_Postponed_num, RM_Renew_deadline, and RM_Release_postponedjob.
Four refined functions: RM_Activate, RM_Block_while_expired, rtems_rate_monotonic_period, RM_Timeout. Rate_monotonic_Control contains one counter for counting the postponed jobs and one for recording the recent deadline. --- cpukit/rtems/include/rtems/rtems/ratemon.h | 42 ++++++-- cpukit/rtems/include/rtems/rtems/ratemonimpl.h | 25 +++-- cpukit/rtems/src/ratemonperiod.c | 144 +++++++++++++++++++++---- cpukit/rtems/src/ratemontimeout.c | 13 ++- 4 files changed, 183 insertions(+), 41 deletions(-) diff --git a/cpukit/rtems/include/rtems/rtems/ratemon.h b/cpukit/rtems/include/rtems/rtems/ratemon.h index 50b8478..71a99dc 100644 --- a/cpukit/rtems/include/rtems/rtems/ratemon.h +++ b/cpukit/rtems/include/rtems/rtems/ratemon.h @@ -22,6 +22,7 @@ /* COPYRIGHT (c) 1989-2009, 2016. * On-Line Applications Research Corporation (OAR). + * COPYRIGHT (c) 2016 Kuan-Hsun Chen, TU Dortmund University (TUDo). * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -194,11 +195,6 @@ typedef struct { /** This field is the object management portion of a Period instance. */ Objects_Control Object; - /** - * @brief Protects the rate monotonic period state. - */ - ISR_LOCK_MEMBER( Lock ) - /** This is the timer used to provide the unblocking mechanism. */ Watchdog_Control Timer; @@ -206,12 +202,6 @@ typedef struct { rtems_rate_monotonic_period_states state; /** - * @brief A priority node for use by the scheduler job release and cancel - * operations. - */ - Priority_Node Priority; - - /** * This field contains the length of the next period to be * executed. */ @@ -240,6 +230,19 @@ typedef struct { * This field contains the statistics maintained for the period. */ Rate_monotonic_Statistics Statistics; + + /** + * This field contains the number of postponed jobs. When the watchdog timeout, + * this variable will be increased immediately. + */ + uint32_t postponed_jobs; + + /** + * This field contains the tick of the latest deadline decided by the period + * watchdog. + */ + uint64_t latest_deadline; + } Rate_monotonic_Control; /** @@ -386,6 +389,23 @@ void rtems_rate_monotonic_report_statistics_with_plugin( void rtems_rate_monotonic_report_statistics( void ); /** + * @brief RTEMS Return the number of postponed jobs + * + * This is a helper function to return the number of postponed jobs by this + * given period. This number is only increased by the corresponding watchdog, + * and is decreased by RMS manager with the postponed job releasing. + * + * @param[in] id is the period id + * + * @retval This helper function returns the number of postponed + * jobs with given period_id. + * + */ +uint32_t rtems_rate_monotonic_Postponed_num( + rtems_id period_id +); + +/** * @brief RTEMS Rate Monotonic Period * * This routine implements the rtems_rate_monotonic_period directive. When diff --git a/cpukit/rtems/include/rtems/rtems/ratemonimpl.h b/cpukit/rtems/include/rtems/rtems/ratemonimpl.h index b6b3ffd..6cdaaeb 100644 --- a/cpukit/rtems/include/rtems/rtems/ratemonimpl.h +++ b/cpukit/rtems/include/rtems/rtems/ratemonimpl.h @@ -9,6 +9,7 @@ /* COPYRIGHT (c) 1989-2008. * On-Line Applications Research Corporation (OAR). * Copyright (c) 2016 embedded brains GmbH. + * COPYRIGHT (c) 2016 Kuan-Hsun Chen, TU Dortmund University (TUDo). * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -69,19 +70,19 @@ RTEMS_INLINE_ROUTINE Rate_monotonic_Control *_Rate_monotonic_Allocate( void ) } RTEMS_INLINE_ROUTINE void _Rate_monotonic_Acquire_critical( - Rate_monotonic_Control *the_period, - ISR_lock_Context *lock_context + Thread_Control *the_thread, + ISR_lock_Context *lock_context ) { - _ISR_lock_Acquire( &the_period->Lock, lock_context ); + _Thread_Wait_acquire_default_critical( the_thread, lock_context ); } RTEMS_INLINE_ROUTINE void _Rate_monotonic_Release( - Rate_monotonic_Control *the_period, - ISR_lock_Context *lock_context + Thread_Control *the_thread, + ISR_lock_Context *lock_context ) { - _ISR_lock_Release_and_ISR_enable( &the_period->Lock, lock_context ); + _Thread_Wait_release_default( the_thread, lock_context ); } RTEMS_INLINE_ROUTINE Rate_monotonic_Control *_Rate_monotonic_Get( @@ -116,6 +117,18 @@ bool _Rate_monotonic_Get_status( Timestamp_Control *cpu_since_last_period ); +/** + * @brief Renew the watchdog deadline + * + * This routine is prepared for the watchdog timeout to renew its deadline + * without releasing jobs. + */ +void _Rate_monotonic_Renew_deadline( + Rate_monotonic_Control *the_period, + Thread_Control *owner, + ISR_lock_Context *lock_context +); + void _Rate_monotonic_Restart( Rate_monotonic_Control *the_period, Thread_Control *owner, diff --git a/cpukit/rtems/src/ratemonperiod.c b/cpukit/rtems/src/ratemonperiod.c index 77bd996..26cee58 100644 --- a/cpukit/rtems/src/ratemonperiod.c +++ b/cpukit/rtems/src/ratemonperiod.c @@ -9,6 +9,7 @@ * COPYRIGHT (c) 1989-2010. * On-Line Applications Research Corporation (OAR). * Copyright (c) 2016 embedded brains GmbH. + * COPYRIGHT (c) 2016 Kuan-Hsun Chen, TU Dortmund University (TUDo). * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -63,6 +64,24 @@ bool _Rate_monotonic_Get_status( return true; } +static void _Rate_monotonic_Release_postponedjob( + Rate_monotonic_Control *the_period, + Thread_Control *owner, + rtems_interval next_length, + ISR_lock_Context *lock_context +) +{ + /* This function only releases the postponed jobs. */ + Per_CPU_Control *cpu_self; + cpu_self = _Thread_Dispatch_disable_critical( lock_context ); + _Rate_monotonic_Release( owner, lock_context ); + + the_period->postponed_jobs -=1; + _Scheduler_Release_job( owner, the_period->latest_deadline ); + + _Thread_Dispatch_enable( cpu_self ); +} + static void _Rate_monotonic_Release_job( Rate_monotonic_Control *the_period, Thread_Control *owner, @@ -70,29 +89,49 @@ static void _Rate_monotonic_Release_job( ISR_lock_Context *lock_context ) { - Per_CPU_Control *cpu_self; - Thread_queue_Context queue_context; - uint64_t deadline; + Per_CPU_Control *cpu_self; + uint64_t deadline; cpu_self = _Thread_Dispatch_disable_critical( lock_context ); + _Rate_monotonic_Release( owner, lock_context ); + _ISR_lock_ISR_disable( lock_context ); deadline = _Watchdog_Per_CPU_insert_relative( &the_period->Timer, cpu_self, next_length ); - _Scheduler_Release_job( - owner, - &the_period->Priority, - deadline, - &queue_context - ); + _ISR_lock_ISR_enable( lock_context ); + + _Scheduler_Release_job( owner, deadline ); - _Rate_monotonic_Release( the_period, lock_context ); - _Thread_Priority_update( &queue_context ); _Thread_Dispatch_enable( cpu_self ); } +void _Rate_monotonic_Renew_deadline( + Rate_monotonic_Control *the_period, + Thread_Control *owner, + ISR_lock_Context *lock_context +) +{ + Per_CPU_Control *cpu_self; + uint64_t deadline; + + cpu_self = _Thread_Dispatch_disable_critical( lock_context ); + _Rate_monotonic_Release( owner, lock_context ); + + _ISR_lock_ISR_disable( lock_context ); + deadline = _Watchdog_Per_CPU_insert_relative( + &the_period->Timer, + cpu_self, + the_period->next_length + ); + the_period->latest_deadline = deadline; + _ISR_lock_ISR_enable( lock_context ); + _Thread_Dispatch_enable( cpu_self ); + +} + void _Rate_monotonic_Restart( Rate_monotonic_Control *the_period, Thread_Control *owner, @@ -190,6 +229,10 @@ static rtems_status_code _Rate_monotonic_Activate( ISR_lock_Context *lock_context ) { + + /* Initialize the number of postponed job variable */ + the_period->postponed_jobs = 0; + the_period->state = RATE_MONOTONIC_ACTIVE; the_period->next_length = length; _Rate_monotonic_Restart( the_period, executing, lock_context ); @@ -221,7 +264,7 @@ static rtems_status_code _Rate_monotonic_Block_while_active( _Thread_Wait_flags_set( executing, RATE_MONOTONIC_INTEND_TO_BLOCK ); cpu_self = _Thread_Dispatch_disable_critical( lock_context ); - _Rate_monotonic_Release( the_period, lock_context ); + _Rate_monotonic_Release( executing, lock_context ); _Thread_Set_state( executing, STATES_WAITING_FOR_PERIOD ); @@ -241,6 +284,11 @@ static rtems_status_code _Rate_monotonic_Block_while_active( return RTEMS_SUCCESSFUL; } +/* + * There are two possible cases: one is that the previous deadline is missed, + * The other is that the number of postponed jobs is not 0, but the current + * deadline is still not expired, i.e., state = RATE_MONOTONIC_ACTIVE. + */ static rtems_status_code _Rate_monotonic_Block_while_expired( Rate_monotonic_Control *the_period, rtems_interval length, @@ -248,6 +296,12 @@ static rtems_status_code _Rate_monotonic_Block_while_expired( ISR_lock_Context *lock_context ) { + /* + * No matter the just finished jobs in time or not, + * they are actually missing their deadlines already. + */ + the_period->state = RATE_MONOTONIC_EXPIRED; + /* * Update statistics from the concluding period */ @@ -255,11 +309,27 @@ static rtems_status_code _Rate_monotonic_Block_while_expired( the_period->state = RATE_MONOTONIC_ACTIVE; the_period->next_length = length; - - _Rate_monotonic_Release_job( the_period, executing, length, lock_context ); + + _Rate_monotonic_Release_postponedjob( the_period, executing, length, lock_context ); return RTEMS_TIMEOUT; } +uint32_t rtems_rate_monotonic_Postponed_num( + rtems_id period_id +) +{ + Rate_monotonic_Control *the_period; + ISR_lock_Context lock_context; + Thread_Control *owner; + + the_period = _Rate_monotonic_Get( period_id, &lock_context ); + _Assert(the_period != NULL); + uint32_t jobs = the_period->postponed_jobs; + owner = the_period->owner; + _Rate_monotonic_Release( owner, &lock_context ); + return jobs; +} + rtems_status_code rtems_rate_monotonic_period( rtems_id id, rtems_interval length @@ -282,22 +352,44 @@ rtems_status_code rtems_rate_monotonic_period( return RTEMS_NOT_OWNER_OF_RESOURCE; } - _Rate_monotonic_Acquire_critical( the_period, &lock_context ); + _Rate_monotonic_Acquire_critical( executing, &lock_context ); state = the_period->state; if ( length == RTEMS_PERIOD_STATUS ) { status = _Rate_monotonic_Get_status_for_state( state ); - _Rate_monotonic_Release( the_period, &lock_context ); + _Rate_monotonic_Release( executing, &lock_context ); } else { switch ( state ) { case RATE_MONOTONIC_ACTIVE: - status = _Rate_monotonic_Block_while_active( - the_period, - length, - executing, - &lock_context - ); + + if(the_period->postponed_jobs > 0){ + /* + * If the number of postponed jobs is not 0, it means the + * previous postponed instance is finished without exceeding + * the current period deadline. + * + * Do nothing on the watchdog deadline assignment but release the next + * remaining postponed job. + */ + status = _Rate_monotonic_Block_while_expired( + the_period, + length, + executing, + &lock_context + ); + }else{ + /* + * Normal case that no postponed jobs and no expiration, so wait for the period + * and update the deadline of watchdog accordingly. + */ + status = _Rate_monotonic_Block_while_active( + the_period, + length, + executing, + &lock_context + ); + } break; case RATE_MONOTONIC_INACTIVE: status = _Rate_monotonic_Activate( @@ -308,6 +400,14 @@ rtems_status_code rtems_rate_monotonic_period( ); break; default: + /* + * As now this period was already TIMEOUT, there must be at least one + * postponed job recorded by the watchdog. The one which exceeded + * the previous deadline"s" was just finished. + * + * Maybe there is more than one job postponed due to the preemption or + * the previous finished job. + */ _Assert( state == RATE_MONOTONIC_EXPIRED ); status = _Rate_monotonic_Block_while_expired( the_period, diff --git a/cpukit/rtems/src/ratemontimeout.c b/cpukit/rtems/src/ratemontimeout.c index e514a31..be0a770 100644 --- a/cpukit/rtems/src/ratemontimeout.c +++ b/cpukit/rtems/src/ratemontimeout.c @@ -9,6 +9,8 @@ * COPYRIGHT (c) 1989-2009. * On-Line Applications Research Corporation (OAR). * + * COPYRIGHT (c) 2016 Kuan-Hsun Chen, TU Dortmund University (TUDo). + * * 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. @@ -31,7 +33,7 @@ void _Rate_monotonic_Timeout( Watchdog_Control *the_watchdog ) owner = the_period->owner; _ISR_lock_ISR_disable( &lock_context ); - _Rate_monotonic_Acquire_critical( the_period, &lock_context ); + _Rate_monotonic_Acquire_critical( owner, &lock_context ); wait_flags = _Thread_Wait_flags_get( owner ); if ( @@ -62,7 +64,14 @@ void _Rate_monotonic_Timeout( Watchdog_Control *the_watchdog ) _Thread_Unblock( owner ); } } else { + /* + * If the watchdog is timeout, it means there is an additional postponed + * job in the next period but it is not available to release now: + * Either the current task is still executed, or it is preemptive by the + * other higher priority tasks. + */ + the_period->postponed_jobs += 1; the_period->state = RATE_MONOTONIC_EXPIRED; - _Rate_monotonic_Release( the_period, &lock_context ); + _Rate_monotonic_Renew_deadline( the_period, owner, &lock_context ); } } -- 1.9.1 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel