diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-03-21 15:01:57 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-03-22 07:05:05 +0100 |
commit | 90960bd11a91259d9aace3870692dbe2e227de0f (patch) | |
tree | 3d88f8bc3d1fe17252e8290cadae2afb4a38ce4b /cpukit/rtems/src/ratemonperiod.c | |
parent | rtems: Avoid __RTEMS_USE_TICKS_FOR_STATISTICS__ (diff) | |
download | rtems-90960bd11a91259d9aace3870692dbe2e227de0f.tar.bz2 |
rtems: Rework rate-monotonic scheduler
Use the default thread lock to protect rate-monotonic state changes.
This avoids use of the Giant lock. Split rtems_rate_monotonic_period()
body into several static functions. Introduce a new thread wait class
THREAD_WAIT_CLASS_PERIOD for period objects to synchronize the blocking
operation.
Close #2631.
Diffstat (limited to 'cpukit/rtems/src/ratemonperiod.c')
-rw-r--r-- | cpukit/rtems/src/ratemonperiod.c | 310 |
1 files changed, 180 insertions, 130 deletions
diff --git a/cpukit/rtems/src/ratemonperiod.c b/cpukit/rtems/src/ratemonperiod.c index e03d8cff09..1a1373117b 100644 --- a/cpukit/rtems/src/ratemonperiod.c +++ b/cpukit/rtems/src/ratemonperiod.c @@ -8,6 +8,7 @@ /* * COPYRIGHT (c) 1989-2010. * On-Line Applications Research Corporation (OAR). + * Copyright (c) 2016 embedded brains GmbH. * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -20,9 +21,7 @@ #include <rtems/rtems/ratemonimpl.h> #include <rtems/score/schedulerimpl.h> -#include <rtems/score/threadimpl.h> #include <rtems/score/todimpl.h> -#include <rtems/score/watchdogimpl.h> bool _Rate_monotonic_Get_status( const Rate_monotonic_Control *the_period, @@ -64,28 +63,49 @@ bool _Rate_monotonic_Get_status( return true; } -void _Rate_monotonic_Restart( Rate_monotonic_Control *the_period ) +static void _Rate_monotonic_Release_job( + Rate_monotonic_Control *the_period, + Thread_Control *owner, + rtems_interval next_length, + ISR_lock_Context *lock_context +) { - ISR_Level level; + Per_CPU_Control *cpu_self; + + cpu_self = _Thread_Dispatch_disable_critical( lock_context ); + _Rate_monotonic_Release( owner, lock_context ); + + _Scheduler_Release_job( owner, next_length ); + + _ISR_lock_ISR_disable( lock_context ); + _Watchdog_Per_CPU_insert_relative( + &the_period->Timer, + cpu_self, + next_length + ); + _ISR_lock_ISR_enable( lock_context ); + _Thread_Dispatch_enable( cpu_self ); +} + +void _Rate_monotonic_Restart( + Rate_monotonic_Control *the_period, + Thread_Control *owner, + ISR_lock_Context *lock_context +) +{ /* * Set the starting point and the CPU time used for the statistics. */ _TOD_Get_uptime( &the_period->time_period_initiated ); - _Thread_Get_CPU_time_used( - the_period->owner, - &the_period->cpu_usage_period_initiated - ); - - _Scheduler_Release_job( the_period->owner, the_period->next_length ); + _Thread_Get_CPU_time_used( owner, &the_period->cpu_usage_period_initiated ); - _ISR_Disable( level ); - _Watchdog_Per_CPU_insert_relative( - &the_period->Timer, - _Per_CPU_Get(), - the_period->next_length + _Rate_monotonic_Release_job( + the_period, + owner, + the_period->next_length, + lock_context ); - _ISR_Enable( level ); } static void _Rate_monotonic_Update_statistics( @@ -143,126 +163,156 @@ static void _Rate_monotonic_Update_statistics( stats->max_wall_time = since_last_period; } +static rtems_status_code _Rate_monotonic_Get_status_for_state( + rtems_rate_monotonic_period_states state +) +{ + switch ( state ) { + case RATE_MONOTONIC_INACTIVE: + return RTEMS_NOT_DEFINED; + case RATE_MONOTONIC_EXPIRED: + return RTEMS_TIMEOUT; + default: + _Assert( state == RATE_MONOTONIC_ACTIVE ); + return RTEMS_SUCCESSFUL; + } +} + +static rtems_status_code _Rate_monotonic_Activate( + Rate_monotonic_Control *the_period, + rtems_interval length, + Thread_Control *executing, + ISR_lock_Context *lock_context +) +{ + the_period->state = RATE_MONOTONIC_ACTIVE; + the_period->next_length = length; + _Rate_monotonic_Restart( the_period, executing, lock_context ); + return RTEMS_SUCCESSFUL; +} + +static rtems_status_code _Rate_monotonic_Block_while_active( + Rate_monotonic_Control *the_period, + rtems_interval length, + Thread_Control *executing, + ISR_lock_Context *lock_context +) +{ + Per_CPU_Control *cpu_self; + bool success; + + /* + * Update statistics from the concluding period. + */ + _Rate_monotonic_Update_statistics( the_period ); + + /* + * This tells the _Rate_monotonic_Timeout that this task is + * in the process of blocking on the period and that we + * may be changing the length of the next period. + */ + the_period->next_length = length; + executing->Wait.return_argument = the_period; + _Thread_Wait_flags_set( executing, RATE_MONOTONIC_INTEND_TO_BLOCK ); + + cpu_self = _Thread_Dispatch_disable_critical( lock_context ); + _Rate_monotonic_Release( executing, lock_context ); + + _Thread_Set_state( executing, STATES_WAITING_FOR_PERIOD ); + + success = _Thread_Wait_flags_try_change( + executing, + RATE_MONOTONIC_INTEND_TO_BLOCK, + RATE_MONOTONIC_BLOCKED + ); + if ( !success ) { + _Assert( + _Thread_Wait_flags_get( executing ) == RATE_MONOTONIC_READY_AGAIN + ); + _Thread_Unblock( executing ); + } + + _Thread_Dispatch_enable( cpu_self ); + return RTEMS_SUCCESSFUL; +} + +static rtems_status_code _Rate_monotonic_Block_while_expired( + Rate_monotonic_Control *the_period, + rtems_interval length, + Thread_Control *executing, + ISR_lock_Context *lock_context +) +{ + /* + * Update statistics from the concluding period + */ + _Rate_monotonic_Update_statistics( the_period ); + + the_period->state = RATE_MONOTONIC_ACTIVE; + the_period->next_length = length; + + _Rate_monotonic_Release_job( the_period, executing, length, lock_context ); + return RTEMS_TIMEOUT; +} + rtems_status_code rtems_rate_monotonic_period( rtems_id id, rtems_interval length ) { - Rate_monotonic_Control *the_period; - Objects_Locations location; - rtems_status_code return_value; - rtems_rate_monotonic_period_states local_state; - ISR_Level level; - - the_period = _Rate_monotonic_Get( id, &location ); - - switch ( location ) { - case OBJECTS_LOCAL: - if ( !_Thread_Is_executing( the_period->owner ) ) { - _Objects_Put( &the_period->Object ); - return RTEMS_NOT_OWNER_OF_RESOURCE; - } - - if ( length == RTEMS_PERIOD_STATUS ) { - switch ( the_period->state ) { - case RATE_MONOTONIC_INACTIVE: - return_value = RTEMS_NOT_DEFINED; - break; - case RATE_MONOTONIC_EXPIRED: - case RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING: - return_value = RTEMS_TIMEOUT; - break; - case RATE_MONOTONIC_ACTIVE: - default: /* unreached -- only to remove warnings */ - return_value = RTEMS_SUCCESSFUL; - break; - } - _Objects_Put( &the_period->Object ); - return( return_value ); - } - - _ISR_Disable( level ); - if ( the_period->state == RATE_MONOTONIC_INACTIVE ) { - _ISR_Enable( level ); - - the_period->state = RATE_MONOTONIC_ACTIVE; - the_period->next_length = length; - _Rate_monotonic_Restart( the_period ); - _Objects_Put( &the_period->Object ); - return RTEMS_SUCCESSFUL; - } - - if ( the_period->state == RATE_MONOTONIC_ACTIVE ) { - /* - * Update statistics from the concluding period. - */ - _Rate_monotonic_Update_statistics( the_period ); - - /* - * This tells the _Rate_monotonic_Timeout that this task is - * in the process of blocking on the period and that we - * may be changing the length of the next period. - */ - the_period->state = RATE_MONOTONIC_OWNER_IS_BLOCKING; - the_period->next_length = length; - - _ISR_Enable( level ); - - _Thread_Executing->Wait.id = the_period->Object.id; - _Thread_Set_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD ); - - /* - * Did the watchdog timer expire while we were actually blocking - * on it? - */ - _ISR_Disable( level ); - local_state = the_period->state; - the_period->state = RATE_MONOTONIC_ACTIVE; - _ISR_Enable( level ); - - /* - * If it did, then we want to unblock ourself and continue as - * if nothing happen. The period was reset in the timeout routine. - */ - if ( local_state == RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING ) - _Thread_Clear_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD ); - - _Objects_Put( &the_period->Object ); - return RTEMS_SUCCESSFUL; - } - - if ( the_period->state == RATE_MONOTONIC_EXPIRED ) { - /* - * Update statistics from the concluding period - */ - _Rate_monotonic_Update_statistics( the_period ); - - _ISR_Enable( level ); - - the_period->state = RATE_MONOTONIC_ACTIVE; - the_period->next_length = length; - - _Watchdog_Per_CPU_insert_relative( - &the_period->Timer, - _Per_CPU_Get(), - length + Rate_monotonic_Control *the_period; + ISR_lock_Context lock_context; + Thread_Control *executing; + rtems_status_code status; + rtems_rate_monotonic_period_states state; + + the_period = _Rate_monotonic_Get( id, &lock_context ); + if ( the_period == NULL ) { + return RTEMS_INVALID_ID; + } + + executing = _Thread_Executing; + if ( executing != the_period->owner ) { + _ISR_lock_ISR_enable( &lock_context ); + return RTEMS_NOT_OWNER_OF_RESOURCE; + } + + _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( executing, &lock_context ); + } else { + switch ( state ) { + case RATE_MONOTONIC_ACTIVE: + status = _Rate_monotonic_Block_while_active( + the_period, + length, + executing, + &lock_context ); - _Scheduler_Release_job( the_period->owner, the_period->next_length ); - _Objects_Put( &the_period->Object ); - return RTEMS_TIMEOUT; - } - - /* - * These should never happen so just return invalid Id. - * - RATE_MONOTONIC_OWNER_IS_BLOCKING: - * - RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING: - */ -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* should never return this */ -#endif - case OBJECTS_ERROR: - break; + break; + case RATE_MONOTONIC_INACTIVE: + status = _Rate_monotonic_Activate( + the_period, + length, + executing, + &lock_context + ); + break; + default: + _Assert( state == RATE_MONOTONIC_EXPIRED ); + status = _Rate_monotonic_Block_while_expired( + the_period, + length, + executing, + &lock_context + ); + break; + } } - return RTEMS_INVALID_ID; + return status; } |