source: rtems/cpukit/rtems/src/ratemonperiod.c @ 2d2352b

4.115
Last change on this file since 2d2352b was 2d2352b, checked in by Sebastian Huber <sebastian.huber@…>, on 06/05/13 at 09:48:57

score: Add and use _Objects_Put()

Add and use _Objects_Put_without_thread_dispatch(). These two functions
pair with the _Objects_Get() function. This helps to introduce object
specific SMP locks to avoid lock contention.

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