source: rtems/cpukit/score/include/rtems/score/watchdogimpl.h @ 03b900d

5
Last change on this file since 03b900d was 03b900d, checked in by Sebastian Huber <sebastian.huber@…>, on 02/18/16 at 07:36:26

score: Replace watchdog handler implementation

Use a red-black tree instead of delta chains.

Close #2344.
Update #2554.
Update #2555.
Close #2606.

  • Property mode set to 100644
File size: 9.7 KB
Line 
1/**
2 * @file
3 *
4 * @brief Inlined Routines in the Watchdog Handler
5 *
6 * This file contains the static inline implementation of all inlined
7 * routines in the Watchdog Handler.
8 */
9
10/*
11 *  COPYRIGHT (c) 1989-2004.
12 *  On-Line Applications Research Corporation (OAR).
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#ifndef _RTEMS_SCORE_WATCHDOGIMPL_H
20#define _RTEMS_SCORE_WATCHDOGIMPL_H
21
22#include <rtems/score/watchdog.h>
23#include <rtems/score/assert.h>
24#include <rtems/score/isrlock.h>
25#include <rtems/score/percpu.h>
26#include <rtems/score/rbtreeimpl.h>
27
28#include <sys/timespec.h>
29
30#ifdef __cplusplus
31extern "C" {
32#endif
33
34/**
35 *  @addtogroup ScoreWatchdog
36 *  @{
37 */
38
39/**
40 * @brief Watchdog states.
41 */
42typedef enum {
43  /**
44   * @brief The watchdog is scheduled and a black node in the red-black tree.
45   */
46  WATCHDOG_SCHEDULED_BLACK,
47
48  /**
49   * @brief The watchdog is scheduled and a red node in the red-black tree.
50   */
51  WATCHDOG_SCHEDULED_RED,
52
53  /**
54   * @brief The watchdog is inactive.
55   */
56  WATCHDOG_INACTIVE,
57
58  /**
59   * @brief The watchdog is on a chain of pending watchdogs.
60   *
61   * This state is used by the timer server for example.
62   */
63  WATCHDOG_PENDING
64} Watchdog_State;
65
66/**
67 * @brief Watchdog initializer for static initialization.
68 *
69 * The processor of this watchdog is set to processor with index zero.
70 *
71 * @see _Watchdog_Preinitialize().
72 */
73#if defined(RTEMS_SMP)
74  #define WATCHDOG_INITIALIZER( routine ) \
75    { \
76      { { { NULL, NULL, NULL, WATCHDOG_INACTIVE } } }, \
77      &_Per_CPU_Information[ 0 ].per_cpu, \
78      ( routine ), \
79      0 \
80    }
81#else
82  #define WATCHDOG_INITIALIZER( routine ) \
83    { \
84      { { { NULL, NULL, NULL, WATCHDOG_INACTIVE } } }, \
85      ( routine ), \
86      0 \
87    }
88#endif
89
90RTEMS_INLINE_ROUTINE void _Watchdog_Header_initialize(
91  Watchdog_Header *header
92)
93{
94  _RBTree_Initialize_empty( &header->Watchdogs );
95  header->first = NULL;
96}
97
98RTEMS_INLINE_ROUTINE void _Watchdog_Header_destroy(
99  Watchdog_Header *header
100)
101{
102  /* Do nothing */
103  (void) header;
104}
105
106/**
107 *  @brief Performs a watchdog tick.
108 *
109 *  @param cpu The processor for this watchdog tick.
110 */
111void _Watchdog_Tick( struct Per_CPU_Control *cpu );
112
113RTEMS_INLINE_ROUTINE Watchdog_State _Watchdog_Get_state(
114  const Watchdog_Control *the_watchdog
115)
116{
117  return RB_COLOR( &the_watchdog->Node.RBTree, Node );
118}
119
120RTEMS_INLINE_ROUTINE void _Watchdog_Set_state(
121  Watchdog_Control *the_watchdog,
122  Watchdog_State    state
123)
124{
125  RB_COLOR( &the_watchdog->Node.RBTree, Node ) = state;
126}
127
128RTEMS_INLINE_ROUTINE Per_CPU_Control *_Watchdog_Get_CPU(
129  const Watchdog_Control *the_watchdog
130)
131{
132#if defined(RTEMS_SMP)
133  return the_watchdog->cpu;
134#else
135  return _Per_CPU_Get_by_index( 0 );
136#endif
137}
138
139RTEMS_INLINE_ROUTINE void _Watchdog_Set_CPU(
140  Watchdog_Control *the_watchdog,
141  Per_CPU_Control  *cpu
142)
143{
144#if defined(RTEMS_SMP)
145  the_watchdog->cpu = cpu;
146#else
147  (void) cpu;
148#endif
149}
150
151/**
152 * @brief Pre-initializes a watchdog.
153 *
154 * This routine must be called before a watchdog is used in any way.  The
155 * exception are statically initialized watchdogs via WATCHDOG_INITIALIZER().
156 *
157 * @param[in] the_watchdog The uninitialized watchdog.
158 */
159RTEMS_INLINE_ROUTINE void _Watchdog_Preinitialize(
160  Watchdog_Control *the_watchdog,
161  Per_CPU_Control  *cpu
162)
163{
164  _Watchdog_Set_CPU( the_watchdog, cpu );
165  _Watchdog_Set_state( the_watchdog, WATCHDOG_INACTIVE );
166
167#if defined(RTEMS_DEBUG)
168  the_watchdog->routine = NULL;
169  the_watchdog->expire = 0;
170#endif
171}
172
173/**
174 * @brief Initializes a watchdog with a new service routine.
175 *
176 * The watchdog must be inactive.
177 */
178RTEMS_INLINE_ROUTINE void _Watchdog_Initialize(
179  Watchdog_Control               *the_watchdog,
180  Watchdog_Service_routine_entry  routine
181)
182{
183  _Assert( _Watchdog_Get_state( the_watchdog ) == WATCHDOG_INACTIVE );
184  the_watchdog->routine = routine;
185}
186
187void _Watchdog_Do_tickle(
188  Watchdog_Header  *header,
189  uint64_t          now,
190#if defined(RTEMS_SMP)
191  ISR_lock_Control *lock,
192#endif
193  ISR_lock_Context *lock_context
194);
195
196#if defined(RTEMS_SMP)
197  #define _Watchdog_Tickle( header, now, lock, lock_context ) \
198    _Watchdog_Do_tickle( header, now, lock, lock_context )
199#else
200  #define _Watchdog_Tickle( header, now, lock, lock_context ) \
201    _Watchdog_Do_tickle( header, now, lock_context )
202#endif
203
204/**
205 * @brief Inserts a watchdog into the set of scheduled watchdogs according to
206 * the specified expiration time.
207 *
208 * The watchdog must be inactive.
209 */
210void _Watchdog_Insert(
211  Watchdog_Header  *header,
212  Watchdog_Control *the_watchdog,
213  uint64_t          expire
214);
215
216/**
217 * @brief In case the watchdog is scheduled, then it is removed from the set of
218 * scheduled watchdogs.
219 *
220 * The watchdog must be initialized before this call.
221 */
222void _Watchdog_Remove(
223  Watchdog_Header  *header,
224  Watchdog_Control *the_watchdog
225);
226
227/**
228 * @brief In case the watchdog is scheduled, then it is removed from the set of
229 * scheduled watchdogs.
230 *
231 * The watchdog must be initialized before this call.
232 *
233 * @retval 0 The now time is greater than or equal to the expiration time of
234 * the watchdog.
235 * @retval other The difference of the now and expiration time.
236 */
237RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Cancel(
238  Watchdog_Header  *header,
239  Watchdog_Control *the_watchdog,
240  uint64_t          now
241)
242{
243  uint64_t expire;
244  uint64_t remaining;
245
246  expire = the_watchdog->expire;
247
248  if ( now < expire ) {
249    remaining = expire - now;
250  } else {
251    remaining = 0;
252  }
253
254  _Watchdog_Remove( header, the_watchdog );
255
256  return remaining;
257}
258
259RTEMS_INLINE_ROUTINE bool _Watchdog_Is_scheduled(
260  const Watchdog_Control *the_watchdog
261)
262{
263  return _Watchdog_Get_state( the_watchdog ) < WATCHDOG_INACTIVE;
264}
265
266RTEMS_INLINE_ROUTINE void _Watchdog_Next_first(
267  Watchdog_Header  *header,
268  Watchdog_Control *the_watchdog
269)
270{
271  RBTree_Node *node = _RBTree_Right( &the_watchdog->Node.RBTree );
272
273  if ( node != NULL ) {
274    RBTree_Node *left;
275
276    while ( ( left = _RBTree_Left( node ) ) != NULL ) {
277      node = left;
278    }
279
280    header->first = node;
281  } else {
282    header->first = _RBTree_Parent( &the_watchdog->Node.RBTree );
283  }
284}
285
286/**
287 * @brief The bits necessary to store 1000000000 nanoseconds.
288 *
289 * The expiration time is an unsigned 64-bit integer.  To store absolute
290 * timeouts we use 30 bits (2**30 == 1073741824) for the nanoseconds and 34
291 * bits for the seconds since UNIX Epoch.  This leads to a year 2514 problem.
292 */
293#define WATCHDOG_BITS_FOR_1E9_NANOSECONDS 30
294
295RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Ticks_from_seconds(
296  uint32_t seconds
297)
298{
299  uint64_t ticks = seconds;
300
301  ticks <<= WATCHDOG_BITS_FOR_1E9_NANOSECONDS;
302
303  return ticks;
304}
305
306RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Ticks_from_timespec(
307  const struct timespec *ts
308)
309{
310  /*
311   * The seconds are in time_t which is a signed integer.  Thus this cast is
312   * subject to the year 2038 problem in case time_t is a 32-bit integer.
313   */
314  uint64_t ticks = (uint64_t) ts->tv_sec;
315
316  _Assert( ticks < 0x400000000 );
317  _Assert( ts->tv_nsec >= 0 );
318  _Assert( ts->tv_nsec < 1000000000 );
319
320  ticks <<= WATCHDOG_BITS_FOR_1E9_NANOSECONDS;
321  ticks |= ts->tv_nsec;
322
323  return ticks;
324}
325
326RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_acquire_critical(
327  Per_CPU_Control  *cpu,
328  ISR_lock_Context *lock_context
329)
330{
331  _ISR_lock_Acquire( &cpu->Watchdog.Lock, lock_context );
332}
333
334RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_release_critical(
335  Per_CPU_Control  *cpu,
336  ISR_lock_Context *lock_context
337)
338{
339  _ISR_lock_Release( &cpu->Watchdog.Lock, lock_context );
340}
341
342RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_insert_relative(
343  Watchdog_Control *the_watchdog,
344  Per_CPU_Control  *cpu,
345  uint32_t          ticks
346)
347{
348  ISR_lock_Context lock_context;
349
350  _Watchdog_Set_CPU( the_watchdog, cpu );
351
352  _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context );
353  _Watchdog_Insert(
354    &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ],
355    the_watchdog,
356    cpu->Watchdog.ticks + ticks
357  );
358  _Watchdog_Per_CPU_release_critical( cpu, &lock_context );
359}
360
361RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_insert_absolute(
362  Watchdog_Control *the_watchdog,
363  Per_CPU_Control  *cpu,
364  uint64_t          expire
365)
366{
367  ISR_lock_Context lock_context;
368
369  _Watchdog_Set_CPU( the_watchdog, cpu );
370
371  _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context );
372  _Watchdog_Insert(
373    &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_ABSOLUTE ],
374    the_watchdog,
375    expire
376  );
377  _Watchdog_Per_CPU_release_critical( cpu, &lock_context );
378}
379
380RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove(
381  Watchdog_Control *the_watchdog,
382  Per_CPU_Control  *cpu,
383  Watchdog_Header  *header
384)
385{
386  ISR_lock_Context lock_context;
387
388  _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context );
389  _Watchdog_Remove(
390    header,
391    the_watchdog
392  );
393  _Watchdog_Per_CPU_release_critical( cpu, &lock_context );
394}
395
396RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove_relative(
397  Watchdog_Control *the_watchdog
398)
399{
400  Per_CPU_Control *cpu;
401
402  cpu = _Watchdog_Get_CPU( the_watchdog );
403  _Watchdog_Per_CPU_remove(
404    the_watchdog,
405    cpu,
406    &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ]
407  );
408}
409
410RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove_absolute(
411  Watchdog_Control *the_watchdog
412)
413{
414  Per_CPU_Control *cpu;
415
416  cpu = _Watchdog_Get_CPU( the_watchdog );
417  _Watchdog_Per_CPU_remove(
418    the_watchdog,
419    cpu,
420    &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_ABSOLUTE ]
421  );
422}
423
424RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_tickle_absolute(
425  Per_CPU_Control *cpu,
426  uint64_t         now
427)
428{
429  ISR_lock_Context lock_context;
430
431  _ISR_lock_ISR_disable_and_acquire( &cpu->Watchdog.Lock, &lock_context );
432  _Watchdog_Tickle(
433    &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_ABSOLUTE ],
434    now,
435    &cpu->Watchdog.Lock,
436    &lock_context
437  );
438}
439
440/** @} */
441
442#ifdef __cplusplus
443}
444#endif
445
446#endif
447/* end of include file */
Note: See TracBrowser for help on using the repository browser.