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

Last change on this file since 9a78f8a5 was 9a78f8a5, checked in by Sebastian Huber <sebastian.huber@…>, on Jun 16, 2016 at 3:08:54 PM

score: Modify release job scheduler operation

Pass the deadline in watchdog ticks to the scheduler.

Update #2173.

  • Property mode set to 100644
File size: 8.0 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 *  Copyright (c) 2016 embedded brains GmbH.
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
15 *  http://www.rtems.org/license/LICENSE.
16 */
17
18#if HAVE_CONFIG_H
19#include "config.h"
20#endif
21
22#include <rtems/rtems/ratemonimpl.h>
23#include <rtems/score/schedulerimpl.h>
24#include <rtems/score/todimpl.h>
25
26bool _Rate_monotonic_Get_status(
27  const Rate_monotonic_Control *the_period,
28  Timestamp_Control            *wall_since_last_period,
29  Timestamp_Control            *cpu_since_last_period
30)
31{
32  Timestamp_Control        uptime;
33  Thread_Control          *owning_thread = the_period->owner;
34  Timestamp_Control        used;
35
36  /*
37   *  Determine elapsed wall time since period initiated.
38   */
39  _TOD_Get_uptime( &uptime );
40  _Timestamp_Subtract(
41    &the_period->time_period_initiated, &uptime, wall_since_last_period
42  );
43
44  /*
45   *  Determine cpu usage since period initiated.
46   */
47  _Thread_Get_CPU_time_used( owning_thread, &used );
48
49  /*
50   *  The cpu usage info was reset while executing.  Can't
51   *  determine a status.
52   */
53  if ( _Timestamp_Less_than( &used, &the_period->cpu_usage_period_initiated ) )
54    return false;
55
56   /* used = current cpu usage - cpu usage at start of period */
57  _Timestamp_Subtract(
58    &the_period->cpu_usage_period_initiated,
59    &used,
60    cpu_since_last_period
61  );
62
63  return true;
64}
65
66static void _Rate_monotonic_Release_job(
67  Rate_monotonic_Control *the_period,
68  Thread_Control         *owner,
69  rtems_interval          next_length,
70  ISR_lock_Context       *lock_context
71)
72{
73  Per_CPU_Control *cpu_self;
74  uint64_t deadline;
75
76  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
77  _Rate_monotonic_Release( owner, lock_context );
78
79  _ISR_lock_ISR_disable( lock_context );
80  deadline = _Watchdog_Per_CPU_insert_relative(
81    &the_period->Timer,
82    cpu_self,
83    next_length
84  );
85  _ISR_lock_ISR_enable( lock_context );
86
87  _Scheduler_Release_job( owner, deadline );
88
89  _Thread_Dispatch_enable( cpu_self );
90}
91
92void _Rate_monotonic_Restart(
93  Rate_monotonic_Control *the_period,
94  Thread_Control         *owner,
95  ISR_lock_Context       *lock_context
96)
97{
98  /*
99   *  Set the starting point and the CPU time used for the statistics.
100   */
101  _TOD_Get_uptime( &the_period->time_period_initiated );
102  _Thread_Get_CPU_time_used( owner, &the_period->cpu_usage_period_initiated );
103
104  _Rate_monotonic_Release_job(
105    the_period,
106    owner,
107    the_period->next_length,
108    lock_context
109  );
110}
111
112static void _Rate_monotonic_Update_statistics(
113  Rate_monotonic_Control    *the_period
114)
115{
116  Timestamp_Control          executed;
117  Timestamp_Control          since_last_period;
118  Rate_monotonic_Statistics *stats;
119  bool                       valid_status;
120
121  /*
122   *  Assume we are only called in states where it is appropriate
123   *  to update the statistics.  This should only be RATE_MONOTONIC_ACTIVE
124   *  and RATE_MONOTONIC_EXPIRED.
125   */
126
127  /*
128   *  Update the counts.
129   */
130  stats = &the_period->Statistics;
131  stats->count++;
132
133  if ( the_period->state == RATE_MONOTONIC_EXPIRED )
134    stats->missed_count++;
135
136  /*
137   *  Grab status for time statistics.
138   */
139  valid_status =
140    _Rate_monotonic_Get_status( the_period, &since_last_period, &executed );
141  if (!valid_status)
142    return;
143
144  /*
145   *  Update CPU time
146   */
147  _Timestamp_Add_to( &stats->total_cpu_time, &executed );
148
149  if ( _Timestamp_Less_than( &executed, &stats->min_cpu_time ) )
150    stats->min_cpu_time = executed;
151
152  if ( _Timestamp_Greater_than( &executed, &stats->max_cpu_time ) )
153    stats->max_cpu_time = executed;
154
155  /*
156   *  Update Wall time
157   */
158  _Timestamp_Add_to( &stats->total_wall_time, &since_last_period );
159
160  if ( _Timestamp_Less_than( &since_last_period, &stats->min_wall_time ) )
161    stats->min_wall_time = since_last_period;
162
163  if ( _Timestamp_Greater_than( &since_last_period, &stats->max_wall_time ) )
164    stats->max_wall_time = since_last_period;
165}
166
167static rtems_status_code _Rate_monotonic_Get_status_for_state(
168  rtems_rate_monotonic_period_states state
169)
170{
171  switch ( state ) {
172    case RATE_MONOTONIC_INACTIVE:
173      return RTEMS_NOT_DEFINED;
174    case RATE_MONOTONIC_EXPIRED:
175      return RTEMS_TIMEOUT;
176    default:
177      _Assert( state == RATE_MONOTONIC_ACTIVE );
178      return RTEMS_SUCCESSFUL;
179  }
180}
181
182static rtems_status_code _Rate_monotonic_Activate(
183  Rate_monotonic_Control *the_period,
184  rtems_interval          length,
185  Thread_Control         *executing,
186  ISR_lock_Context       *lock_context
187)
188{
189  the_period->state = RATE_MONOTONIC_ACTIVE;
190  the_period->next_length = length;
191  _Rate_monotonic_Restart( the_period, executing, lock_context );
192  return RTEMS_SUCCESSFUL;
193}
194
195static rtems_status_code _Rate_monotonic_Block_while_active(
196  Rate_monotonic_Control *the_period,
197  rtems_interval          length,
198  Thread_Control         *executing,
199  ISR_lock_Context       *lock_context
200)
201{
202  Per_CPU_Control *cpu_self;
203  bool             success;
204
205  /*
206   *  Update statistics from the concluding period.
207   */
208  _Rate_monotonic_Update_statistics( the_period );
209
210  /*
211   *  This tells the _Rate_monotonic_Timeout that this task is
212   *  in the process of blocking on the period and that we
213   *  may be changing the length of the next period.
214   */
215  the_period->next_length = length;
216  executing->Wait.return_argument = the_period;
217  _Thread_Wait_flags_set( executing, RATE_MONOTONIC_INTEND_TO_BLOCK );
218
219  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
220  _Rate_monotonic_Release( executing, lock_context );
221
222  _Thread_Set_state( executing, STATES_WAITING_FOR_PERIOD );
223
224  success = _Thread_Wait_flags_try_change(
225    executing,
226    RATE_MONOTONIC_INTEND_TO_BLOCK,
227    RATE_MONOTONIC_BLOCKED
228  );
229  if ( !success ) {
230    _Assert(
231      _Thread_Wait_flags_get( executing ) == RATE_MONOTONIC_READY_AGAIN
232    );
233    _Thread_Unblock( executing );
234  }
235
236  _Thread_Dispatch_enable( cpu_self );
237  return RTEMS_SUCCESSFUL;
238}
239
240static rtems_status_code _Rate_monotonic_Block_while_expired(
241  Rate_monotonic_Control *the_period,
242  rtems_interval          length,
243  Thread_Control         *executing,
244  ISR_lock_Context       *lock_context
245)
246{
247  /*
248   *  Update statistics from the concluding period
249   */
250  _Rate_monotonic_Update_statistics( the_period );
251
252  the_period->state = RATE_MONOTONIC_ACTIVE;
253  the_period->next_length = length;
254
255  _Rate_monotonic_Release_job( the_period, executing, length, lock_context );
256  return RTEMS_TIMEOUT;
257}
258
259rtems_status_code rtems_rate_monotonic_period(
260  rtems_id       id,
261  rtems_interval length
262)
263{
264  Rate_monotonic_Control            *the_period;
265  ISR_lock_Context                   lock_context;
266  Thread_Control                    *executing;
267  rtems_status_code                  status;
268  rtems_rate_monotonic_period_states state;
269
270  the_period = _Rate_monotonic_Get( id, &lock_context );
271  if ( the_period == NULL ) {
272    return RTEMS_INVALID_ID;
273  }
274
275  executing = _Thread_Executing;
276  if ( executing != the_period->owner ) {
277    _ISR_lock_ISR_enable( &lock_context );
278    return RTEMS_NOT_OWNER_OF_RESOURCE;
279  }
280
281  _Rate_monotonic_Acquire_critical( executing, &lock_context );
282
283  state = the_period->state;
284
285  if ( length == RTEMS_PERIOD_STATUS ) {
286    status = _Rate_monotonic_Get_status_for_state( state );
287    _Rate_monotonic_Release( executing, &lock_context );
288  } else {
289    switch ( state ) {
290      case RATE_MONOTONIC_ACTIVE:
291        status = _Rate_monotonic_Block_while_active(
292          the_period,
293          length,
294          executing,
295          &lock_context
296        );
297        break;
298      case RATE_MONOTONIC_INACTIVE:
299        status = _Rate_monotonic_Activate(
300          the_period,
301          length,
302          executing,
303          &lock_context
304        );
305        break;
306      default:
307        _Assert( state == RATE_MONOTONIC_EXPIRED );
308        status = _Rate_monotonic_Block_while_expired(
309          the_period,
310          length,
311          executing,
312          &lock_context
313        );
314        break;
315    }
316  }
317
318  return status;
319}
Note: See TracBrowser for help on using the repository browser.