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

Last change on this file was bcef89f2, checked in by Sebastian Huber <sebastian.huber@…>, on 05/19/23 at 06:18:25

Update company name

The embedded brains GmbH & Co. KG is the legal successor of embedded
brains GmbH.

  • Property mode set to 100644
File size: 11.3 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup RTEMSImplClassicRateMonotonic
7 *
8 * @brief This source file contains the implementation of
9 *   rtems_rate_monotonic_period_states().
10 */
11
12/*
13 *  COPYRIGHT (c) 1989-2010.
14 *  On-Line Applications Research Corporation (OAR).
15 *  Copyright (c) 2016 embedded brains GmbH & Co. KG
16 *  COPYRIGHT (c) 2016 Kuan-Hsun Chen.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 *    notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 *    notice, this list of conditions and the following disclaimer in the
25 *    documentation and/or other materials provided with the distribution.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40#ifdef HAVE_CONFIG_H
41#include "config.h"
42#endif
43
44#include <rtems/rtems/ratemonimpl.h>
45#include <rtems/score/schedulerimpl.h>
46#include <rtems/score/todimpl.h>
47
48void _Rate_monotonic_Get_status(
49  const Rate_monotonic_Control *the_period,
50  Timestamp_Control            *wall_since_last_period,
51  Timestamp_Control            *cpu_since_last_period
52)
53{
54  Timestamp_Control        uptime;
55  Thread_Control          *owning_thread = the_period->owner;
56  Timestamp_Control        used;
57
58  /*
59   *  Determine elapsed wall time since period initiated.
60   */
61  _TOD_Get_uptime( &uptime );
62  _Timestamp_Subtract(
63    &the_period->time_period_initiated, &uptime, wall_since_last_period
64  );
65
66  /*
67   *  Determine cpu usage since period initiated.
68   */
69  used = _Thread_Get_CPU_time_used( owning_thread );
70
71   /* used = current cpu usage - cpu usage at start of period */
72  _Timestamp_Subtract(
73    &the_period->cpu_usage_period_initiated,
74    &used,
75    cpu_since_last_period
76  );
77}
78
79static void _Rate_monotonic_Release_postponed_job(
80  Rate_monotonic_Control *the_period,
81  Thread_Control         *owner,
82  rtems_interval          next_length,
83  ISR_lock_Context       *lock_context
84)
85{
86  Per_CPU_Control      *cpu_self;
87  Thread_queue_Context  queue_context;
88
89  --the_period->postponed_jobs;
90  _Scheduler_Release_job(
91    owner,
92    &the_period->Priority,
93    the_period->latest_deadline,
94    &queue_context
95  );
96
97  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
98  _Rate_monotonic_Release( the_period, lock_context );
99  _Thread_Priority_update( &queue_context );
100  _Thread_Dispatch_direct( cpu_self );
101}
102
103static void _Rate_monotonic_Release_job(
104  Rate_monotonic_Control *the_period,
105  Thread_Control         *owner,
106  rtems_interval          next_length,
107  ISR_lock_Context       *lock_context
108)
109{
110  Per_CPU_Control      *cpu_self;
111  Thread_queue_Context  queue_context;
112  uint64_t              deadline;
113
114  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
115
116  deadline = _Watchdog_Per_CPU_insert_ticks(
117    &the_period->Timer,
118    cpu_self,
119    next_length
120  );
121  _Scheduler_Release_job(
122    owner,
123    &the_period->Priority,
124    deadline,
125    &queue_context
126  );
127
128  _Rate_monotonic_Release( the_period, lock_context );
129  _Thread_Priority_update( &queue_context );
130  _Thread_Dispatch_enable( cpu_self );
131}
132
133void _Rate_monotonic_Restart(
134  Rate_monotonic_Control *the_period,
135  Thread_Control         *owner,
136  ISR_lock_Context       *lock_context
137)
138{
139  /*
140   *  Set the starting point and the CPU time used for the statistics.
141   */
142  _TOD_Get_uptime( &the_period->time_period_initiated );
143  the_period->cpu_usage_period_initiated = _Thread_Get_CPU_time_used( owner );
144
145  _Rate_monotonic_Release_job(
146    the_period,
147    owner,
148    the_period->next_length,
149    lock_context
150  );
151}
152
153static void _Rate_monotonic_Update_statistics(
154  Rate_monotonic_Control    *the_period
155)
156{
157  Timestamp_Control          executed;
158  Timestamp_Control          since_last_period;
159  Rate_monotonic_Statistics *stats;
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  _Rate_monotonic_Get_status( the_period, &since_last_period, &executed );
180
181  /*
182   *  Update CPU time
183   */
184  _Timestamp_Add_to( &stats->total_cpu_time, &executed );
185
186  if ( _Timestamp_Less_than( &executed, &stats->min_cpu_time ) )
187    stats->min_cpu_time = executed;
188
189  if ( _Timestamp_Greater_than( &executed, &stats->max_cpu_time ) )
190    stats->max_cpu_time = executed;
191
192  /*
193   *  Update Wall time
194   */
195  _Timestamp_Add_to( &stats->total_wall_time, &since_last_period );
196
197  if ( _Timestamp_Less_than( &since_last_period, &stats->min_wall_time ) )
198    stats->min_wall_time = since_last_period;
199
200  if ( _Timestamp_Greater_than( &since_last_period, &stats->max_wall_time ) )
201    stats->max_wall_time = since_last_period;
202}
203
204static rtems_status_code _Rate_monotonic_Get_status_for_state(
205  rtems_rate_monotonic_period_states state
206)
207{
208  switch ( state ) {
209    case RATE_MONOTONIC_INACTIVE:
210      return RTEMS_NOT_DEFINED;
211    case RATE_MONOTONIC_EXPIRED:
212      return RTEMS_TIMEOUT;
213    default:
214      _Assert( state == RATE_MONOTONIC_ACTIVE );
215      return RTEMS_SUCCESSFUL;
216  }
217}
218
219static rtems_status_code _Rate_monotonic_Activate(
220  Rate_monotonic_Control *the_period,
221  rtems_interval          length,
222  Thread_Control         *executing,
223  ISR_lock_Context       *lock_context
224)
225{
226  _Assert( the_period->postponed_jobs == 0 );
227  the_period->state = RATE_MONOTONIC_ACTIVE;
228  the_period->next_length = length;
229  _Rate_monotonic_Restart( the_period, executing, lock_context );
230  return RTEMS_SUCCESSFUL;
231}
232
233static rtems_status_code _Rate_monotonic_Block_while_active(
234  Rate_monotonic_Control *the_period,
235  rtems_interval          length,
236  Thread_Control         *executing,
237  ISR_lock_Context       *lock_context
238)
239{
240  Per_CPU_Control *cpu_self;
241  bool             success;
242
243  /*
244   *  Update statistics from the concluding period.
245   */
246  _Rate_monotonic_Update_statistics( the_period );
247
248  /*
249   *  This tells the _Rate_monotonic_Timeout that this task is
250   *  in the process of blocking on the period and that we
251   *  may be changing the length of the next period.
252   */
253  the_period->next_length = length;
254  executing->Wait.return_argument = the_period;
255  _Thread_Wait_flags_set( executing, RATE_MONOTONIC_INTEND_TO_BLOCK );
256
257  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
258  _Rate_monotonic_Release( the_period, lock_context );
259
260  _Thread_Set_state( executing, STATES_WAITING_FOR_PERIOD );
261
262  success = _Thread_Wait_flags_try_change_acquire(
263    executing,
264    RATE_MONOTONIC_INTEND_TO_BLOCK,
265    RATE_MONOTONIC_BLOCKED
266  );
267  if ( !success ) {
268    _Assert(
269      _Thread_Wait_flags_get( executing ) == THREAD_WAIT_STATE_READY
270    );
271    _Thread_Unblock( executing );
272  }
273
274  _Thread_Dispatch_direct( cpu_self );
275  return RTEMS_SUCCESSFUL;
276}
277
278/*
279 * There are two possible cases: one is that the previous deadline is missed,
280 * The other is that the number of postponed jobs is not 0, but the current
281 * deadline is still not expired, i.e., state = RATE_MONOTONIC_ACTIVE.
282 */
283static rtems_status_code _Rate_monotonic_Block_while_expired(
284  Rate_monotonic_Control *the_period,
285  rtems_interval          length,
286  Thread_Control         *executing,
287  ISR_lock_Context       *lock_context
288)
289{
290  /*
291   * No matter the just finished jobs in time or not,
292   * they are actually missing their deadlines already.
293   */
294  the_period->state = RATE_MONOTONIC_EXPIRED;
295
296  /*
297   * Update statistics from the concluding period
298   */
299  _Rate_monotonic_Update_statistics( the_period );
300
301  the_period->state = RATE_MONOTONIC_ACTIVE;
302  the_period->next_length = length;
303
304  _Rate_monotonic_Release_postponed_job(
305      the_period,
306      executing,
307      length,
308      lock_context
309  );
310  return RTEMS_TIMEOUT;
311}
312
313rtems_status_code rtems_rate_monotonic_period(
314  rtems_id       id,
315  rtems_interval length
316)
317{
318  Rate_monotonic_Control            *the_period;
319  ISR_lock_Context                   lock_context;
320  Thread_Control                    *executing;
321  rtems_status_code                  status;
322  rtems_rate_monotonic_period_states state;
323
324  the_period = _Rate_monotonic_Get( id, &lock_context );
325  if ( the_period == NULL ) {
326    return RTEMS_INVALID_ID;
327  }
328
329  executing = _Thread_Executing;
330  if ( executing != the_period->owner ) {
331    _ISR_lock_ISR_enable( &lock_context );
332    return RTEMS_NOT_OWNER_OF_RESOURCE;
333  }
334
335  _Rate_monotonic_Acquire_critical( the_period, &lock_context );
336
337  state = the_period->state;
338
339  if ( length == RTEMS_PERIOD_STATUS ) {
340    status = _Rate_monotonic_Get_status_for_state( state );
341    _Rate_monotonic_Release( the_period, &lock_context );
342  } else {
343    switch ( state ) {
344      case RATE_MONOTONIC_ACTIVE:
345
346        if( the_period->postponed_jobs > 0 ){
347          /*
348           * If the number of postponed jobs is not 0, it means the
349           * previous postponed instance is finished without exceeding
350           * the current period deadline.
351           *
352           * Do nothing on the watchdog deadline assignment but release the
353           * next remaining postponed job.
354           */
355          status = _Rate_monotonic_Block_while_expired(
356            the_period,
357            length,
358            executing,
359            &lock_context
360          );
361        }else{
362          /*
363           * Normal case that no postponed jobs and no expiration, so wait for
364           * the period and update the deadline of watchdog accordingly.
365           */
366          status = _Rate_monotonic_Block_while_active(
367            the_period,
368            length,
369            executing,
370            &lock_context
371          );
372        }
373        break;
374      case RATE_MONOTONIC_INACTIVE:
375        status = _Rate_monotonic_Activate(
376          the_period,
377          length,
378          executing,
379          &lock_context
380        );
381        break;
382      default:
383        /*
384         * As now this period was already TIMEOUT, there must be at least one
385         * postponed job recorded by the watchdog. The one which exceeded
386         * the previous deadlines was just finished.
387         *
388         * Maybe there is more than one job postponed due to the preemption or
389         * the previous finished job.
390         */
391        _Assert( state == RATE_MONOTONIC_EXPIRED );
392        status = _Rate_monotonic_Block_while_expired(
393          the_period,
394          length,
395          executing,
396          &lock_context
397        );
398        break;
399    }
400  }
401
402  return status;
403}
Note: See TracBrowser for help on using the repository browser.