[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