[5f9b3db] | 1 | /* |
---|
[e1bce86] | 2 | * Rate Monotonic Manager - Period Blocking and Status |
---|
[5f9b3db] | 3 | * |
---|
[94d9bee] | 4 | * COPYRIGHT (c) 1989-2009. |
---|
[5f9b3db] | 5 | * On-Line Applications Research Corporation (OAR). |
---|
| 6 | * |
---|
| 7 | * The license and distribution terms for this file may be |
---|
| 8 | * found in the file LICENSE in this distribution or at |
---|
[277cc95] | 9 | * http://www.rtems.com/license/LICENSE. |
---|
[5f9b3db] | 10 | * |
---|
| 11 | * $Id$ |
---|
| 12 | */ |
---|
| 13 | |
---|
[1095ec1] | 14 | #if HAVE_CONFIG_H |
---|
| 15 | #include "config.h" |
---|
| 16 | #endif |
---|
| 17 | |
---|
[5f9b3db] | 18 | #include <rtems/system.h> |
---|
| 19 | #include <rtems/rtems/status.h> |
---|
| 20 | #include <rtems/rtems/support.h> |
---|
| 21 | #include <rtems/score/isr.h> |
---|
| 22 | #include <rtems/score/object.h> |
---|
| 23 | #include <rtems/rtems/ratemon.h> |
---|
| 24 | #include <rtems/score/thread.h> |
---|
| 25 | |
---|
[eb37f9d] | 26 | bool _Rate_monotonic_Get_status( |
---|
| 27 | Rate_monotonic_Control *the_period, |
---|
| 28 | Rate_monotonic_Period_time_t *wall_since_last_period, |
---|
| 29 | Thread_CPU_usage_t *cpu_since_last_period |
---|
| 30 | ) |
---|
| 31 | { |
---|
| 32 | #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ |
---|
| 33 | Timestamp_Control uptime; |
---|
| 34 | #endif |
---|
| 35 | Thread_Control *owning_thread = the_period->owner; |
---|
| 36 | Thread_CPU_usage_t used; |
---|
| 37 | |
---|
| 38 | /* |
---|
| 39 | * Determine elapsed wall time since period initiated. |
---|
| 40 | */ |
---|
| 41 | #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ |
---|
| 42 | _TOD_Get_uptime( &uptime ); |
---|
| 43 | _Timestamp_Subtract( |
---|
| 44 | &the_period->time_period_initiated, &uptime, wall_since_last_period |
---|
| 45 | ); |
---|
| 46 | #else |
---|
| 47 | *wall_since_last_period = |
---|
| 48 | _Watchdog_Ticks_since_boot - the_period->time_period_initiated; |
---|
| 49 | #endif |
---|
| 50 | |
---|
| 51 | /* |
---|
| 52 | * Determine cpu usage since period initiated. |
---|
| 53 | */ |
---|
| 54 | used = owning_thread->cpu_time_used; |
---|
| 55 | |
---|
| 56 | #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ |
---|
| 57 | if (owning_thread == _Thread_Executing) { |
---|
| 58 | |
---|
| 59 | Thread_CPU_usage_t ran; |
---|
| 60 | |
---|
| 61 | /* How much time time since last context switch */ |
---|
| 62 | _Timestamp_Subtract( |
---|
| 63 | &_Thread_Time_of_last_context_switch, &uptime, &ran |
---|
| 64 | ); |
---|
| 65 | |
---|
| 66 | /* cpu usage += ran */ |
---|
| 67 | _Timestamp_Add_to( &used, &ran ); |
---|
| 68 | |
---|
| 69 | /* |
---|
| 70 | * The cpu usage info was reset while executing. Can't |
---|
| 71 | * determine a status. |
---|
| 72 | */ |
---|
| 73 | if (_Timestamp_Less_than(&used, &the_period->cpu_usage_period_initiated)) |
---|
| 74 | return false; |
---|
| 75 | |
---|
| 76 | /* used = current cpu usage - cpu usage at start of period */ |
---|
| 77 | _Timestamp_Subtract( |
---|
| 78 | &the_period->cpu_usage_period_initiated, |
---|
| 79 | &used, |
---|
| 80 | cpu_since_last_period |
---|
| 81 | ); |
---|
| 82 | } |
---|
| 83 | #else |
---|
| 84 | /* |
---|
| 85 | * The cpu usage info was reset while executing. Can't |
---|
| 86 | * determine a status. |
---|
| 87 | */ |
---|
| 88 | if (used < the_period->cpu_usage_period_initiated) |
---|
| 89 | return false; |
---|
| 90 | |
---|
| 91 | *cpu_since_last_period = used - the_period->cpu_usage_period_initiated; |
---|
| 92 | #endif |
---|
| 93 | return true; |
---|
| 94 | } |
---|
| 95 | |
---|
[94d9bee] | 96 | void _Rate_monotonic_Initiate_statistics( |
---|
| 97 | Rate_monotonic_Control *the_period |
---|
| 98 | ) |
---|
| 99 | { |
---|
| 100 | Thread_Control *owning_thread = the_period->owner; |
---|
| 101 | |
---|
| 102 | /* |
---|
[c6f7e060] | 103 | * If using nanosecond statistics, we need to obtain the uptime. |
---|
[94d9bee] | 104 | */ |
---|
[c6f7e060] | 105 | #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ |
---|
| 106 | Timestamp_Control uptime; |
---|
[94d9bee] | 107 | |
---|
| 108 | _TOD_Get_uptime( &uptime ); |
---|
| 109 | #endif |
---|
| 110 | |
---|
| 111 | /* |
---|
| 112 | * Set the starting point and the CPU time used for the statistics. |
---|
| 113 | */ |
---|
[c6f7e060] | 114 | #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ |
---|
[eb37f9d] | 115 | the_period->time_period_initiated = uptime; |
---|
[94d9bee] | 116 | #else |
---|
[eb37f9d] | 117 | the_period->time_period_initiated = _Watchdog_Ticks_since_boot; |
---|
[94d9bee] | 118 | #endif |
---|
| 119 | |
---|
[eb37f9d] | 120 | the_period->cpu_usage_period_initiated = owning_thread->cpu_time_used; |
---|
[94d9bee] | 121 | |
---|
| 122 | /* |
---|
[c6f7e060] | 123 | * If using nanosecond statistics and the period's thread is currently |
---|
| 124 | * executing, then we need to take into account how much time the |
---|
| 125 | * executing thread has run since the last context switch. When this |
---|
| 126 | * routine is invoked from rtems_rate_monotonic_period, the owner will |
---|
| 127 | * be the executing thread. When this routine is invoked from |
---|
| 128 | * _Rate_monotonic_Timeout, it will not. |
---|
[94d9bee] | 129 | */ |
---|
[c6f7e060] | 130 | #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ |
---|
[05c1886] | 131 | if (owning_thread == _Thread_Executing) { |
---|
[94d9bee] | 132 | |
---|
| 133 | rtems_thread_cpu_usage_t ran; |
---|
| 134 | |
---|
| 135 | /* |
---|
| 136 | * Adjust the CPU time used to account for the time since last |
---|
| 137 | * context switch. |
---|
| 138 | */ |
---|
| 139 | _Timespec_Subtract( |
---|
| 140 | &_Thread_Time_of_last_context_switch, &uptime, &ran |
---|
| 141 | ); |
---|
| 142 | |
---|
[eb37f9d] | 143 | _Timespec_Add_to( &the_period->cpu_usage_period_initiated, &ran ); |
---|
[94d9bee] | 144 | } |
---|
| 145 | #endif |
---|
| 146 | } |
---|
| 147 | |
---|
[e1bce86] | 148 | void _Rate_monotonic_Update_statistics( |
---|
| 149 | Rate_monotonic_Control *the_period |
---|
| 150 | ) |
---|
| 151 | { |
---|
[9dc2c8d] | 152 | Thread_CPU_usage_t executed; |
---|
| 153 | Rate_monotonic_Period_time_t since_last_period; |
---|
[eb37f9d] | 154 | Rate_monotonic_Statistics *stats; |
---|
| 155 | bool valid_status; |
---|
[e1bce86] | 156 | |
---|
| 157 | /* |
---|
| 158 | * Assume we are only called in states where it is appropriate |
---|
| 159 | * to update the statistics. This should only be RATE_MONOTONIC_ACTIVE |
---|
| 160 | * and RATE_MONOTONIC_EXPIRED. |
---|
| 161 | */ |
---|
| 162 | |
---|
| 163 | /* |
---|
[94d9bee] | 164 | * Update the counts. |
---|
| 165 | */ |
---|
| 166 | stats = &the_period->Statistics; |
---|
| 167 | stats->count++; |
---|
| 168 | |
---|
| 169 | if ( the_period->state == RATE_MONOTONIC_EXPIRED ) |
---|
| 170 | stats->missed_count++; |
---|
| 171 | |
---|
| 172 | /* |
---|
[eb37f9d] | 173 | * Grab status for time statistics. |
---|
[e1bce86] | 174 | */ |
---|
[eb37f9d] | 175 | valid_status = |
---|
| 176 | _Rate_monotonic_Get_status( the_period, &since_last_period, &executed ); |
---|
| 177 | if (!valid_status) |
---|
| 178 | return; |
---|
[e1bce86] | 179 | |
---|
| 180 | /* |
---|
| 181 | * Update CPU time |
---|
| 182 | */ |
---|
[c6f7e060] | 183 | #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ |
---|
[c16bcc0] | 184 | _Timestamp_Add_to( &stats->total_cpu_time, &executed ); |
---|
[c3330a8] | 185 | |
---|
[05c1886] | 186 | if ( _Timestamp_Less_than( &executed, &stats->min_cpu_time ) ) |
---|
[c3330a8] | 187 | stats->min_cpu_time = executed; |
---|
| 188 | |
---|
[05c1886] | 189 | if ( _Timestamp_Greater_than( &executed, &stats->max_cpu_time ) ) |
---|
[c3330a8] | 190 | stats->max_cpu_time = executed; |
---|
| 191 | #else |
---|
[5fa5185] | 192 | stats->total_cpu_time += executed; |
---|
[e1bce86] | 193 | |
---|
[5fa5185] | 194 | if ( executed < stats->min_cpu_time ) |
---|
| 195 | stats->min_cpu_time = executed; |
---|
[c3330a8] | 196 | |
---|
[5fa5185] | 197 | if ( executed > stats->max_cpu_time ) |
---|
| 198 | stats->max_cpu_time = executed; |
---|
[c3330a8] | 199 | #endif |
---|
[e1bce86] | 200 | |
---|
| 201 | /* |
---|
| 202 | * Update Wall time |
---|
| 203 | */ |
---|
[c6f7e060] | 204 | #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ |
---|
| 205 | _Timestamp_Add_to( &stats->total_wall_time, &since_last_period ); |
---|
[e1bce86] | 206 | |
---|
[c6f7e060] | 207 | if ( _Timestamp_Less_than( &since_last_period, &stats->min_wall_time ) ) |
---|
| 208 | stats->min_wall_time = since_last_period; |
---|
| 209 | |
---|
| 210 | if ( _Timestamp_Greater_than( &since_last_period, &stats->max_wall_time ) ) |
---|
| 211 | stats->max_wall_time = since_last_period; |
---|
| 212 | #else |
---|
[a91e372] | 213 | |
---|
| 214 | /* Sanity check wall time */ |
---|
| 215 | if ( since_last_period < executed ) |
---|
| 216 | since_last_period = executed; |
---|
| 217 | |
---|
[5fa5185] | 218 | stats->total_wall_time += since_last_period; |
---|
[c3330a8] | 219 | |
---|
[5fa5185] | 220 | if ( since_last_period < stats->min_wall_time ) |
---|
| 221 | stats->min_wall_time = since_last_period; |
---|
[c3330a8] | 222 | |
---|
[5fa5185] | 223 | if ( since_last_period > stats->max_wall_time ) |
---|
| 224 | stats->max_wall_time = since_last_period; |
---|
[c3330a8] | 225 | #endif |
---|
[e1bce86] | 226 | } |
---|
| 227 | |
---|
| 228 | |
---|
[5f9b3db] | 229 | /*PAGE |
---|
| 230 | * |
---|
| 231 | * rtems_rate_monotonic_period |
---|
| 232 | * |
---|
| 233 | * This directive allows a thread to manipulate a rate monotonic timer. |
---|
| 234 | * |
---|
| 235 | * Input parameters: |
---|
| 236 | * id - rate monotonic id |
---|
| 237 | * length - length of period (in ticks) |
---|
| 238 | * |
---|
| 239 | * Output parameters: |
---|
| 240 | * RTEMS_SUCCESSFUL - if successful |
---|
[e980b219] | 241 | * error code - if unsuccessful |
---|
[5f9b3db] | 242 | */ |
---|
| 243 | |
---|
| 244 | rtems_status_code rtems_rate_monotonic_period( |
---|
| 245 | Objects_Id id, |
---|
| 246 | rtems_interval length |
---|
| 247 | ) |
---|
| 248 | { |
---|
| 249 | Rate_monotonic_Control *the_period; |
---|
| 250 | Objects_Locations location; |
---|
| 251 | rtems_status_code return_value; |
---|
| 252 | rtems_rate_monotonic_period_states local_state; |
---|
| 253 | ISR_Level level; |
---|
| 254 | |
---|
| 255 | the_period = _Rate_monotonic_Get( id, &location ); |
---|
| 256 | |
---|
[94d9bee] | 257 | switch ( location ) { |
---|
[5f9b3db] | 258 | case OBJECTS_LOCAL: |
---|
| 259 | if ( !_Thread_Is_executing( the_period->owner ) ) { |
---|
| 260 | _Thread_Enable_dispatch(); |
---|
| 261 | return RTEMS_NOT_OWNER_OF_RESOURCE; |
---|
| 262 | } |
---|
| 263 | |
---|
| 264 | if ( length == RTEMS_PERIOD_STATUS ) { |
---|
| 265 | switch ( the_period->state ) { |
---|
| 266 | case RATE_MONOTONIC_INACTIVE: |
---|
| 267 | return_value = RTEMS_NOT_DEFINED; |
---|
| 268 | break; |
---|
| 269 | case RATE_MONOTONIC_EXPIRED: |
---|
[11c16a64] | 270 | case RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING: |
---|
[5f9b3db] | 271 | return_value = RTEMS_TIMEOUT; |
---|
| 272 | break; |
---|
[ebe61382] | 273 | case RATE_MONOTONIC_ACTIVE: |
---|
[5f9b3db] | 274 | default: /* unreached -- only to remove warnings */ |
---|
[ebe61382] | 275 | return_value = RTEMS_SUCCESSFUL; |
---|
[5f9b3db] | 276 | break; |
---|
| 277 | } |
---|
| 278 | _Thread_Enable_dispatch(); |
---|
| 279 | return( return_value ); |
---|
| 280 | } |
---|
| 281 | |
---|
| 282 | _ISR_Disable( level ); |
---|
| 283 | switch ( the_period->state ) { |
---|
[ec2078d] | 284 | case RATE_MONOTONIC_INACTIVE: { |
---|
[e1bce86] | 285 | |
---|
[5f9b3db] | 286 | _ISR_Enable( level ); |
---|
[e1bce86] | 287 | |
---|
[94d9bee] | 288 | /* |
---|
| 289 | * Baseline statistics information for the beginning of a period. |
---|
| 290 | */ |
---|
| 291 | _Rate_monotonic_Initiate_statistics( the_period ); |
---|
[c3330a8] | 292 | |
---|
[5f9b3db] | 293 | the_period->state = RATE_MONOTONIC_ACTIVE; |
---|
| 294 | _Watchdog_Initialize( |
---|
| 295 | &the_period->Timer, |
---|
| 296 | _Rate_monotonic_Timeout, |
---|
| 297 | id, |
---|
| 298 | NULL |
---|
| 299 | ); |
---|
| 300 | |
---|
[bebf0438] | 301 | the_period->next_length = length; |
---|
[5f9b3db] | 302 | |
---|
| 303 | _Watchdog_Insert_ticks( &the_period->Timer, length ); |
---|
| 304 | _Thread_Enable_dispatch(); |
---|
| 305 | return RTEMS_SUCCESSFUL; |
---|
[ec2078d] | 306 | } |
---|
[5f9b3db] | 307 | case RATE_MONOTONIC_ACTIVE: |
---|
[e1bce86] | 308 | |
---|
| 309 | /* |
---|
[94d9bee] | 310 | * Update statistics from the concluding period. |
---|
[e1bce86] | 311 | */ |
---|
| 312 | _Rate_monotonic_Update_statistics( the_period ); |
---|
| 313 | |
---|
[5f9b3db] | 314 | /* |
---|
| 315 | * This tells the _Rate_monotonic_Timeout that this task is |
---|
[bebf0438] | 316 | * in the process of blocking on the period and that we |
---|
| 317 | * may be changing the length of the next period. |
---|
[5f9b3db] | 318 | */ |
---|
| 319 | the_period->state = RATE_MONOTONIC_OWNER_IS_BLOCKING; |
---|
[bebf0438] | 320 | the_period->next_length = length; |
---|
| 321 | |
---|
[5f9b3db] | 322 | _ISR_Enable( level ); |
---|
| 323 | |
---|
| 324 | _Thread_Executing->Wait.id = the_period->Object.id; |
---|
| 325 | _Thread_Set_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD ); |
---|
[50f32b11] | 326 | |
---|
[5f9b3db] | 327 | /* |
---|
[50f32b11] | 328 | * Did the watchdog timer expire while we were actually blocking |
---|
[5f9b3db] | 329 | * on it? |
---|
| 330 | */ |
---|
| 331 | _ISR_Disable( level ); |
---|
| 332 | local_state = the_period->state; |
---|
| 333 | the_period->state = RATE_MONOTONIC_ACTIVE; |
---|
| 334 | _ISR_Enable( level ); |
---|
| 335 | |
---|
| 336 | /* |
---|
| 337 | * If it did, then we want to unblock ourself and continue as |
---|
| 338 | * if nothing happen. The period was reset in the timeout routine. |
---|
| 339 | */ |
---|
| 340 | if ( local_state == RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING ) |
---|
| 341 | _Thread_Clear_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD ); |
---|
| 342 | |
---|
| 343 | _Thread_Enable_dispatch(); |
---|
| 344 | return RTEMS_SUCCESSFUL; |
---|
| 345 | break; |
---|
| 346 | |
---|
| 347 | case RATE_MONOTONIC_EXPIRED: |
---|
[94d9bee] | 348 | |
---|
[e1bce86] | 349 | /* |
---|
| 350 | * Update statistics from the concluding period |
---|
| 351 | */ |
---|
[ba3e987e] | 352 | _Rate_monotonic_Update_statistics( the_period ); |
---|
[e1bce86] | 353 | |
---|
[5f9b3db] | 354 | _ISR_Enable( level ); |
---|
[e1bce86] | 355 | |
---|
[5f9b3db] | 356 | the_period->state = RATE_MONOTONIC_ACTIVE; |
---|
[bebf0438] | 357 | the_period->next_length = length; |
---|
[5f9b3db] | 358 | |
---|
| 359 | _Watchdog_Insert_ticks( &the_period->Timer, length ); |
---|
| 360 | _Thread_Enable_dispatch(); |
---|
| 361 | return RTEMS_TIMEOUT; |
---|
| 362 | |
---|
| 363 | case RATE_MONOTONIC_OWNER_IS_BLOCKING: |
---|
| 364 | case RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING: |
---|
| 365 | /* |
---|
| 366 | * These should never happen. |
---|
| 367 | */ |
---|
| 368 | break; |
---|
| 369 | } |
---|
[ebe61382] | 370 | |
---|
| 371 | #if defined(RTEMS_MULTIPROCESSING) |
---|
| 372 | case OBJECTS_REMOTE: /* should never return this */ |
---|
| 373 | #endif |
---|
| 374 | case OBJECTS_ERROR: |
---|
| 375 | break; |
---|
[5f9b3db] | 376 | } |
---|
| 377 | |
---|
[ebe61382] | 378 | return RTEMS_INVALID_ID; |
---|
[5f9b3db] | 379 | } |
---|