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

Last change on this file since cb2cbec was cb2cbec, checked in by Gedare Bloom <gedare@…>, on Jan 13, 2017 at 6:54:11 PM

classic: adjust names of RM postponed job functions

closes #2795

  • Property mode set to 100644
File size: 11.5 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 *  COPYRIGHT (c) 2016 Kuan-Hsun Chen.
13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
16 *  http://www.rtems.org/license/LICENSE.
17 */
18
19#if HAVE_CONFIG_H
20#include "config.h"
21#endif
22
23#include <rtems/rtems/ratemonimpl.h>
24#include <rtems/score/schedulerimpl.h>
25#include <rtems/score/todimpl.h>
26
27bool _Rate_monotonic_Get_status(
28  const Rate_monotonic_Control *the_period,
29  Timestamp_Control            *wall_since_last_period,
30  Timestamp_Control            *cpu_since_last_period
31)
32{
33  Timestamp_Control        uptime;
34  Thread_Control          *owning_thread = the_period->owner;
35  Timestamp_Control        used;
36
37  /*
38   *  Determine elapsed wall time since period initiated.
39   */
40  _TOD_Get_uptime( &uptime );
41  _Timestamp_Subtract(
42    &the_period->time_period_initiated, &uptime, wall_since_last_period
43  );
44
45  /*
46   *  Determine cpu usage since period initiated.
47   */
48  _Thread_Get_CPU_time_used( owning_thread, &used );
49
50  /*
51   *  The cpu usage info was reset while executing.  Can't
52   *  determine a status.
53   */
54  if ( _Timestamp_Less_than( &used, &the_period->cpu_usage_period_initiated ) )
55    return false;
56
57   /* used = current cpu usage - cpu usage at start of period */
58  _Timestamp_Subtract(
59    &the_period->cpu_usage_period_initiated,
60    &used,
61    cpu_since_last_period
62  );
63
64  return true;
65}
66
67static void _Rate_monotonic_Release_postponed_job(
68  Rate_monotonic_Control *the_period,
69  Thread_Control         *owner,
70  rtems_interval          next_length,
71  ISR_lock_Context       *lock_context
72)
73{
74  /* This function only releases the postponed jobs. */
75  Per_CPU_Control *cpu_self;
76  Thread_queue_Context  queue_context;
77  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
78  _Rate_monotonic_Release( owner, lock_context );
79
80  the_period->postponed_jobs -=1;
81  _Scheduler_Release_job(
82    owner,
83    &the_period->Priority,
84    the_period->latest_deadline,
85    &queue_context
86  );
87
88  _Rate_monotonic_Release( the_period, lock_context );
89  _Thread_Priority_update( &queue_context );
90  _Thread_Dispatch_enable( cpu_self );
91}
92
93static void _Rate_monotonic_Release_job(
94  Rate_monotonic_Control *the_period,
95  Thread_Control         *owner,
96  rtems_interval          next_length,
97  ISR_lock_Context       *lock_context
98)
99{
100  Per_CPU_Control      *cpu_self;
101  Thread_queue_Context  queue_context;
102  uint64_t              deadline;
103
104  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
105
106  deadline = _Watchdog_Per_CPU_insert_relative(
107    &the_period->Timer,
108    cpu_self,
109    next_length
110  );
111  _Scheduler_Release_job(
112    owner,
113    &the_period->Priority,
114    deadline,
115    &queue_context
116  );
117
118  _Rate_monotonic_Release( the_period, lock_context );
119  _Thread_Priority_update( &queue_context );
120  _Thread_Dispatch_enable( cpu_self );
121}
122
123void _Rate_monotonic_Renew_deadline(
124  Rate_monotonic_Control *the_period,
125  Thread_Control         *owner,
126  ISR_lock_Context       *lock_context
127)
128{
129  Per_CPU_Control *cpu_self;
130  uint64_t deadline;
131
132  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
133  _Rate_monotonic_Release( owner, lock_context );
134
135  _ISR_lock_ISR_disable( lock_context );
136  deadline = _Watchdog_Per_CPU_insert_relative(
137    &the_period->Timer,
138    cpu_self,
139    the_period->next_length
140  );
141  the_period->latest_deadline = deadline;
142  _ISR_lock_ISR_enable( lock_context );
143  _Thread_Dispatch_enable( cpu_self );
144
145}
146
147void _Rate_monotonic_Restart(
148  Rate_monotonic_Control *the_period,
149  Thread_Control         *owner,
150  ISR_lock_Context       *lock_context
151)
152{
153  /*
154   *  Set the starting point and the CPU time used for the statistics.
155   */
156  _TOD_Get_uptime( &the_period->time_period_initiated );
157  _Thread_Get_CPU_time_used( owner, &the_period->cpu_usage_period_initiated );
158
159  _Rate_monotonic_Release_job(
160    the_period,
161    owner,
162    the_period->next_length,
163    lock_context
164  );
165}
166
167static void _Rate_monotonic_Update_statistics(
168  Rate_monotonic_Control    *the_period
169)
170{
171  Timestamp_Control          executed;
172  Timestamp_Control          since_last_period;
173  Rate_monotonic_Statistics *stats;
174  bool                       valid_status;
175
176  /*
177   *  Assume we are only called in states where it is appropriate
178   *  to update the statistics.  This should only be RATE_MONOTONIC_ACTIVE
179   *  and RATE_MONOTONIC_EXPIRED.
180   */
181
182  /*
183   *  Update the counts.
184   */
185  stats = &the_period->Statistics;
186  stats->count++;
187
188  if ( the_period->state == RATE_MONOTONIC_EXPIRED )
189    stats->missed_count++;
190
191  /*
192   *  Grab status for time statistics.
193   */
194  valid_status =
195    _Rate_monotonic_Get_status( the_period, &since_last_period, &executed );
196  if (!valid_status)
197    return;
198
199  /*
200   *  Update CPU time
201   */
202  _Timestamp_Add_to( &stats->total_cpu_time, &executed );
203
204  if ( _Timestamp_Less_than( &executed, &stats->min_cpu_time ) )
205    stats->min_cpu_time = executed;
206
207  if ( _Timestamp_Greater_than( &executed, &stats->max_cpu_time ) )
208    stats->max_cpu_time = executed;
209
210  /*
211   *  Update Wall time
212   */
213  _Timestamp_Add_to( &stats->total_wall_time, &since_last_period );
214
215  if ( _Timestamp_Less_than( &since_last_period, &stats->min_wall_time ) )
216    stats->min_wall_time = since_last_period;
217
218  if ( _Timestamp_Greater_than( &since_last_period, &stats->max_wall_time ) )
219    stats->max_wall_time = since_last_period;
220}
221
222static rtems_status_code _Rate_monotonic_Get_status_for_state(
223  rtems_rate_monotonic_period_states state
224)
225{
226  switch ( state ) {
227    case RATE_MONOTONIC_INACTIVE:
228      return RTEMS_NOT_DEFINED;
229    case RATE_MONOTONIC_EXPIRED:
230      return RTEMS_TIMEOUT;
231    default:
232      _Assert( state == RATE_MONOTONIC_ACTIVE );
233      return RTEMS_SUCCESSFUL;
234  }
235}
236
237static rtems_status_code _Rate_monotonic_Activate(
238  Rate_monotonic_Control *the_period,
239  rtems_interval          length,
240  Thread_Control         *executing,
241  ISR_lock_Context       *lock_context
242)
243{
244  the_period->postponed_jobs = 0;
245  the_period->state = RATE_MONOTONIC_ACTIVE;
246  the_period->next_length = length;
247  _Rate_monotonic_Restart( the_period, executing, lock_context );
248  return RTEMS_SUCCESSFUL;
249}
250
251static rtems_status_code _Rate_monotonic_Block_while_active(
252  Rate_monotonic_Control *the_period,
253  rtems_interval          length,
254  Thread_Control         *executing,
255  ISR_lock_Context       *lock_context
256)
257{
258  Per_CPU_Control *cpu_self;
259  bool             success;
260
261  /*
262   *  Update statistics from the concluding period.
263   */
264  _Rate_monotonic_Update_statistics( the_period );
265
266  /*
267   *  This tells the _Rate_monotonic_Timeout that this task is
268   *  in the process of blocking on the period and that we
269   *  may be changing the length of the next period.
270   */
271  the_period->next_length = length;
272  executing->Wait.return_argument = the_period;
273  _Thread_Wait_flags_set( executing, RATE_MONOTONIC_INTEND_TO_BLOCK );
274
275  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
276  _Rate_monotonic_Release( the_period, lock_context );
277
278  _Thread_Set_state( executing, STATES_WAITING_FOR_PERIOD );
279
280  success = _Thread_Wait_flags_try_change_acquire(
281    executing,
282    RATE_MONOTONIC_INTEND_TO_BLOCK,
283    RATE_MONOTONIC_BLOCKED
284  );
285  if ( !success ) {
286    _Assert(
287      _Thread_Wait_flags_get( executing ) == RATE_MONOTONIC_READY_AGAIN
288    );
289    _Thread_Unblock( executing );
290  }
291
292  _Thread_Dispatch_enable( cpu_self );
293  return RTEMS_SUCCESSFUL;
294}
295
296/*
297 * There are two possible cases: one is that the previous deadline is missed,
298 * The other is that the number of postponed jobs is not 0, but the current
299 * deadline is still not expired, i.e., state = RATE_MONOTONIC_ACTIVE.
300 */
301static rtems_status_code _Rate_monotonic_Block_while_expired(
302  Rate_monotonic_Control *the_period,
303  rtems_interval          length,
304  Thread_Control         *executing,
305  ISR_lock_Context       *lock_context
306)
307{
308  /*
309   * No matter the just finished jobs in time or not,
310   * they are actually missing their deadlines already.
311   */
312  the_period->state = RATE_MONOTONIC_EXPIRED;
313
314  /*
315   * Update statistics from the concluding period
316   */
317  _Rate_monotonic_Update_statistics( the_period );
318
319  the_period->state = RATE_MONOTONIC_ACTIVE;
320  the_period->next_length = length;
321
322  _Rate_monotonic_Release_postponed_job(
323      the_period,
324      executing,
325      length,
326      lock_context
327  );
328  return RTEMS_TIMEOUT;
329}
330
331/*
332 * This helper function is prepared for run-time monitoring.
333 */
334uint32_t rtems_rate_monotonic_postponed_job_count(
335    rtems_id   period_id
336)
337{
338  Rate_monotonic_Control             *the_period;
339  ISR_lock_Context                    lock_context;
340  Thread_Control                     *owner;
341
342  the_period = _Rate_monotonic_Get( period_id, &lock_context );
343  _Assert( the_period != NULL );
344  uint32_t jobs = the_period->postponed_jobs;
345  owner = the_period->owner;
346  _Rate_monotonic_Release( owner, &lock_context );
347  return jobs;
348}
349
350rtems_status_code rtems_rate_monotonic_period(
351  rtems_id       id,
352  rtems_interval length
353)
354{
355  Rate_monotonic_Control            *the_period;
356  ISR_lock_Context                   lock_context;
357  Thread_Control                    *executing;
358  rtems_status_code                  status;
359  rtems_rate_monotonic_period_states state;
360
361  the_period = _Rate_monotonic_Get( id, &lock_context );
362  if ( the_period == NULL ) {
363    return RTEMS_INVALID_ID;
364  }
365
366  executing = _Thread_Executing;
367  if ( executing != the_period->owner ) {
368    _ISR_lock_ISR_enable( &lock_context );
369    return RTEMS_NOT_OWNER_OF_RESOURCE;
370  }
371
372  _Rate_monotonic_Acquire_critical( the_period, &lock_context );
373
374  state = the_period->state;
375
376  if ( length == RTEMS_PERIOD_STATUS ) {
377    status = _Rate_monotonic_Get_status_for_state( state );
378    _Rate_monotonic_Release( the_period, &lock_context );
379  } else {
380    switch ( state ) {
381      case RATE_MONOTONIC_ACTIVE:
382
383        if( the_period->postponed_jobs > 0 ){
384          /*
385           * If the number of postponed jobs is not 0, it means the
386           * previous postponed instance is finished without exceeding
387           * the current period deadline.
388           *
389           * Do nothing on the watchdog deadline assignment but release the
390           * next remaining postponed job.
391           */
392          status = _Rate_monotonic_Block_while_expired(
393            the_period,
394            length,
395            executing,
396            &lock_context
397          );
398        }else{
399          /*
400           * Normal case that no postponed jobs and no expiration, so wait for
401           * the period and update the deadline of watchdog accordingly.
402           */
403          status = _Rate_monotonic_Block_while_active(
404            the_period,
405            length,
406            executing,
407            &lock_context
408          );
409        }
410        break;
411      case RATE_MONOTONIC_INACTIVE:
412        status = _Rate_monotonic_Activate(
413          the_period,
414          length,
415          executing,
416          &lock_context
417        );
418        break;
419      default:
420        /*
421         * As now this period was already TIMEOUT, there must be at least one
422         * postponed job recorded by the watchdog. The one which exceeded
423         * the previous deadlines was just finished.
424         *
425         * Maybe there is more than one job postponed due to the preemption or
426         * the previous finished job.
427         */
428        _Assert( state == RATE_MONOTONIC_EXPIRED );
429        status = _Rate_monotonic_Block_while_expired(
430          the_period,
431          length,
432          executing,
433          &lock_context
434        );
435        break;
436    }
437  }
438
439  return status;
440}
Note: See TracBrowser for help on using the repository browser.