source: rtems/cpukit/rtems/src/ratemonperiod.c @ 9e162be9

4.11
Last change on this file since 9e162be9 was 9e162be9, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 19, 2011 at 7:25:10 AM

2011-10-18 Sebastian Huber <sebastian.huber@…>

PR 1939/cpukit

  • rtems/src/ratemonperiod.c: Fixed type mismatch.
  • Property mode set to 100644
File size: 10.4 KB
Line 
1/*
2 *  Rate Monotonic Manager - Period Blocking and Status
3 *
4 *  COPYRIGHT (c) 1989-2010.
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
9 *  http://www.rtems.com/license/LICENSE.
10 *
11 *  $Id$
12 */
13
14#if HAVE_CONFIG_H
15#include "config.h"
16#endif
17
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
26bool _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
96void _Rate_monotonic_Initiate_statistics(
97  Rate_monotonic_Control *the_period
98)
99{
100  Thread_Control *owning_thread = the_period->owner;
101
102  /*
103   *  If using nanosecond statistics, we need to obtain the uptime.
104   */
105  #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
106    Timestamp_Control  uptime;
107
108    _TOD_Get_uptime( &uptime );
109  #endif
110
111  /*
112   *  Set the starting point and the CPU time used for the statistics.
113   */
114  #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
115    the_period->time_period_initiated = uptime;
116  #else
117    the_period->time_period_initiated = _Watchdog_Ticks_since_boot;
118  #endif
119
120  the_period->cpu_usage_period_initiated = owning_thread->cpu_time_used;
121
122  /*
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.
129   */
130  #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
131    if (owning_thread == _Thread_Executing) {
132      Timestamp_Control ran;
133
134      /*
135       *  Adjust the CPU time used to account for the time since last
136       *  context switch.
137       */
138      _Timestamp_Subtract(
139        &_Thread_Time_of_last_context_switch, &uptime, &ran
140      );
141
142      _Timestamp_Add_to( &the_period->cpu_usage_period_initiated, &ran );
143    }
144  #endif
145
146  _Scheduler_Release_job(the_period->owner, the_period->next_length);
147}
148
149void _Rate_monotonic_Update_statistics(
150  Rate_monotonic_Control    *the_period
151)
152{
153  Thread_CPU_usage_t              executed;
154  Rate_monotonic_Period_time_t    since_last_period;
155  Rate_monotonic_Statistics      *stats;
156  bool                            valid_status;
157
158  /*
159   *  Assume we are only called in states where it is appropriate
160   *  to update the statistics.  This should only be RATE_MONOTONIC_ACTIVE
161   *  and RATE_MONOTONIC_EXPIRED.
162   */
163
164  /*
165   *  Update the counts.
166   */
167  stats = &the_period->Statistics;
168  stats->count++;
169
170  if ( the_period->state == RATE_MONOTONIC_EXPIRED )
171    stats->missed_count++;
172
173  /*
174   *  Grab status for time statistics.
175   */
176  valid_status =
177    _Rate_monotonic_Get_status( the_period, &since_last_period, &executed );
178  if (!valid_status)
179    return;
180
181  /*
182   *  Update CPU time
183   */
184  #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
185    _Timestamp_Add_to( &stats->total_cpu_time, &executed );
186
187    if ( _Timestamp_Less_than( &executed, &stats->min_cpu_time ) )
188      stats->min_cpu_time = executed;
189
190    if ( _Timestamp_Greater_than( &executed, &stats->max_cpu_time ) )
191      stats->max_cpu_time = executed;
192  #else
193    stats->total_cpu_time  += executed;
194
195    if ( executed < stats->min_cpu_time )
196      stats->min_cpu_time = executed;
197
198    if ( executed > stats->max_cpu_time )
199      stats->max_cpu_time = executed;
200  #endif
201
202  /*
203   *  Update Wall time
204   */
205  #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
206    _Timestamp_Add_to( &stats->total_wall_time, &since_last_period );
207
208    if ( _Timestamp_Less_than( &since_last_period, &stats->min_wall_time ) )
209      stats->min_wall_time = since_last_period;
210
211    if ( _Timestamp_Greater_than( &since_last_period, &stats->max_wall_time ) )
212      stats->max_wall_time = since_last_period;
213  #else
214
215    /* Sanity check wall time */
216    if ( since_last_period < executed )
217      since_last_period = executed;
218
219    stats->total_wall_time += since_last_period;
220
221    if ( since_last_period < stats->min_wall_time )
222      stats->min_wall_time = since_last_period;
223
224    if ( since_last_period > stats->max_wall_time )
225      stats->max_wall_time = since_last_period;
226  #endif
227}
228
229
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
241 *    error code       - if unsuccessful
242 */
243
244rtems_status_code rtems_rate_monotonic_period(
245  rtems_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
257  switch ( location ) {
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:
270          case RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING:
271            return_value = RTEMS_TIMEOUT;
272            break;
273          case RATE_MONOTONIC_ACTIVE:
274          default:              /* unreached -- only to remove warnings */
275            return_value = RTEMS_SUCCESSFUL;
276            break;
277        }
278        _Thread_Enable_dispatch();
279        return( return_value );
280      }
281
282      _ISR_Disable( level );
283      if ( the_period->state == RATE_MONOTONIC_INACTIVE ) {
284        _ISR_Enable( level );
285
286        the_period->next_length = length;
287
288        /*
289         *  Baseline statistics information for the beginning of a period.
290         */
291        _Rate_monotonic_Initiate_statistics( the_period );
292
293        the_period->state = RATE_MONOTONIC_ACTIVE;
294        _Watchdog_Initialize(
295          &the_period->Timer,
296          _Rate_monotonic_Timeout,
297          id,
298          NULL
299        );
300
301        _Watchdog_Insert_ticks( &the_period->Timer, length );
302        _Thread_Enable_dispatch();
303        return RTEMS_SUCCESSFUL;
304      }
305
306      if ( the_period->state == RATE_MONOTONIC_ACTIVE ) {
307        /*
308         *  Update statistics from the concluding period.
309         */
310        _Rate_monotonic_Update_statistics( the_period );
311
312        /*
313         *  This tells the _Rate_monotonic_Timeout that this task is
314         *  in the process of blocking on the period and that we
315         *  may be changing the length of the next period.
316         */
317        the_period->state = RATE_MONOTONIC_OWNER_IS_BLOCKING;
318        the_period->next_length = length;
319
320        _ISR_Enable( level );
321
322        _Thread_Executing->Wait.id = the_period->Object.id;
323        _Thread_Set_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD );
324
325        /*
326         *  Did the watchdog timer expire while we were actually blocking
327         *  on it?
328         */
329        _ISR_Disable( level );
330          local_state = the_period->state;
331          the_period->state = RATE_MONOTONIC_ACTIVE;
332        _ISR_Enable( level );
333
334        /*
335         *  If it did, then we want to unblock ourself and continue as
336         *  if nothing happen.  The period was reset in the timeout routine.
337         */
338        if ( local_state == RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING )
339          _Thread_Clear_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD );
340
341        _Thread_Enable_dispatch();
342        return RTEMS_SUCCESSFUL;
343      }
344
345      if ( the_period->state == RATE_MONOTONIC_EXPIRED ) {
346        /*
347         *  Update statistics from the concluding period
348         */
349        _Rate_monotonic_Update_statistics( the_period );
350
351        _ISR_Enable( level );
352
353        the_period->state = RATE_MONOTONIC_ACTIVE;
354        the_period->next_length = length;
355
356        _Watchdog_Insert_ticks( &the_period->Timer, length );
357        _Scheduler_Release_job(the_period->owner, the_period->next_length);
358        _Thread_Enable_dispatch();
359        return RTEMS_TIMEOUT;
360      }
361
362      /*
363       *  These should never happen so just return invalid Id.
364       *    - RATE_MONOTONIC_OWNER_IS_BLOCKING:
365       *    - RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING:
366       */
367#if defined(RTEMS_MULTIPROCESSING)
368    case OBJECTS_REMOTE:            /* should never return this */
369#endif
370    case OBJECTS_ERROR:
371      break;
372  }
373
374  return RTEMS_INVALID_ID;
375}
Note: See TracBrowser for help on using the repository browser.