RTEMS
ratemonperiod.c
Go to the documentation of this file.
1 
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 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
25 #include <rtems/score/todimpl.h>
26 
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 );
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 */
59  &the_period->cpu_usage_period_initiated,
60  &used,
61  cpu_since_last_period
62  );
63 
64  return true;
65 }
66 
67 static 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  Per_CPU_Control *cpu_self;
75  Thread_queue_Context queue_context;
76 
77  --the_period->postponed_jobs;
79  owner,
80  &the_period->Priority,
81  the_period->latest_deadline,
82  &queue_context
83  );
84 
85  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
86  _Rate_monotonic_Release( the_period, lock_context );
87  _Thread_Priority_update( &queue_context );
88  _Thread_Dispatch_direct( cpu_self );
89 }
90 
91 static 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 )
97 {
98  Per_CPU_Control *cpu_self;
99  Thread_queue_Context queue_context;
100  uint64_t deadline;
101 
102  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
103 
105  &the_period->Timer,
106  cpu_self,
107  next_length
108  );
110  owner,
111  &the_period->Priority,
112  deadline,
113  &queue_context
114  );
115 
116  _Rate_monotonic_Release( the_period, lock_context );
117  _Thread_Priority_update( &queue_context );
118  _Thread_Dispatch_enable( cpu_self );
119 }
120 
121 void _Rate_monotonic_Restart(
122  Rate_monotonic_Control *the_period,
123  Thread_Control *owner,
124  ISR_lock_Context *lock_context
125 )
126 {
127  /*
128  * Set the starting point and the CPU time used for the statistics.
129  */
130  _TOD_Get_uptime( &the_period->time_period_initiated );
132 
133  _Rate_monotonic_Release_job(
134  the_period,
135  owner,
136  the_period->next_length,
137  lock_context
138  );
139 }
140 
141 static void _Rate_monotonic_Update_statistics(
142  Rate_monotonic_Control *the_period
143 )
144 {
145  Timestamp_Control executed;
146  Timestamp_Control since_last_period;
148  bool valid_status;
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  /*
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  /*
166  * Grab status for time statistics.
167  */
168  valid_status =
169  _Rate_monotonic_Get_status( the_period, &since_last_period, &executed );
170  if (!valid_status)
171  return;
172 
173  /*
174  * Update CPU time
175  */
176  _Timestamp_Add_to( &stats->total_cpu_time, &executed );
177 
178  if ( _Timestamp_Less_than( &executed, &stats->min_cpu_time ) )
179  stats->min_cpu_time = executed;
180 
181  if ( _Timestamp_Greater_than( &executed, &stats->max_cpu_time ) )
182  stats->max_cpu_time = executed;
183 
184  /*
185  * Update Wall time
186  */
187  _Timestamp_Add_to( &stats->total_wall_time, &since_last_period );
188 
189  if ( _Timestamp_Less_than( &since_last_period, &stats->min_wall_time ) )
190  stats->min_wall_time = since_last_period;
191 
192  if ( _Timestamp_Greater_than( &since_last_period, &stats->max_wall_time ) )
193  stats->max_wall_time = since_last_period;
194 }
195 
196 static rtems_status_code _Rate_monotonic_Get_status_for_state(
198 )
199 {
200  switch ( state ) {
202  return RTEMS_NOT_DEFINED;
204  return RTEMS_TIMEOUT;
205  default:
206  _Assert( state == RATE_MONOTONIC_ACTIVE );
207  return RTEMS_SUCCESSFUL;
208  }
209 }
210 
211 static 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 {
218  the_period->postponed_jobs = 0;
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 
225 static 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 );
250  _Rate_monotonic_Release( the_period, lock_context );
251 
253 
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 
266  _Thread_Dispatch_direct( cpu_self );
267  return RTEMS_SUCCESSFUL;
268 }
269 
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  */
275 static 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  /*
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
290  */
291  _Rate_monotonic_Update_statistics( the_period );
292 
293  the_period->state = RATE_MONOTONIC_ACTIVE;
294  the_period->next_length = length;
295 
296  _Rate_monotonic_Release_postponed_job(
297  the_period,
298  executing,
299  length,
300  lock_context
301  );
302  return RTEMS_TIMEOUT;
303 }
304 
306  rtems_id id,
307  rtems_interval length
308 )
309 {
310  Rate_monotonic_Control *the_period;
311  ISR_lock_Context lock_context;
312  Thread_Control *executing;
313  rtems_status_code status;
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 );
325  }
326 
327  _Rate_monotonic_Acquire_critical( the_period, &lock_context );
328 
329  state = the_period->state;
330 
331  if ( length == RTEMS_PERIOD_STATUS ) {
332  status = _Rate_monotonic_Get_status_for_state( state );
333  _Rate_monotonic_Release( the_period, &lock_context );
334  } else {
335  switch ( state ) {
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  *
344  * Do nothing on the watchdog deadline assignment but release the
345  * next remaining postponed job.
346  */
347  status = _Rate_monotonic_Block_while_expired(
348  the_period,
349  length,
350  executing,
351  &lock_context
352  );
353  }else{
354  /*
355  * Normal case that no postponed jobs and no expiration, so wait for
356  * the period and update the deadline of watchdog accordingly.
357  */
358  status = _Rate_monotonic_Block_while_active(
359  the_period,
360  length,
361  executing,
362  &lock_context
363  );
364  }
365  break;
367  status = _Rate_monotonic_Activate(
368  the_period,
369  length,
370  executing,
371  &lock_context
372  );
373  break;
374  default:
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  */
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  }
392  }
393 
394  return status;
395 }
static __inline__ void _Thread_Unblock(Thread_Control *the_thread)
Unblocks the thread.
Definition: threadimpl.h:965
Timestamp_Control max_wall_time
Definition: ratemondata.h:56
void _Thread_Get_CPU_time_used(Thread_Control *the_thread, Timestamp_Control *cpu_time_used)
Gets the used cpu time of the thread and stores it in the given Timestamp_Control.
static void _TOD_Get_uptime(Timestamp_Control *time)
Gets the system uptime with potential accuracy to the nanosecond.
Definition: todimpl.h:231
int64_t Timestamp_Control
Definition: timestamp.h:57
Timestamp_Control min_cpu_time
Definition: ratemondata.h:47
Thread_Wait_information Wait
Definition: thread.h:767
Thread queue context for the thread queue methods.
Definition: threadq.h:198
void _Thread_Dispatch_direct(Per_CPU_Control *cpu_self)
Directly do a thread dispatch.
static __inline__ bool _Timestamp_Less_than(const Timestamp_Control *_lhs, const Timestamp_Control *_rhs)
Checks if the left hand side timestamp is less than the right one.
Definition: timestampimpl.h:90
Watchdog_Control Timer
Protects the rate monotonic period state.
Definition: ratemondata.h:79
#define RTEMS_PERIOD_STATUS
This constant is the interval passed to the rtems_rate_monotonic_period() directive to obtain status ...
Definition: ratemon.h:345
Inlined Routines Associated with the Manipulation of the Scheduler.
static __inline__ bool _Thread_Wait_flags_try_change_acquire(Thread_Control *the_thread, Thread_Wait_flags expected_flags, Thread_Wait_flags desired_flags)
Tries to change the thread wait flags with acquire semantics.
Definition: threadimpl.h:2300
#define _ISR_lock_ISR_enable(_context)
Restores the saved interrupt state of the ISR lock context.
Definition: isrlock.h:416
#define STATES_WAITING_FOR_PERIOD
Definition: statesimpl.h:78
static __inline__ Thread_Wait_flags _Thread_Wait_flags_get(const Thread_Control *the_thread)
Gets the thread&#39;s wait flags according to the ATOMIC_ORDER_RELAXED.
Definition: threadimpl.h:2215
Thread_Control * owner
Definition: ratemondata.h:100
static __inline__ bool _Timestamp_Greater_than(const Timestamp_Control *_lhs, const Timestamp_Control *_rhs)
Checks if the left hand side timestamp is greater than the right one.
rtems_status_code rtems_rate_monotonic_period(rtems_id id, rtems_interval length)
%
This status code indicates successful completion.
Definition: status.h:86
static __inline__ void _Timestamp_Subtract(const Timestamp_Control *_start, const Timestamp_Control *_end, Timestamp_Control *_result)
Subtracts two timestamps.
static __inline__ Per_CPU_Control * _Thread_Dispatch_disable_critical(const ISR_lock_Context *lock_context)
Disables thread dispatching inside a critical section (interrupts disabled).
Timestamp_Control total_wall_time
Definition: ratemondata.h:58
static __inline__ void _Thread_Wait_flags_set(Thread_Control *the_thread, Thread_Wait_flags flags)
Sets the thread&#39;s wait flags.
Definition: threadimpl.h:2196
rtems_status_code
This enumeration provides status codes for directives of the Classic API.
Definition: status.h:82
Timestamp_Control min_wall_time
Definition: ratemondata.h:54
Per CPU Core Structure.
Definition: percpu.h:347
bool _Rate_monotonic_Get_status(const Rate_monotonic_Control *the_period, Timestamp_Control *wall_since_last_period, Timestamp_Control *cpu_since_last_period)
_Rate_monotonic_Get_status(
Definition: ratemonperiod.c:27
static __inline__ void _Timestamp_Add_to(Timestamp_Control *_time, const Timestamp_Control *_add)
Adds two timestamps.
Rate_monotonic_Statistics Statistics
Definition: ratemondata.h:118
static __inline__ uint64_t _Watchdog_Per_CPU_insert_ticks(Watchdog_Control *the_watchdog, Per_CPU_Control *cpu, Watchdog_Interval ticks)
Sets the watchdog&#39;s cpu to the given instance and sets its expiration time to the watchdog expiration...
Definition: watchdogimpl.h:593
void _Thread_Priority_update(Thread_queue_Context *queue_context)
Updates the priority of all threads in the set.
rtems_rate_monotonic_period_states state
Definition: ratemondata.h:82
Timestamp_Control total_cpu_time
Definition: ratemondata.h:51
void _Thread_Dispatch_enable(Per_CPU_Control *cpu_self)
Enables thread dispatching.
States_Control _Thread_Set_state(Thread_Control *the_thread, States_Control state)
Sets the specified thread state.
Time of Day Handler API.
Timestamp_Control cpu_usage_period_initiated
Definition: ratemondata.h:107
The following structure defines the control block used to manage each period.
Definition: ratemondata.h:69
Watchdog_Interval rtems_interval
This type is used to represent clock tick intervals.
Definition: types.h:90
This status code indicates that the item has not been initialized.
Definition: status.h:143
This status code indicates that an object identifier was invalid.
Definition: status.h:106
This status code indicates that the caller was not the owner of the resource.
Definition: status.h:211
Objects_Id rtems_id
Values of this type identify an RTEMS object.
Definition: types.h:99
This status code indicates that a blocking directive timed out.
Definition: status.h:117
rtems_rate_monotonic_period_states
%
Definition: ratemon.h:87
Timestamp_Control time_period_initiated
Definition: ratemondata.h:113
Classic Rate Monotonic Scheduler Implementation.
Local ISR lock context for acquire and release pairs.
Definition: isrlock.h:65
Timestamp_Control max_cpu_time
Definition: ratemondata.h:49
static __inline__ void _Scheduler_Release_job(Thread_Control *the_thread, Priority_Node *priority_node, uint64_t deadline, Thread_queue_Context *queue_context)
Releases a job of a thread with respect to the scheduler.
Priority_Node Priority
A priority node for use by the scheduler job release and cancel operations.
Definition: ratemondata.h:88
#define _Assert(_e)
Assertion similar to assert() controlled via RTEMS_DEBUG instead of NDEBUG.
Definition: assert.h:100