summaryrefslogtreecommitdiffstats
path: root/cpukit/rtems/src/ratemonperiod.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-03-21 15:01:57 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2016-03-22 07:05:05 +0100
commit90960bd11a91259d9aace3870692dbe2e227de0f (patch)
tree3d88f8bc3d1fe17252e8290cadae2afb4a38ce4b /cpukit/rtems/src/ratemonperiod.c
parentrtems: Avoid __RTEMS_USE_TICKS_FOR_STATISTICS__ (diff)
downloadrtems-90960bd11a91259d9aace3870692dbe2e227de0f.tar.bz2
rtems: Rework rate-monotonic scheduler
Use the default thread lock to protect rate-monotonic state changes. This avoids use of the Giant lock. Split rtems_rate_monotonic_period() body into several static functions. Introduce a new thread wait class THREAD_WAIT_CLASS_PERIOD for period objects to synchronize the blocking operation. Close #2631.
Diffstat (limited to 'cpukit/rtems/src/ratemonperiod.c')
-rw-r--r--cpukit/rtems/src/ratemonperiod.c310
1 files changed, 180 insertions, 130 deletions
diff --git a/cpukit/rtems/src/ratemonperiod.c b/cpukit/rtems/src/ratemonperiod.c
index e03d8cff09..1a1373117b 100644
--- a/cpukit/rtems/src/ratemonperiod.c
+++ b/cpukit/rtems/src/ratemonperiod.c
@@ -8,6 +8,7 @@
/*
* COPYRIGHT (c) 1989-2010.
* On-Line Applications Research Corporation (OAR).
+ * Copyright (c) 2016 embedded brains GmbH.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -20,9 +21,7 @@
#include <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,156 @@ static void _Rate_monotonic_Update_statistics(
stats->max_wall_time = since_last_period;
}
+static rtems_status_code _Rate_monotonic_Get_status_for_state(
+ rtems_rate_monotonic_period_states state
+)
+{
+ switch ( state ) {
+ case RATE_MONOTONIC_INACTIVE:
+ return RTEMS_NOT_DEFINED;
+ case RATE_MONOTONIC_EXPIRED:
+ return RTEMS_TIMEOUT;
+ default:
+ _Assert( state == RATE_MONOTONIC_ACTIVE );
+ return RTEMS_SUCCESSFUL;
+ }
+}
+
+static rtems_status_code _Rate_monotonic_Activate(
+ Rate_monotonic_Control *the_period,
+ rtems_interval length,
+ Thread_Control *executing,
+ ISR_lock_Context *lock_context
+)
+{
+ the_period->state = RATE_MONOTONIC_ACTIVE;
+ the_period->next_length = length;
+ _Rate_monotonic_Restart( the_period, executing, lock_context );
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_status_code _Rate_monotonic_Block_while_active(
+ Rate_monotonic_Control *the_period,
+ rtems_interval length,
+ Thread_Control *executing,
+ ISR_lock_Context *lock_context
+)
+{
+ Per_CPU_Control *cpu_self;
+ bool success;
+
+ /*
+ * Update statistics from the concluding period.
+ */
+ _Rate_monotonic_Update_statistics( the_period );
+
+ /*
+ * This tells the _Rate_monotonic_Timeout that this task is
+ * in the process of blocking on the period and that we
+ * may be changing the length of the next period.
+ */
+ the_period->next_length = length;
+ executing->Wait.return_argument = the_period;
+ _Thread_Wait_flags_set( executing, RATE_MONOTONIC_INTEND_TO_BLOCK );
+
+ cpu_self = _Thread_Dispatch_disable_critical( lock_context );
+ _Rate_monotonic_Release( executing, lock_context );
+
+ _Thread_Set_state( executing, STATES_WAITING_FOR_PERIOD );
+
+ success = _Thread_Wait_flags_try_change(
+ executing,
+ RATE_MONOTONIC_INTEND_TO_BLOCK,
+ RATE_MONOTONIC_BLOCKED
+ );
+ if ( !success ) {
+ _Assert(
+ _Thread_Wait_flags_get( executing ) == RATE_MONOTONIC_READY_AGAIN
+ );
+ _Thread_Unblock( executing );
+ }
+
+ _Thread_Dispatch_enable( cpu_self );
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_status_code _Rate_monotonic_Block_while_expired(
+ Rate_monotonic_Control *the_period,
+ rtems_interval length,
+ Thread_Control *executing,
+ ISR_lock_Context *lock_context
+)
+{
+ /*
+ * Update statistics from the concluding period
+ */
+ _Rate_monotonic_Update_statistics( the_period );
+
+ the_period->state = RATE_MONOTONIC_ACTIVE;
+ the_period->next_length = length;
+
+ _Rate_monotonic_Release_job( the_period, executing, length, lock_context );
+ return RTEMS_TIMEOUT;
+}
+
rtems_status_code rtems_rate_monotonic_period(
rtems_id id,
rtems_interval length
)
{
- Rate_monotonic_Control *the_period;
- Objects_Locations location;
- rtems_status_code return_value;
- rtems_rate_monotonic_period_states local_state;
- ISR_Level level;
-
- the_period = _Rate_monotonic_Get( id, &location );
-
- switch ( location ) {
- case OBJECTS_LOCAL:
- if ( !_Thread_Is_executing( the_period->owner ) ) {
- _Objects_Put( &the_period->Object );
- return RTEMS_NOT_OWNER_OF_RESOURCE;
- }
-
- if ( length == RTEMS_PERIOD_STATUS ) {
- switch ( the_period->state ) {
- case RATE_MONOTONIC_INACTIVE:
- return_value = RTEMS_NOT_DEFINED;
- break;
- case RATE_MONOTONIC_EXPIRED:
- case RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING:
- return_value = RTEMS_TIMEOUT;
- break;
- case RATE_MONOTONIC_ACTIVE:
- default: /* unreached -- only to remove warnings */
- return_value = RTEMS_SUCCESSFUL;
- break;
- }
- _Objects_Put( &the_period->Object );
- return( return_value );
- }
-
- _ISR_Disable( level );
- if ( the_period->state == RATE_MONOTONIC_INACTIVE ) {
- _ISR_Enable( level );
-
- the_period->state = RATE_MONOTONIC_ACTIVE;
- the_period->next_length = length;
- _Rate_monotonic_Restart( the_period );
- _Objects_Put( &the_period->Object );
- return RTEMS_SUCCESSFUL;
- }
-
- if ( the_period->state == RATE_MONOTONIC_ACTIVE ) {
- /*
- * Update statistics from the concluding period.
- */
- _Rate_monotonic_Update_statistics( the_period );
-
- /*
- * This tells the _Rate_monotonic_Timeout that this task is
- * in the process of blocking on the period and that we
- * may be changing the length of the next period.
- */
- the_period->state = RATE_MONOTONIC_OWNER_IS_BLOCKING;
- the_period->next_length = length;
-
- _ISR_Enable( level );
-
- _Thread_Executing->Wait.id = the_period->Object.id;
- _Thread_Set_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD );
-
- /*
- * Did the watchdog timer expire while we were actually blocking
- * on it?
- */
- _ISR_Disable( level );
- local_state = the_period->state;
- the_period->state = RATE_MONOTONIC_ACTIVE;
- _ISR_Enable( level );
-
- /*
- * If it did, then we want to unblock ourself and continue as
- * if nothing happen. The period was reset in the timeout routine.
- */
- if ( local_state == RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING )
- _Thread_Clear_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD );
-
- _Objects_Put( &the_period->Object );
- return RTEMS_SUCCESSFUL;
- }
-
- if ( the_period->state == RATE_MONOTONIC_EXPIRED ) {
- /*
- * Update statistics from the concluding period
- */
- _Rate_monotonic_Update_statistics( the_period );
-
- _ISR_Enable( level );
-
- the_period->state = RATE_MONOTONIC_ACTIVE;
- the_period->next_length = length;
-
- _Watchdog_Per_CPU_insert_relative(
- &the_period->Timer,
- _Per_CPU_Get(),
- length
+ Rate_monotonic_Control *the_period;
+ ISR_lock_Context lock_context;
+ Thread_Control *executing;
+ rtems_status_code status;
+ rtems_rate_monotonic_period_states state;
+
+ the_period = _Rate_monotonic_Get( id, &lock_context );
+ if ( the_period == NULL ) {
+ return RTEMS_INVALID_ID;
+ }
+
+ executing = _Thread_Executing;
+ if ( executing != the_period->owner ) {
+ _ISR_lock_ISR_enable( &lock_context );
+ return RTEMS_NOT_OWNER_OF_RESOURCE;
+ }
+
+ _Rate_monotonic_Acquire_critical( executing, &lock_context );
+
+ state = the_period->state;
+
+ if ( length == RTEMS_PERIOD_STATUS ) {
+ status = _Rate_monotonic_Get_status_for_state( state );
+ _Rate_monotonic_Release( executing, &lock_context );
+ } else {
+ switch ( state ) {
+ case RATE_MONOTONIC_ACTIVE:
+ status = _Rate_monotonic_Block_while_active(
+ the_period,
+ length,
+ executing,
+ &lock_context
);
- _Scheduler_Release_job( the_period->owner, the_period->next_length );
- _Objects_Put( &the_period->Object );
- return RTEMS_TIMEOUT;
- }
-
- /*
- * These should never happen so just return invalid Id.
- * - RATE_MONOTONIC_OWNER_IS_BLOCKING:
- * - RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING:
- */
-#if defined(RTEMS_MULTIPROCESSING)
- case OBJECTS_REMOTE: /* should never return this */
-#endif
- case OBJECTS_ERROR:
- break;
+ break;
+ case RATE_MONOTONIC_INACTIVE:
+ status = _Rate_monotonic_Activate(
+ the_period,
+ length,
+ executing,
+ &lock_context
+ );
+ break;
+ default:
+ _Assert( state == RATE_MONOTONIC_EXPIRED );
+ status = _Rate_monotonic_Block_while_expired(
+ the_period,
+ length,
+ executing,
+ &lock_context
+ );
+ break;
+ }
}
- return RTEMS_INVALID_ID;
+ return status;
}