[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