File indexing completed on 2025-05-11 08:24:22
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
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
0060
0061 _TOD_Get_uptime( &uptime );
0062 _Timestamp_Subtract(
0063 &the_period->time_period_initiated, &uptime, wall_since_last_period
0064 );
0065
0066
0067
0068
0069 used = _Thread_Get_CPU_time_used( owning_thread );
0070
0071
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
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
0163
0164
0165
0166
0167
0168
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
0178
0179 _Rate_monotonic_Get_status( the_period, &since_last_period, &executed );
0180
0181
0182
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
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
0245
0246 _Rate_monotonic_Update_statistics( the_period );
0247
0248
0249
0250
0251
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
0280
0281
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
0292
0293
0294 the_period->state = RATE_MONOTONIC_EXPIRED;
0295
0296
0297
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
0349
0350
0351
0352
0353
0354
0355 status = _Rate_monotonic_Block_while_expired(
0356 the_period,
0357 length,
0358 executing,
0359 &lock_context
0360 );
0361 }else{
0362
0363
0364
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
0385
0386
0387
0388
0389
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 }