[PATCH] rtems: Rework rate-monotonic scheduler
Gedare Bloom
gedare at rtems.org
Tue Mar 22 00:59:05 UTC 2016
Looks good.
On Mon, Mar 21, 2016 at 10:40 AM, Sebastian Huber
<sebastian.huber at embedded-brains.de> wrote:
> Use the default thread lock to protect rate-monotonic state changes.
> his 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 | 307 ++++++++++++++-----------
> 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 | 24 +-
> 11 files changed, 412 insertions(+), 435 deletions(-)
>
> diff --git a/cpukit/rtems/include/rtems/rtems/ratemon.h b/cpukit/rtems/include/rtems/rtems/ratemon.h
> index 0159e5c..87bd064c 100644
> --- a/cpukit/rtems/include/rtems/rtems/ratemon.h
> +++ b/cpukit/rtems/include/rtems/rtems/ratemon.h
> @@ -84,24 +84,12 @@ typedef enum {
>
> /**
> * 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
> * another object.
> */
> 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
> * all time to complete this iteration of the period.
> @@ -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 3141bfa..28837a2 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 <rtems/rtems/ratemon.h>
> #include <rtems/score/objectimpl.h>
> +#include <rtems/score/schedulerimpl.h>
> +#include <rtems/score/threadimpl.h>
> +#include <rtems/score/watchdogimpl.h>
>
> #include <string.h>
>
> @@ -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 2e4d532..af6b1ec 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 <rtems/rtems/ratemonimpl.h>
> -#include <rtems/score/schedulerimpl.h>
> -#include <rtems/score/threadimpl.h>
> -#include <rtems/score/watchdogimpl.h>
> +
> +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 09b9ab6..cb07694 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 <rtems/rtems/ratemonimpl.h>
> -#include <rtems/score/schedulerimpl.h>
> -#include <rtems/score/thread.h>
> -#include <rtems/score/watchdogimpl.h>
>
> 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 6644562..a6a0525 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 <rtems/system.h>
> -#include <rtems/rtems/status.h>
> -#include <rtems/rtems/support.h>
> -#include <rtems/score/isr.h>
> #include <rtems/rtems/ratemonimpl.h>
> -#include <rtems/score/thread.h>
>
> 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 29296eb..82a950e 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 <rtems/system.h>
> -#include <rtems/rtems/status.h>
> -#include <rtems/rtems/support.h>
> -#include <rtems/score/isr.h>
> #include <rtems/rtems/ratemonimpl.h>
> -#include <rtems/score/thread.h>
> -#include <rtems/score/timespec.h>
>
> 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 e03d8cf..96ea65c 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,153 @@ 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 ) {
> + _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 1256409..b146e6a 100644
> --- a/cpukit/rtems/src/ratemonresetstatistics.c
> +++ b/cpukit/rtems/src/ratemonresetstatistics.c
> @@ -18,49 +18,24 @@
> #include "config.h"
> #endif
>
> -#include <rtems/system.h>
> -#include <rtems/rtems/status.h>
> -#include <rtems/rtems/support.h>
> -#include <rtems/score/isr.h>
> #include <rtems/rtems/ratemonimpl.h>
> -#include <rtems/score/thread.h>
> -
> -/*
> - * 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 7c25595..78c78e2 100644
> --- a/cpukit/rtems/src/ratemontimeout.c
> +++ b/cpukit/rtems/src/ratemontimeout.c
> @@ -19,33 +19,50 @@
> #endif
>
> #include <rtems/rtems/ratemonimpl.h>
> -#include <rtems/score/threadimpl.h>
> -#include <rtems/score/watchdogimpl.h>
>
> -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 37ac596..55fdb22 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 3610e65..2e700da 100644
> --- a/testsuites/sptests/spintrcritical08/init.c
> +++ b/testsuites/sptests/spintrcritical08/init.c
> @@ -27,18 +27,14 @@ static volatile bool case_hit = false;
>
> 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(
> @@ -57,10 +53,14 @@ static rtems_timer_service_routine test_release_from_isr(
> ) {
> _Watchdog_Per_CPU_remove_relative( watchdog );
>
> + rtems_test_assert( getState() == RATE_MONOTONIC_ACTIVE );
> +
> (*watchdog->routine)( watchdog );
>
> - if ( getState() == RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING ) {
> + if ( getState() == RATE_MONOTONIC_EXPIRED ) {
> case_hit = true;
> + } else {
> + rtems_test_assert( getState() == RATE_MONOTONIC_ACTIVE );
> }
> }
> }
> --
> 1.8.4.5
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
More information about the devel
mailing list