Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:22

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSImplClassicRateMonotonic
0007  *
0008  * @brief This source file contains the implementation of
0009  *   rtems_rate_monotonic_period_states().
0010  */
0011 
0012 /*
0013  *  COPYRIGHT (c) 1989-2010.
0014  *  On-Line Applications Research Corporation (OAR).
0015  *  Copyright (c) 2016 embedded brains GmbH & Co. KG
0016  *  COPYRIGHT (c) 2016 Kuan-Hsun Chen.
0017  *
0018  * Redistribution and use in source and binary forms, with or without
0019  * modification, are permitted provided that the following conditions
0020  * are met:
0021  * 1. Redistributions of source code must retain the above copyright
0022  *    notice, this list of conditions and the following disclaimer.
0023  * 2. Redistributions in binary form must reproduce the above copyright
0024  *    notice, this list of conditions and the following disclaimer in the
0025  *    documentation and/or other materials provided with the distribution.
0026  *
0027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0028  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0030  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0031  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0032  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0033  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0034  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0035  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0036  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0037  * POSSIBILITY OF SUCH DAMAGE.
0038  */
0039 
0040 #ifdef HAVE_CONFIG_H
0041 #include "config.h"
0042 #endif
0043 
0044 #include <rtems/rtems/ratemonimpl.h>
0045 #include <rtems/score/schedulerimpl.h>
0046 #include <rtems/score/todimpl.h>
0047 
0048 void _Rate_monotonic_Get_status(
0049   const Rate_monotonic_Control *the_period,
0050   Timestamp_Control            *wall_since_last_period,
0051   Timestamp_Control            *cpu_since_last_period
0052 )
0053 {
0054   Timestamp_Control        uptime;
0055   Thread_Control          *owning_thread = the_period->owner;
0056   Timestamp_Control        used;
0057 
0058   /*
0059    *  Determine elapsed wall time since period initiated.
0060    */
0061   _TOD_Get_uptime( &uptime );
0062   _Timestamp_Subtract(
0063     &the_period->time_period_initiated, &uptime, wall_since_last_period
0064   );
0065 
0066   /*
0067    *  Determine cpu usage since period initiated.
0068    */
0069   used = _Thread_Get_CPU_time_used( owning_thread );
0070 
0071    /* used = current cpu usage - cpu usage at start of period */
0072   _Timestamp_Subtract(
0073     &the_period->cpu_usage_period_initiated,
0074     &used,
0075     cpu_since_last_period
0076   );
0077 }
0078 
0079 static void _Rate_monotonic_Release_postponed_job(
0080   Rate_monotonic_Control *the_period,
0081   Thread_Control         *owner,
0082   rtems_interval          next_length,
0083   ISR_lock_Context       *lock_context
0084 )
0085 {
0086   Per_CPU_Control      *cpu_self;
0087   Thread_queue_Context  queue_context;
0088 
0089   --the_period->postponed_jobs;
0090   _Scheduler_Release_job(
0091     owner,
0092     &the_period->Priority,
0093     the_period->latest_deadline,
0094     &queue_context
0095   );
0096 
0097   cpu_self = _Thread_Dispatch_disable_critical( lock_context );
0098   _Rate_monotonic_Release( the_period, lock_context );
0099   _Thread_Priority_update( &queue_context );
0100   _Thread_Dispatch_direct( cpu_self );
0101 }
0102 
0103 static void _Rate_monotonic_Release_job(
0104   Rate_monotonic_Control *the_period,
0105   Thread_Control         *owner,
0106   rtems_interval          next_length,
0107   ISR_lock_Context       *lock_context
0108 )
0109 {
0110   Per_CPU_Control      *cpu_self;
0111   Thread_queue_Context  queue_context;
0112   uint64_t              deadline;
0113 
0114   cpu_self = _Thread_Dispatch_disable_critical( lock_context );
0115 
0116   deadline = _Watchdog_Per_CPU_insert_ticks(
0117     &the_period->Timer,
0118     cpu_self,
0119     next_length
0120   );
0121   _Scheduler_Release_job(
0122     owner,
0123     &the_period->Priority,
0124     deadline,
0125     &queue_context
0126   );
0127 
0128   _Rate_monotonic_Release( the_period, lock_context );
0129   _Thread_Priority_update( &queue_context );
0130   _Thread_Dispatch_enable( cpu_self );
0131 }
0132 
0133 void _Rate_monotonic_Restart(
0134   Rate_monotonic_Control *the_period,
0135   Thread_Control         *owner,
0136   ISR_lock_Context       *lock_context
0137 )
0138 {
0139   /*
0140    *  Set the starting point and the CPU time used for the statistics.
0141    */
0142   _TOD_Get_uptime( &the_period->time_period_initiated );
0143   the_period->cpu_usage_period_initiated = _Thread_Get_CPU_time_used( owner );
0144 
0145   _Rate_monotonic_Release_job(
0146     the_period,
0147     owner,
0148     the_period->next_length,
0149     lock_context
0150   );
0151 }
0152 
0153 static void _Rate_monotonic_Update_statistics(
0154   Rate_monotonic_Control    *the_period
0155 )
0156 {
0157   Timestamp_Control          executed;
0158   Timestamp_Control          since_last_period;
0159   Rate_monotonic_Statistics *stats;
0160 
0161   /*
0162    *  Assume we are only called in states where it is appropriate
0163    *  to update the statistics.  This should only be RATE_MONOTONIC_ACTIVE
0164    *  and RATE_MONOTONIC_EXPIRED.
0165    */
0166 
0167   /*
0168    *  Update the counts.
0169    */
0170   stats = &the_period->Statistics;
0171   stats->count++;
0172 
0173   if ( the_period->state == RATE_MONOTONIC_EXPIRED )
0174     stats->missed_count++;
0175 
0176   /*
0177    *  Grab status for time statistics.
0178    */
0179   _Rate_monotonic_Get_status( the_period, &since_last_period, &executed );
0180 
0181   /*
0182    *  Update CPU time
0183    */
0184   _Timestamp_Add_to( &stats->total_cpu_time, &executed );
0185 
0186   if ( _Timestamp_Less_than( &executed, &stats->min_cpu_time ) )
0187     stats->min_cpu_time = executed;
0188 
0189   if ( _Timestamp_Greater_than( &executed, &stats->max_cpu_time ) )
0190     stats->max_cpu_time = executed;
0191 
0192   /*
0193    *  Update Wall time
0194    */
0195   _Timestamp_Add_to( &stats->total_wall_time, &since_last_period );
0196 
0197   if ( _Timestamp_Less_than( &since_last_period, &stats->min_wall_time ) )
0198     stats->min_wall_time = since_last_period;
0199 
0200   if ( _Timestamp_Greater_than( &since_last_period, &stats->max_wall_time ) )
0201     stats->max_wall_time = since_last_period;
0202 }
0203 
0204 static rtems_status_code _Rate_monotonic_Get_status_for_state(
0205   rtems_rate_monotonic_period_states state
0206 )
0207 {
0208   switch ( state ) {
0209     case RATE_MONOTONIC_INACTIVE:
0210       return RTEMS_NOT_DEFINED;
0211     case RATE_MONOTONIC_EXPIRED:
0212       return RTEMS_TIMEOUT;
0213     default:
0214       _Assert( state == RATE_MONOTONIC_ACTIVE );
0215       return RTEMS_SUCCESSFUL;
0216   }
0217 }
0218 
0219 static rtems_status_code _Rate_monotonic_Activate(
0220   Rate_monotonic_Control *the_period,
0221   rtems_interval          length,
0222   Thread_Control         *executing,
0223   ISR_lock_Context       *lock_context
0224 )
0225 {
0226   _Assert( the_period->postponed_jobs == 0 );
0227   the_period->state = RATE_MONOTONIC_ACTIVE;
0228   the_period->next_length = length;
0229   _Rate_monotonic_Restart( the_period, executing, lock_context );
0230   return RTEMS_SUCCESSFUL;
0231 }
0232 
0233 static rtems_status_code _Rate_monotonic_Block_while_active(
0234   Rate_monotonic_Control *the_period,
0235   rtems_interval          length,
0236   Thread_Control         *executing,
0237   ISR_lock_Context       *lock_context
0238 )
0239 {
0240   Per_CPU_Control *cpu_self;
0241   bool             success;
0242 
0243   /*
0244    *  Update statistics from the concluding period.
0245    */
0246   _Rate_monotonic_Update_statistics( the_period );
0247 
0248   /*
0249    *  This tells the _Rate_monotonic_Timeout that this task is
0250    *  in the process of blocking on the period and that we
0251    *  may be changing the length of the next period.
0252    */
0253   the_period->next_length = length;
0254   executing->Wait.return_argument = the_period;
0255   _Thread_Wait_flags_set( executing, RATE_MONOTONIC_INTEND_TO_BLOCK );
0256 
0257   cpu_self = _Thread_Dispatch_disable_critical( lock_context );
0258   _Rate_monotonic_Release( the_period, lock_context );
0259 
0260   _Thread_Set_state( executing, STATES_WAITING_FOR_PERIOD );
0261 
0262   success = _Thread_Wait_flags_try_change_acquire(
0263     executing,
0264     RATE_MONOTONIC_INTEND_TO_BLOCK,
0265     RATE_MONOTONIC_BLOCKED
0266   );
0267   if ( !success ) {
0268     _Assert(
0269       _Thread_Wait_flags_get( executing ) == THREAD_WAIT_STATE_READY
0270     );
0271     _Thread_Unblock( executing );
0272   }
0273 
0274   _Thread_Dispatch_direct( cpu_self );
0275   return RTEMS_SUCCESSFUL;
0276 }
0277 
0278 /*
0279  * There are two possible cases: one is that the previous deadline is missed,
0280  * The other is that the number of postponed jobs is not 0, but the current
0281  * deadline is still not expired, i.e., state = RATE_MONOTONIC_ACTIVE.
0282  */
0283 static rtems_status_code _Rate_monotonic_Block_while_expired(
0284   Rate_monotonic_Control *the_period,
0285   rtems_interval          length,
0286   Thread_Control         *executing,
0287   ISR_lock_Context       *lock_context
0288 )
0289 {
0290   /*
0291    * No matter the just finished jobs in time or not,
0292    * they are actually missing their deadlines already.
0293    */
0294   the_period->state = RATE_MONOTONIC_EXPIRED;
0295 
0296   /*
0297    * Update statistics from the concluding period
0298    */
0299   _Rate_monotonic_Update_statistics( the_period );
0300 
0301   the_period->state = RATE_MONOTONIC_ACTIVE;
0302   the_period->next_length = length;
0303 
0304   _Rate_monotonic_Release_postponed_job(
0305       the_period,
0306       executing,
0307       length,
0308       lock_context
0309   );
0310   return RTEMS_TIMEOUT;
0311 }
0312 
0313 rtems_status_code rtems_rate_monotonic_period(
0314   rtems_id       id,
0315   rtems_interval length
0316 )
0317 {
0318   Rate_monotonic_Control            *the_period;
0319   ISR_lock_Context                   lock_context;
0320   Thread_Control                    *executing;
0321   rtems_status_code                  status;
0322   rtems_rate_monotonic_period_states state;
0323 
0324   the_period = _Rate_monotonic_Get( id, &lock_context );
0325   if ( the_period == NULL ) {
0326     return RTEMS_INVALID_ID;
0327   }
0328 
0329   executing = _Thread_Executing;
0330   if ( executing != the_period->owner ) {
0331     _ISR_lock_ISR_enable( &lock_context );
0332     return RTEMS_NOT_OWNER_OF_RESOURCE;
0333   }
0334 
0335   _Rate_monotonic_Acquire_critical( the_period, &lock_context );
0336 
0337   state = the_period->state;
0338 
0339   if ( length == RTEMS_PERIOD_STATUS ) {
0340     status = _Rate_monotonic_Get_status_for_state( state );
0341     _Rate_monotonic_Release( the_period, &lock_context );
0342   } else {
0343     switch ( state ) {
0344       case RATE_MONOTONIC_ACTIVE:
0345 
0346         if( the_period->postponed_jobs > 0 ){
0347           /*
0348            * If the number of postponed jobs is not 0, it means the
0349            * previous postponed instance is finished without exceeding
0350            * the current period deadline.
0351            *
0352            * Do nothing on the watchdog deadline assignment but release the
0353            * next remaining postponed job.
0354            */
0355           status = _Rate_monotonic_Block_while_expired(
0356             the_period,
0357             length,
0358             executing,
0359             &lock_context
0360           );
0361         }else{
0362           /*
0363            * Normal case that no postponed jobs and no expiration, so wait for
0364            * the period and update the deadline of watchdog accordingly.
0365            */
0366           status = _Rate_monotonic_Block_while_active(
0367             the_period,
0368             length,
0369             executing,
0370             &lock_context
0371           );
0372         }
0373         break;
0374       case RATE_MONOTONIC_INACTIVE:
0375         status = _Rate_monotonic_Activate(
0376           the_period,
0377           length,
0378           executing,
0379           &lock_context
0380         );
0381         break;
0382       default:
0383         /*
0384          * As now this period was already TIMEOUT, there must be at least one
0385          * postponed job recorded by the watchdog. The one which exceeded
0386          * the previous deadlines was just finished.
0387          *
0388          * Maybe there is more than one job postponed due to the preemption or
0389          * the previous finished job.
0390          */
0391         _Assert( state == RATE_MONOTONIC_EXPIRED );
0392         status = _Rate_monotonic_Block_while_expired(
0393           the_period,
0394           length,
0395           executing,
0396           &lock_context
0397         );
0398         break;
0399     }
0400   }
0401 
0402   return status;
0403 }