From 90960bd11a91259d9aace3870692dbe2e227de0f Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 21 Mar 2016 15:01:57 +0100 Subject: 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. --- cpukit/rtems/include/rtems/rtems/ratemon.h | 20 +- cpukit/rtems/include/rtems/rtems/ratemonimpl.h | 113 +++------ cpukit/rtems/src/ratemoncancel.c | 65 +++--- cpukit/rtems/src/ratemondelete.c | 39 ++-- cpukit/rtems/src/ratemongetstatistics.c | 61 +++-- cpukit/rtems/src/ratemongetstatus.c | 101 ++++---- cpukit/rtems/src/ratemonperiod.c | 310 ++++++++++++++----------- cpukit/rtems/src/ratemonresetstatistics.c | 47 +--- cpukit/rtems/src/ratemontimeout.c | 63 +++-- cpukit/score/include/rtems/score/threadimpl.h | 7 +- testsuites/sptests/spintrcritical08/init.c | 32 ++- 11 files changed, 423 insertions(+), 435 deletions(-) diff --git a/cpukit/rtems/include/rtems/rtems/ratemon.h b/cpukit/rtems/include/rtems/rtems/ratemon.h index 0159e5c1e6..87bd064c98 100644 --- a/cpukit/rtems/include/rtems/rtems/ratemon.h +++ b/cpukit/rtems/include/rtems/rtems/ratemon.h @@ -82,12 +82,6 @@ typedef enum { */ RATE_MONOTONIC_INACTIVE, - /** - * This value indicates the period is on the watchdog chain, and - * the owner is blocked waiting on it. - */ - RATE_MONOTONIC_OWNER_IS_BLOCKING, - /** * This value indicates the period is on the watchdog chain, and * running. The owner should be executed or blocked waiting on @@ -95,12 +89,6 @@ typedef enum { */ RATE_MONOTONIC_ACTIVE, - /** - * This value indicates the period is on the watchdog chain, and - * has expired. The owner should be blocked waiting for the next period. - */ - RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING, - /** * This value indicates the period is off the watchdog chain, and * has expired. The owner is still executing and has taken too much @@ -194,8 +182,12 @@ typedef struct { } rtems_rate_monotonic_period_status; /** - * The following structure defines the control block used to manage - * each period. + * @brief The following structure defines the control block used to manage each + * period. + * + * State changes are protected by the default thread lock of the owner thread. + * The owner thread is the thread that created the period object. The owner + * thread field is immutable after object creation. */ typedef struct { /** This field is the object management portion of a Period instance. */ diff --git a/cpukit/rtems/include/rtems/rtems/ratemonimpl.h b/cpukit/rtems/include/rtems/rtems/ratemonimpl.h index 3141bfa9ae..28837a2c16 100644 --- a/cpukit/rtems/include/rtems/rtems/ratemonimpl.h +++ b/cpukit/rtems/include/rtems/rtems/ratemonimpl.h @@ -8,6 +8,7 @@ /* COPYRIGHT (c) 1989-2008. * 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 @@ -19,6 +20,9 @@ #include #include +#include +#include +#include #include @@ -34,6 +38,15 @@ extern "C" { * @{ */ +#define RATE_MONOTONIC_INTEND_TO_BLOCK \ + ( THREAD_WAIT_CLASS_PERIOD | THREAD_WAIT_STATE_INTEND_TO_BLOCK ) + +#define RATE_MONOTONIC_BLOCKED \ + ( THREAD_WAIT_CLASS_PERIOD | THREAD_WAIT_STATE_BLOCKED ) + +#define RATE_MONOTONIC_READY_AGAIN \ + ( THREAD_WAIT_CLASS_PERIOD | THREAD_WAIT_STATE_READY_AGAIN ) + /** * @brief Rate Monotonic Period Class Management Structure * @@ -55,86 +68,31 @@ RTEMS_INLINE_ROUTINE Rate_monotonic_Control *_Rate_monotonic_Allocate( void ) _Objects_Allocate( &_Rate_monotonic_Information ); } -/** - * @brief Allocates a period control block from - * the inactive chain of free period control blocks. - * - * This routine allocates a period control block from - * the inactive chain of free period control blocks. - */ -RTEMS_INLINE_ROUTINE void _Rate_monotonic_Free ( - Rate_monotonic_Control *the_period +RTEMS_INLINE_ROUTINE void _Rate_monotonic_Acquire_critical( + Thread_Control *the_thread, + ISR_lock_Context *lock_context ) { - _Objects_Free( &_Rate_monotonic_Information, &the_period->Object ); + _Thread_Lock_acquire_default_critical( the_thread, lock_context ); } -/** - * @brief Maps period IDs to period control blocks. - * - * This function maps period IDs to period control blocks. - * If ID corresponds to a local period, then it returns - * the_period control pointer which maps to ID and location - * is set to OBJECTS_LOCAL. Otherwise, location is set - * to OBJECTS_ERROR and the_period is undefined. - */ -RTEMS_INLINE_ROUTINE Rate_monotonic_Control *_Rate_monotonic_Get ( - Objects_Id id, - Objects_Locations *location +RTEMS_INLINE_ROUTINE void _Rate_monotonic_Release( + Thread_Control *the_thread, + ISR_lock_Context *lock_context ) { - return (Rate_monotonic_Control *) - _Objects_Get( &_Rate_monotonic_Information, id, location ); + _Thread_Lock_release_default( the_thread, lock_context ); } -/** - * @brief Checks if the_period is in the ACTIVE state. - * - * This function returns TRUE if the_period is in the ACTIVE state, - * and FALSE otherwise. - */ -RTEMS_INLINE_ROUTINE bool _Rate_monotonic_Is_active ( - Rate_monotonic_Control *the_period +RTEMS_INLINE_ROUTINE Rate_monotonic_Control *_Rate_monotonic_Get( + Objects_Id id, + ISR_lock_Context *lock_context ) { - return (the_period->state == RATE_MONOTONIC_ACTIVE); -} - -/** - * @brief Checks if the_period is in the ACTIVE state. - * - * This function returns TRUE if the_period is in the ACTIVE state, - * and FALSE otherwise. - */ -RTEMS_INLINE_ROUTINE bool _Rate_monotonic_Is_inactive ( - Rate_monotonic_Control *the_period -) -{ - return (the_period->state == RATE_MONOTONIC_INACTIVE); -} - -/** - * @brief Checks if the_period is in the EXPIRED state. - * - * This function returns TRUE if the_period is in the EXPIRED state, - * and FALSE otherwise. - */ -RTEMS_INLINE_ROUTINE bool _Rate_monotonic_Is_expired ( - Rate_monotonic_Control *the_period -) -{ - return (the_period->state == RATE_MONOTONIC_EXPIRED); + return (Rate_monotonic_Control *) + _Objects_Get_local( &_Rate_monotonic_Information, id, lock_context ); } -/** - * @brief Rate Monotonic Timeout - * - * This routine is invoked when the period represented by the watchdog expires. - * If the thread which owns this period is blocked waiting for the period to - * expire, then it is readied and the period is restarted. If the owning thread - * is not waiting for the period to expire, then the period is placed in the - * EXPIRED state and not restarted. - */ void _Rate_monotonic_Timeout( Watchdog_Control *watchdog ); /** @@ -158,17 +116,16 @@ bool _Rate_monotonic_Get_status( Timestamp_Control *cpu_since_last_period ); -/** - * @brief Restart Rate Monotonic Period - * - * This routine is invoked when a period is initiated via an explicit - * call to rtems_rate_monotonic_period for the period's first iteration - * or from _Rate_monotonic_Timeout for period iterations 2-n. - * - * @param[in] the_period points to the period being operated upon. - */ void _Rate_monotonic_Restart( - Rate_monotonic_Control *the_period + Rate_monotonic_Control *the_period, + Thread_Control *owner, + ISR_lock_Context *lock_context +); + +void _Rate_monotonic_Cancel( + Rate_monotonic_Control *the_period, + Thread_Control *owner, + ISR_lock_Context *lock_context ); RTEMS_INLINE_ROUTINE void _Rate_monotonic_Reset_min_time( diff --git a/cpukit/rtems/src/ratemoncancel.c b/cpukit/rtems/src/ratemoncancel.c index 2e4d5322db..af6b1ec4e3 100644 --- a/cpukit/rtems/src/ratemoncancel.c +++ b/cpukit/rtems/src/ratemoncancel.c @@ -8,6 +8,7 @@ /* * COPYRIGHT (c) 1989-2007. * 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 @@ -19,40 +20,48 @@ #endif #include -#include -#include -#include + +void _Rate_monotonic_Cancel( + Rate_monotonic_Control *the_period, + Thread_Control *owner, + ISR_lock_Context *lock_context +) +{ + Per_CPU_Control *cpu_self; + + _Watchdog_Per_CPU_remove_relative( &the_period->Timer ); + + owner = the_period->owner; + _Rate_monotonic_Acquire_critical( owner, lock_context ); + the_period->state = RATE_MONOTONIC_INACTIVE; + + cpu_self = _Thread_Dispatch_disable_critical( lock_context ); + _Rate_monotonic_Release( owner, lock_context ); + + _Scheduler_Release_job( owner, 0 ); + + _Thread_Dispatch_enable( cpu_self ); +} rtems_status_code rtems_rate_monotonic_cancel( rtems_id id ) { Rate_monotonic_Control *the_period; - Objects_Locations location; - 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; - } - _ISR_Disable( level ); - _Watchdog_Per_CPU_remove_relative( &the_period->Timer ); - _ISR_Enable( level ); - the_period->state = RATE_MONOTONIC_INACTIVE; - _Scheduler_Release_job( the_period->owner, 0 ); - _Objects_Put( &the_period->Object ); - return RTEMS_SUCCESSFUL; - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: -#endif - case OBJECTS_ERROR: - break; + ISR_lock_Context lock_context; + Thread_Control *executing; + + 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; } - return RTEMS_INVALID_ID; + _Rate_monotonic_Cancel( the_period, executing, &lock_context ); + return RTEMS_SUCCESSFUL; } diff --git a/cpukit/rtems/src/ratemondelete.c b/cpukit/rtems/src/ratemondelete.c index 09b9ab6712..cb07694c1b 100644 --- a/cpukit/rtems/src/ratemondelete.c +++ b/cpukit/rtems/src/ratemondelete.c @@ -8,6 +8,7 @@ /* * COPYRIGHT (c) 1989-2007. * 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 @@ -19,42 +20,28 @@ #endif #include -#include -#include -#include rtems_status_code rtems_rate_monotonic_delete( rtems_id id ) { Rate_monotonic_Control *the_period; - Objects_Locations location; - ISR_Level level; + ISR_lock_Context lock_context; + rtems_status_code status; _Objects_Allocator_lock(); - the_period = _Rate_monotonic_Get( id, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - _Scheduler_Release_job( the_period->owner, 0 ); - _Objects_Close( &_Rate_monotonic_Information, &the_period->Object ); - _ISR_Disable( level ); - _Watchdog_Per_CPU_remove_relative( &the_period->Timer ); - _ISR_Enable( level ); - the_period->state = RATE_MONOTONIC_INACTIVE; - _Objects_Put( &the_period->Object ); - _Rate_monotonic_Free( the_period ); - _Objects_Allocator_unlock(); - return RTEMS_SUCCESSFUL; - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* should never return this */ -#endif - case OBJECTS_ERROR: - break; + + the_period = _Rate_monotonic_Get( id, &lock_context ); + if ( the_period != NULL ) { + _Objects_Close( &_Rate_monotonic_Information, &the_period->Object ); + _Rate_monotonic_Cancel( the_period, the_period->owner, &lock_context ); + _Objects_Free( &_Rate_monotonic_Information, &the_period->Object ); + status = RTEMS_SUCCESSFUL; + } else { + status = RTEMS_INVALID_ID; } _Objects_Allocator_unlock(); - return RTEMS_INVALID_ID; + return status; } diff --git a/cpukit/rtems/src/ratemongetstatistics.c b/cpukit/rtems/src/ratemongetstatistics.c index 6644562ba0..a6a0525fb0 100644 --- a/cpukit/rtems/src/ratemongetstatistics.c +++ b/cpukit/rtems/src/ratemongetstatistics.c @@ -8,6 +8,7 @@ /* * COPYRIGHT (c) 1989-2009. * 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 @@ -18,50 +19,40 @@ #include "config.h" #endif -#include -#include -#include -#include #include -#include rtems_status_code rtems_rate_monotonic_get_statistics( rtems_id id, - rtems_rate_monotonic_period_statistics *statistics + rtems_rate_monotonic_period_statistics *dst ) { - Objects_Locations location; - Rate_monotonic_Control *the_period; - rtems_rate_monotonic_period_statistics *dst; - Rate_monotonic_Statistics *src; + Rate_monotonic_Control *the_period; + ISR_lock_Context lock_context; + Thread_Control *owner; + const Rate_monotonic_Statistics *src; - if ( !statistics ) + if ( dst == NULL ) { return RTEMS_INVALID_ADDRESS; + } - the_period = _Rate_monotonic_Get( id, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - dst = statistics; - src = &the_period->Statistics; - dst->count = src->count; - dst->missed_count = src->missed_count; - _Timestamp_To_timespec( &src->min_cpu_time, &dst->min_cpu_time ); - _Timestamp_To_timespec( &src->max_cpu_time, &dst->max_cpu_time ); - _Timestamp_To_timespec( &src->total_cpu_time, &dst->total_cpu_time ); - _Timestamp_To_timespec( &src->min_wall_time, &dst->min_wall_time ); - _Timestamp_To_timespec( &src->max_wall_time, &dst->max_wall_time ); - _Timestamp_To_timespec( &src->total_wall_time, &dst->total_wall_time ); - - _Objects_Put( &the_period->Object ); - return RTEMS_SUCCESSFUL; - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* should never return this */ -#endif - case OBJECTS_ERROR: - break; + the_period = _Rate_monotonic_Get( id, &lock_context ); + if ( the_period == NULL ) { + return RTEMS_INVALID_ID; } - return RTEMS_INVALID_ID; + owner = the_period->owner; + _Rate_monotonic_Acquire_critical( owner, &lock_context ); + + src = &the_period->Statistics; + dst->count = src->count; + dst->missed_count = src->missed_count; + _Timestamp_To_timespec( &src->min_cpu_time, &dst->min_cpu_time ); + _Timestamp_To_timespec( &src->max_cpu_time, &dst->max_cpu_time ); + _Timestamp_To_timespec( &src->total_cpu_time, &dst->total_cpu_time ); + _Timestamp_To_timespec( &src->min_wall_time, &dst->min_wall_time ); + _Timestamp_To_timespec( &src->max_wall_time, &dst->max_wall_time ); + _Timestamp_To_timespec( &src->total_wall_time, &dst->total_wall_time ); + + _Rate_monotonic_Release( owner, &lock_context ); + return RTEMS_SUCCESSFUL; } diff --git a/cpukit/rtems/src/ratemongetstatus.c b/cpukit/rtems/src/ratemongetstatus.c index 29296ebca3..82a950ec6a 100644 --- a/cpukit/rtems/src/ratemongetstatus.c +++ b/cpukit/rtems/src/ratemongetstatus.c @@ -8,6 +8,7 @@ /* * COPYRIGHT (c) 1989-2009. * 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 @@ -18,72 +19,68 @@ #include "config.h" #endif -#include -#include -#include -#include #include -#include -#include rtems_status_code rtems_rate_monotonic_get_status( rtems_id id, - rtems_rate_monotonic_period_status *status + rtems_rate_monotonic_period_status *period_status ) { - Timestamp_Control executed; - Objects_Locations location; - Timestamp_Control since_last_period; Rate_monotonic_Control *the_period; - bool valid_status; + ISR_lock_Context lock_context; + Thread_Control *owner; + rtems_status_code status; - if ( !status ) + if ( period_status == NULL ) { return RTEMS_INVALID_ADDRESS; + } - the_period = _Rate_monotonic_Get( id, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - status->owner = the_period->owner->Object.id; - status->state = the_period->state; - - /* - * If the period is inactive, there is no information. - */ - if ( status->state == RATE_MONOTONIC_INACTIVE ) { - _Timespec_Set_to_zero( &status->since_last_period ); - _Timespec_Set_to_zero( &status->executed_since_last_period ); - } else { + the_period = _Rate_monotonic_Get( id, &lock_context ); + if ( the_period == NULL ) { + return RTEMS_INVALID_ID; + } - /* - * Grab the current status. - */ - valid_status = - _Rate_monotonic_Get_status( - the_period, &since_last_period, &executed - ); - if (!valid_status) { - _Objects_Put( &the_period->Object ); - return RTEMS_NOT_DEFINED; - } + owner = the_period->owner; + _Rate_monotonic_Acquire_critical( owner, &lock_context ); - _Timestamp_To_timespec( - &since_last_period, &status->since_last_period - ); - _Timestamp_To_timespec( - &executed, &status->executed_since_last_period - ); - } + period_status->owner = owner->Object.id; + period_status->state = the_period->state; - _Objects_Put( &the_period->Object ); - return RTEMS_SUCCESSFUL; + if ( the_period->state == RATE_MONOTONIC_INACTIVE ) { + /* + * If the period is inactive, there is no information. + */ + _Timespec_Set_to_zero( &period_status->since_last_period ); + _Timespec_Set_to_zero( &period_status->executed_since_last_period ); + status = RTEMS_SUCCESSFUL; + } else { + Timestamp_Control wall_since_last_period; + Timestamp_Control cpu_since_last_period; + bool valid_status; -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* should never return this */ -#endif - case OBJECTS_ERROR: - break; + /* + * Grab the current status. + */ + valid_status = _Rate_monotonic_Get_status( + the_period, + &wall_since_last_period, + &cpu_since_last_period + ); + if ( valid_status ) { + _Timestamp_To_timespec( + &wall_since_last_period, + &period_status->since_last_period + ); + _Timestamp_To_timespec( + &cpu_since_last_period, + &period_status->executed_since_last_period + ); + status = RTEMS_SUCCESSFUL; + } else { + status = RTEMS_NOT_DEFINED; + } } - return RTEMS_INVALID_ID; + _Rate_monotonic_Release( owner, &lock_context ); + return status; } 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 #include -#include #include -#include 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; } diff --git a/cpukit/rtems/src/ratemonresetstatistics.c b/cpukit/rtems/src/ratemonresetstatistics.c index 1256409a21..b146e6acb2 100644 --- a/cpukit/rtems/src/ratemonresetstatistics.c +++ b/cpukit/rtems/src/ratemonresetstatistics.c @@ -18,49 +18,24 @@ #include "config.h" #endif -#include -#include -#include -#include #include -#include - -/* - * rtems_rate_monotonic_reset_statistics - * - * This directive allows a thread to reset the statistics information - * on a specific period instance. - * - * Input parameters: - * id - rate monotonic id - * - * Output parameters: - * RTEMS_SUCCESSFUL - if successful - * error code - if unsuccessful - * - */ rtems_status_code rtems_rate_monotonic_reset_statistics( rtems_id id ) { - Objects_Locations location; - Rate_monotonic_Control *the_period; - - the_period = _Rate_monotonic_Get( id, &location ); - switch ( location ) { + Rate_monotonic_Control *the_period; + ISR_lock_Context lock_context; + Thread_Control *owner; - case OBJECTS_LOCAL: - _Rate_monotonic_Reset_statistics( the_period ); - _Objects_Put( &the_period->Object ); - return RTEMS_SUCCESSFUL; - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* should never return this */ -#endif - case OBJECTS_ERROR: - break; + the_period = _Rate_monotonic_Get( id, &lock_context ); + if ( the_period == NULL ) { + return RTEMS_INVALID_ID; } - return RTEMS_INVALID_ID; + owner = the_period->owner; + _Rate_monotonic_Acquire_critical( owner, &lock_context ); + _Rate_monotonic_Reset_statistics( the_period ); + _Rate_monotonic_Release( owner, &lock_context ); + return RTEMS_SUCCESSFUL; } diff --git a/cpukit/rtems/src/ratemontimeout.c b/cpukit/rtems/src/ratemontimeout.c index 7c25595a16..78c78e2a7f 100644 --- a/cpukit/rtems/src/ratemontimeout.c +++ b/cpukit/rtems/src/ratemontimeout.c @@ -19,33 +19,50 @@ #endif #include -#include -#include -void _Rate_monotonic_Timeout( Watchdog_Control *watchdog ) +void _Rate_monotonic_Timeout( Watchdog_Control *the_watchdog ) { Rate_monotonic_Control *the_period; - Thread_Control *the_thread; - - /* - * When we get here, the Timer is already off the chain so we do not - * have to worry about that -- hence no _Watchdog_Remove(). - */ - the_period = RTEMS_CONTAINER_OF( watchdog, Rate_monotonic_Control, Timer ); - the_thread = the_period->owner; - - _Thread_Disable_dispatch(); - - if ( _States_Is_waiting_for_period( the_thread->current_state ) && - the_thread->Wait.id == the_period->Object.id ) { - _Thread_Unblock( the_thread ); - _Rate_monotonic_Restart( the_period ); - } else if ( the_period->state == RATE_MONOTONIC_OWNER_IS_BLOCKING ) { - the_period->state = RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING; - _Rate_monotonic_Restart( the_period ); + Thread_Control *owner; + ISR_lock_Context lock_context; + Thread_Wait_flags wait_flags; + + the_period = RTEMS_CONTAINER_OF( the_watchdog, Rate_monotonic_Control, Timer ); + owner = the_period->owner; + + _ISR_lock_ISR_disable( &lock_context ); + _Rate_monotonic_Acquire_critical( owner, &lock_context ); + wait_flags = _Thread_Wait_flags_get( owner ); + + if ( + ( wait_flags & THREAD_WAIT_CLASS_PERIOD ) != 0 + && owner->Wait.return_argument == the_period + ) { + bool unblock; + bool success; + + owner->Wait.return_argument = NULL; + + success = _Thread_Wait_flags_try_change_critical( + owner, + RATE_MONOTONIC_INTEND_TO_BLOCK, + RATE_MONOTONIC_READY_AGAIN + ); + if ( success ) { + unblock = false; + } else { + _Assert( _Thread_Wait_flags_get( owner ) == RATE_MONOTONIC_BLOCKED ); + _Thread_Wait_flags_set( owner, RATE_MONOTONIC_READY_AGAIN ); + unblock = true; + } + + _Rate_monotonic_Restart( the_period, owner, &lock_context ); + + if ( unblock ) { + _Thread_Unblock( owner ); + } } else { the_period->state = RATE_MONOTONIC_EXPIRED; + _Rate_monotonic_Release( owner, &lock_context ); } - - _Thread_Unnest_dispatch(); } diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h index 37ac5964be..55fdb224da 100644 --- a/cpukit/score/include/rtems/score/threadimpl.h +++ b/cpukit/score/include/rtems/score/threadimpl.h @@ -1280,10 +1280,15 @@ RTEMS_INLINE_ROUTINE void _Thread_Lock_restore_default( #define THREAD_WAIT_CLASS_SYSTEM_EVENT 0x200U /** - * @brief Indicates that the thread waits for a object. + * @brief Indicates that the thread waits for an object. */ #define THREAD_WAIT_CLASS_OBJECT 0x400U +/** + * @brief Indicates that the thread waits for a period. + */ +#define THREAD_WAIT_CLASS_PERIOD 0x800U + RTEMS_INLINE_ROUTINE void _Thread_Wait_flags_set( Thread_Control *the_thread, Thread_Wait_flags flags diff --git a/testsuites/sptests/spintrcritical08/init.c b/testsuites/sptests/spintrcritical08/init.c index 3610e65b96..8d17feb365 100644 --- a/testsuites/sptests/spintrcritical08/init.c +++ b/testsuites/sptests/spintrcritical08/init.c @@ -25,20 +25,18 @@ static rtems_id Period; static volatile bool case_hit = false; +static Thread_Control *thread; + static rtems_rate_monotonic_period_states getState(void) { - Objects_Locations location; - Rate_monotonic_Control *period; - - period = (Rate_monotonic_Control *)_Objects_Get( - &_Rate_monotonic_Information, Period, &location ); - if ( location != OBJECTS_LOCAL ) { - puts( "Bad object lookup" ); - rtems_test_exit(0); - } - _Thread_Unnest_dispatch(); + Rate_monotonic_Control *the_period; + ISR_lock_Context lock_context; + + the_period = _Rate_monotonic_Get( Period, &lock_context ); + rtems_test_assert( the_period != NULL ); + _ISR_lock_ISR_enable( &lock_context ); - return period->state; + return the_period->state; } static rtems_timer_service_routine test_release_from_isr( @@ -55,11 +53,19 @@ static rtems_timer_service_routine test_release_from_isr( && watchdog->expire == cpu->Watchdog.ticks && watchdog->routine == _Rate_monotonic_Timeout ) { + Thread_Wait_flags flags = _Thread_Wait_flags_get( thread ); + _Watchdog_Per_CPU_remove_relative( watchdog ); + rtems_test_assert( getState() == RATE_MONOTONIC_ACTIVE ); + (*watchdog->routine)( watchdog ); - if ( getState() == RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING ) { + if ( flags == RATE_MONOTONIC_INTEND_TO_BLOCK ) { + rtems_test_assert( + _Thread_Wait_flags_get( thread ) == RATE_MONOTONIC_READY_AGAIN + ); + rtems_test_assert( getState() == RATE_MONOTONIC_ACTIVE ); case_hit = true; } } @@ -93,6 +99,8 @@ rtems_task Init( puts( "Init - Trying to generate period ending while blocking" ); + thread = _Thread_Get_executing(); + puts( "Init - rtems_rate_monotonic_create - OK" ); sc = rtems_rate_monotonic_create( rtems_build_name( 'P', 'E', 'R', '1' ), -- cgit v1.2.3