source: rtems/cpukit/rtems/src/ratemonperiod.c @ 05c1886

4.104.115
Last change on this file since 05c1886 was 05c1886, checked in by Ralf Corsepius <ralf.corsepius@…>, on 11/30/09 at 16:01:51

Whitespace removal.

  • Property mode set to 100644
File size: 10.1 KB
Line 
1/*
2 *  Rate Monotonic Manager - Period Blocking and Status
3 *
4 *  COPYRIGHT (c) 1989-2009.
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
26void _Rate_monotonic_Initiate_statistics(
27  Rate_monotonic_Control *the_period
28)
29{
30  Thread_Control *owning_thread = the_period->owner;
31
32  /*
33   *  If any statistics are at nanosecond granularity, we need to
34   *  obtain the uptime.
35   */
36  #if defined(RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS) || \
37      defined(RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS)
38
39    struct timespec  uptime;
40
41    _TOD_Get_uptime( &uptime );
42  #endif
43
44  /*
45   *  Set the starting point and the CPU time used for the statistics.
46   */
47  #ifdef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
48    the_period->time_at_period = uptime;
49  #else
50    the_period->time_at_period = _Watchdog_Ticks_since_boot;
51  #endif
52
53  the_period->owner_executed_at_period = owning_thread->cpu_time_used;
54
55  /*
56   *  If using nanosecond granularity for CPU Usage Statistics and the
57   *  period's thread is currently executing, then we need to take into
58   *  account how much time the executing thread has run since the last
59   *  context switch.  When this routine is invoked from
60   *  rtems_rate_monotonic_period, the owner will be the executing thread.
61   *  When this routine is invoked from _Rate_monotonic_Timeout, it will not.
62   */
63  #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
64    if (owning_thread == _Thread_Executing) {
65
66      rtems_thread_cpu_usage_t ran;
67
68      /*
69       *  Adjust the CPU time used to account for the time since last
70       *  context switch.
71       */
72      _Timespec_Subtract(
73        &_Thread_Time_of_last_context_switch, &uptime, &ran
74      );
75
76      _Timespec_Add_to( &the_period->owner_executed_at_period, &ran );
77    }
78  #endif
79}
80
81void _Rate_monotonic_Update_statistics(
82  Rate_monotonic_Control    *the_period
83)
84{
85  Rate_monotonic_Statistics      *stats;
86  Thread_CPU_usage_t              executed;
87  Rate_monotonic_Period_time_t    since_last_period;
88  #if defined(RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS) || \
89      defined(RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS)
90    Timestamp_Control             uptime;
91
92    /*
93     * Obtain the current time since boot
94     */
95    _TOD_Get_uptime( &uptime );
96  #endif
97
98  /*
99   *  Assume we are only called in states where it is appropriate
100   *  to update the statistics.  This should only be RATE_MONOTONIC_ACTIVE
101   *  and RATE_MONOTONIC_EXPIRED.
102   */
103
104  /*
105   *  Update the counts.
106   */
107  stats = &the_period->Statistics;
108  stats->count++;
109
110  if ( the_period->state == RATE_MONOTONIC_EXPIRED )
111    stats->missed_count++;
112
113  /*
114   *  Grab basic information for time statistics.
115   */
116  #ifdef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
117    _Timespec_Subtract(
118      &the_period->time_at_period,
119      &uptime,
120      &since_last_period
121    );
122  #else
123    since_last_period = _Watchdog_Ticks_since_boot - the_period->time_at_period;
124  #endif
125
126  #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
127    {
128      Thread_CPU_usage_t ran, used;
129
130      /* Grab CPU usage when the thread got switched in */
131      used = _Thread_Executing->cpu_time_used;
132
133      /* partial period, cpu usage info reset while executing.  Throw away */
134      if (_Timestamp_Less_than( &used, &the_period->owner_executed_at_period))
135        return;
136
137      /* How much time time since last context switch */
138      _Timestamp_Subtract(&_Thread_Time_of_last_context_switch, &uptime, &ran);
139
140      /* executed += ran */
141      _Timestamp_Add_to( &used, &ran );
142
143       /* executed = current cpu usage - value at start of period */
144      _Timestamp_Subtract(
145         &the_period->owner_executed_at_period,
146         &used,
147         &executed
148      );
149    }
150  #else
151      /* partial period, cpu usage info reset while executing.  Throw away */
152      if (the_period->owner->cpu_time_used <
153          the_period->owner_executed_at_period)
154        return;
155      executed = the_period->owner->cpu_time_used -
156        the_period->owner_executed_at_period;
157  #endif
158
159  /*
160   *  Update CPU time
161   */
162
163  #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
164    _Timestamp_Add_to( &stats->total_cpu_time, &executed );
165
166    if ( _Timestamp_Less_than( &executed, &stats->min_cpu_time ) )
167      stats->min_cpu_time = executed;
168
169    if ( _Timestamp_Greater_than( &executed, &stats->max_cpu_time ) )
170      stats->max_cpu_time = executed;
171  #else
172    stats->total_cpu_time  += executed;
173
174    if ( executed < stats->min_cpu_time )
175      stats->min_cpu_time = executed;
176
177    if ( executed > stats->max_cpu_time )
178      stats->max_cpu_time = executed;
179  #endif
180
181  /*
182   *  Update Wall time
183   */
184
185  #ifndef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
186
187    /* Sanity check wall time */
188    if ( since_last_period < executed )
189      since_last_period = executed;
190
191    stats->total_wall_time += since_last_period;
192
193    if ( since_last_period < stats->min_wall_time )
194      stats->min_wall_time = since_last_period;
195
196    if ( since_last_period > stats->max_wall_time )
197      stats->max_wall_time = since_last_period;
198  #else
199    _Timestamp_Add_to( &stats->total_wall_time, &since_last_period );
200
201    if ( _Timestamp_Less_than( &since_last_period, &stats->min_wall_time ) )
202      stats->min_wall_time = since_last_period;
203
204    if ( _Timestamp_Greater_than( &since_last_period, &stats->max_wall_time ) )
205      stats->max_wall_time = since_last_period;
206  #endif
207}
208
209
210/*PAGE
211 *
212 *  rtems_rate_monotonic_period
213 *
214 *  This directive allows a thread to manipulate a rate monotonic timer.
215 *
216 *  Input parameters:
217 *    id     - rate monotonic id
218 *    length - length of period (in ticks)
219 *
220 *  Output parameters:
221 *    RTEMS_SUCCESSFUL - if successful
222 *    error code       - if unsuccessful
223 */
224
225rtems_status_code rtems_rate_monotonic_period(
226  Objects_Id        id,
227  rtems_interval    length
228)
229{
230  Rate_monotonic_Control              *the_period;
231  Objects_Locations                    location;
232  rtems_status_code                    return_value;
233  rtems_rate_monotonic_period_states   local_state;
234  ISR_Level                            level;
235
236  the_period = _Rate_monotonic_Get( id, &location );
237
238  switch ( location ) {
239    case OBJECTS_LOCAL:
240      if ( !_Thread_Is_executing( the_period->owner ) ) {
241        _Thread_Enable_dispatch();
242        return RTEMS_NOT_OWNER_OF_RESOURCE;
243      }
244
245      if ( length == RTEMS_PERIOD_STATUS ) {
246        switch ( the_period->state ) {
247          case RATE_MONOTONIC_INACTIVE:
248            return_value = RTEMS_NOT_DEFINED;
249            break;
250          case RATE_MONOTONIC_EXPIRED:
251          case RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING:
252            return_value = RTEMS_TIMEOUT;
253            break;
254          case RATE_MONOTONIC_ACTIVE:
255          default:              /* unreached -- only to remove warnings */
256            return_value = RTEMS_SUCCESSFUL;
257            break;
258        }
259        _Thread_Enable_dispatch();
260        return( return_value );
261      }
262
263      _ISR_Disable( level );
264      switch ( the_period->state ) {
265        case RATE_MONOTONIC_INACTIVE: {
266
267          _ISR_Enable( level );
268
269          /*
270           *  Baseline statistics information for the beginning of a period.
271           */
272          _Rate_monotonic_Initiate_statistics( the_period );
273
274          the_period->state = RATE_MONOTONIC_ACTIVE;
275          _Watchdog_Initialize(
276            &the_period->Timer,
277            _Rate_monotonic_Timeout,
278            id,
279            NULL
280          );
281
282          the_period->next_length = length;
283
284          _Watchdog_Insert_ticks( &the_period->Timer, length );
285          _Thread_Enable_dispatch();
286          return RTEMS_SUCCESSFUL;
287        }
288        case RATE_MONOTONIC_ACTIVE:
289
290          /*
291           *  Update statistics from the concluding period.
292           */
293          _Rate_monotonic_Update_statistics( the_period );
294
295          /*
296           *  This tells the _Rate_monotonic_Timeout that this task is
297           *  in the process of blocking on the period and that we
298           *  may be changing the length of the next period.
299           */
300          the_period->state = RATE_MONOTONIC_OWNER_IS_BLOCKING;
301          the_period->next_length = length;
302
303          _ISR_Enable( level );
304
305          _Thread_Executing->Wait.id = the_period->Object.id;
306          _Thread_Set_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD );
307
308          /*
309           *  Did the watchdog timer expire while we were actually blocking
310           *  on it?
311           */
312          _ISR_Disable( level );
313            local_state = the_period->state;
314            the_period->state = RATE_MONOTONIC_ACTIVE;
315          _ISR_Enable( level );
316
317          /*
318           *  If it did, then we want to unblock ourself and continue as
319           *  if nothing happen.  The period was reset in the timeout routine.
320           */
321          if ( local_state == RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING )
322            _Thread_Clear_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD );
323
324          _Thread_Enable_dispatch();
325          return RTEMS_SUCCESSFUL;
326          break;
327
328        case RATE_MONOTONIC_EXPIRED:
329
330          /*
331           *  Update statistics from the concluding period
332           */
333          _Rate_monotonic_Initiate_statistics( the_period );
334
335          _ISR_Enable( level );
336
337          the_period->state = RATE_MONOTONIC_ACTIVE;
338          the_period->next_length = length;
339
340          _Watchdog_Insert_ticks( &the_period->Timer, length );
341          _Thread_Enable_dispatch();
342          return RTEMS_TIMEOUT;
343
344        case RATE_MONOTONIC_OWNER_IS_BLOCKING:
345        case RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING:
346          /*
347           *  These should never happen.
348           */
349          break;
350      }
351
352#if defined(RTEMS_MULTIPROCESSING)
353    case OBJECTS_REMOTE:            /* should never return this */
354#endif
355    case OBJECTS_ERROR:
356      break;
357  }
358
359  return RTEMS_INVALID_ID;
360}
Note: See TracBrowser for help on using the repository browser.