[PATCH] rtems: Rework rate-monotonic scheduler

Sebastian Huber sebastian.huber at embedded-brains.de
Mon Mar 21 14:40:46 UTC 2016


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



More information about the devel mailing list