source: rtems/cpukit/include/rtems/score/watchdogimpl.h @ 4c20da4b

5
Last change on this file since 4c20da4b was 4c20da4b, checked in by Sebastian Huber <sebastian.huber@…>, on 04/04/19 at 07:18:11

doxygen: Rename Score* groups in RTEMSScore*

Update #3706

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