source: rtems/cpukit/rtems/src/ratemonperiod.c @ 7ec66e08

5
Last change on this file since 7ec66e08 was 90960bd, checked in by Sebastian Huber <sebastian.huber@…>, on 03/21/16 at 14:01:57

rtems: Rework rate-monotonic scheduler

Use the default thread lock to protect rate-monotonic state changes.
This avoids use of the Giant lock. Split rtems_rate_monotonic_period()
body into several static functions. Introduce a new thread wait class
THREAD_WAIT_CLASS_PERIOD for period objects to synchronize the blocking
operation.

Close #2631.

  • 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
75  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
76  _Rate_monotonic_Release( owner, lock_context );
77
78  _Scheduler_Release_job( owner, next_length );
79
80  _ISR_lock_ISR_disable( lock_context );
81  _Watchdog_Per_CPU_insert_relative(
82    &the_period->Timer,
83    cpu_self,
84    next_length
85  );
86  _ISR_lock_ISR_enable( lock_context );
87
88  _Thread_Dispatch_enable( cpu_self );
89}
90
91void _Rate_monotonic_Restart(
92  Rate_monotonic_Control *the_period,
93  Thread_Control         *owner,
94  ISR_lock_Context       *lock_context
95)
96{
97  /*
98   *  Set the starting point and the CPU time used for the statistics.
99   */
100  _TOD_Get_uptime( &the_period->time_period_initiated );
101  _Thread_Get_CPU_time_used( owner, &the_period->cpu_usage_period_initiated );
102
103  _Rate_monotonic_Release_job(
104    the_period,
105    owner,
106    the_period->next_length,
107    lock_context
108  );
109}
110
111static void _Rate_monotonic_Update_statistics(
112  Rate_monotonic_Control    *the_period
113)
114{
115  Timestamp_Control          executed;
116  Timestamp_Control          since_last_period;
117  Rate_monotonic_Statistics *stats;
118  bool                       valid_status;
119
120  /*
121   *  Assume we are only called in states where it is appropriate
122   *  to update the statistics.  This should only be RATE_MONOTONIC_ACTIVE
123   *  and RATE_MONOTONIC_EXPIRED.
124   */
125
126  /*
127   *  Update the counts.
128   */
129  stats = &the_period->Statistics;
130  stats->count++;
131
132  if ( the_period->state == RATE_MONOTONIC_EXPIRED )
133    stats->missed_count++;
134
135  /*
136   *  Grab status for time statistics.
137   */
138  valid_status =
139    _Rate_monotonic_Get_status( the_period, &since_last_period, &executed );
140  if (!valid_status)
141    return;
142
143  /*
144   *  Update CPU time
145   */
146  _Timestamp_Add_to( &stats->total_cpu_time, &executed );
147
148  if ( _Timestamp_Less_than( &executed, &stats->min_cpu_time ) )
149    stats->min_cpu_time = executed;
150
151  if ( _Timestamp_Greater_than( &executed, &stats->max_cpu_time ) )
152    stats->max_cpu_time = executed;
153
154  /*
155   *  Update Wall time
156   */
157  _Timestamp_Add_to( &stats->total_wall_time, &since_last_period );
158
159  if ( _Timestamp_Less_than( &since_last_period, &stats->min_wall_time ) )
160    stats->min_wall_time = since_last_period;
161
162  if ( _Timestamp_Greater_than( &since_last_period, &stats->max_wall_time ) )
163    stats->max_wall_time = since_last_period;
164}
165
166static rtems_status_code _Rate_monotonic_Get_status_for_state(
167  rtems_rate_monotonic_period_states state
168)
169{
170  switch ( state ) {
171    case RATE_MONOTONIC_INACTIVE:
172      return RTEMS_NOT_DEFINED;
173    case RATE_MONOTONIC_EXPIRED:
174      return RTEMS_TIMEOUT;
175    default:
176      _Assert( state == RATE_MONOTONIC_ACTIVE );
177      return RTEMS_SUCCESSFUL;
178  }
179}
180
181static rtems_status_code _Rate_monotonic_Activate(
182  Rate_monotonic_Control *the_period,
183  rtems_interval          length,
184  Thread_Control         *executing,
185  ISR_lock_Context       *lock_context
186)
187{
188  the_period->state = RATE_MONOTONIC_ACTIVE;
189  the_period->next_length = length;
190  _Rate_monotonic_Restart( the_period, executing, lock_context );
191  return RTEMS_SUCCESSFUL;
192}
193
194static rtems_status_code _Rate_monotonic_Block_while_active(
195  Rate_monotonic_Control *the_period,
196  rtems_interval          length,
197  Thread_Control         *executing,
198  ISR_lock_Context       *lock_context
199)
200{
201  Per_CPU_Control *cpu_self;
202  bool             success;
203
204  /*
205   *  Update statistics from the concluding period.
206   */
207  _Rate_monotonic_Update_statistics( the_period );
208
209  /*
210   *  This tells the _Rate_monotonic_Timeout that this task is
211   *  in the process of blocking on the period and that we
212   *  may be changing the length of the next period.
213   */
214  the_period->next_length = length;
215  executing->Wait.return_argument = the_period;
216  _Thread_Wait_flags_set( executing, RATE_MONOTONIC_INTEND_TO_BLOCK );
217
218  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
219  _Rate_monotonic_Release( executing, lock_context );
220
221  _Thread_Set_state( executing, STATES_WAITING_FOR_PERIOD );
222
223  success = _Thread_Wait_flags_try_change(
224    executing,
225    RATE_MONOTONIC_INTEND_TO_BLOCK,
226    RATE_MONOTONIC_BLOCKED
227  );
228  if ( !success ) {
229    _Assert(
230      _Thread_Wait_flags_get( executing ) == RATE_MONOTONIC_READY_AGAIN
231    );
232    _Thread_Unblock( executing );
233  }
234
235  _Thread_Dispatch_enable( cpu_self );
236  return RTEMS_SUCCESSFUL;
237}
238
239static rtems_status_code _Rate_monotonic_Block_while_expired(
240  Rate_monotonic_Control *the_period,
241  rtems_interval          length,
242  Thread_Control         *executing,
243  ISR_lock_Context       *lock_context
244)
245{
246  /*
247   *  Update statistics from the concluding period
248   */
249  _Rate_monotonic_Update_statistics( the_period );
250
251  the_period->state = RATE_MONOTONIC_ACTIVE;
252  the_period->next_length = length;
253
254  _Rate_monotonic_Release_job( the_period, executing, length, lock_context );
255  return RTEMS_TIMEOUT;
256}
257
258rtems_status_code rtems_rate_monotonic_period(
259  rtems_id       id,
260  rtems_interval length
261)
262{
263  Rate_monotonic_Control            *the_period;
264  ISR_lock_Context                   lock_context;
265  Thread_Control                    *executing;
266  rtems_status_code                  status;
267  rtems_rate_monotonic_period_states state;
268
269  the_period = _Rate_monotonic_Get( id, &lock_context );
270  if ( the_period == NULL ) {
271    return RTEMS_INVALID_ID;
272  }
273
274  executing = _Thread_Executing;
275  if ( executing != the_period->owner ) {
276    _ISR_lock_ISR_enable( &lock_context );
277    return RTEMS_NOT_OWNER_OF_RESOURCE;
278  }
279
280  _Rate_monotonic_Acquire_critical( executing, &lock_context );
281
282  state = the_period->state;
283
284  if ( length == RTEMS_PERIOD_STATUS ) {
285    status = _Rate_monotonic_Get_status_for_state( state );
286    _Rate_monotonic_Release( executing, &lock_context );
287  } else {
288    switch ( state ) {
289      case RATE_MONOTONIC_ACTIVE:
290        status = _Rate_monotonic_Block_while_active(
291          the_period,
292          length,
293          executing,
294          &lock_context
295        );
296        break;
297      case RATE_MONOTONIC_INACTIVE:
298        status = _Rate_monotonic_Activate(
299          the_period,
300          length,
301          executing,
302          &lock_context
303        );
304        break;
305      default:
306        _Assert( state == RATE_MONOTONIC_EXPIRED );
307        status = _Rate_monotonic_Block_while_expired(
308          the_period,
309          length,
310          executing,
311          &lock_context
312        );
313        break;
314    }
315  }
316
317  return status;
318}
Note: See TracBrowser for help on using the repository browser.