source: rtems/cpukit/rtems/src/ratemonperiod.c @ 66cb142

5
Last change on this file since 66cb142 was ed24ed4e, checked in by Sebastian Huber <sebastian.huber@…>, on 02/08/18 at 09:47:16

Use _Thread_Dispatch_direct()

Use _Thread_Dispatch_direct() for operations that block the executing
thread. This ensures that we get a fatal error
(INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL) if we try to block in
an invalid context, e.g. during system start or an interrupt handler.

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