source: rtems/cpukit/rtems/src/ratemonperiod.c @ ec2078d

4.104.114.84.95
Last change on this file since ec2078d was ec2078d, checked in by Joel Sherrill <joel.sherrill@…>, on 05/21/07 at 19:28:55

2007-05-21 Joel Sherrill <joel.sherrill@…>

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