source: rtems/cpukit/include/rtems/score/watchdogimpl.h @ c5b7942

5
Last change on this file since c5b7942 was c5b7942, checked in by Chris Johns <chrisj@…>, on 08/19/22 at 05:22:17

cpukit/include: Fix including in C++

Closes #4709

  • Property mode set to 100644
File size: 16.5 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup RTEMSScoreWatchdog
5 *
6 * @brief Inlined Routines in the Watchdog Handler
7 *
8 * This file contains the static inline implementation of all inlined
9 * routines in the Watchdog Handler.
10 */
11
12/*
13 *  COPYRIGHT (c) 1989-2004.
14 *  On-Line Applications Research Corporation (OAR).
15 *
16 *  The license and distribution terms for this file may be
17 *  found in the file LICENSE in this distribution or at
18 *  http://www.rtems.org/license/LICENSE.
19 */
20
21#ifndef _RTEMS_SCORE_WATCHDOGIMPL_H
22#define _RTEMS_SCORE_WATCHDOGIMPL_H
23
24#include <rtems/score/watchdog.h>
25#include <rtems/score/watchdogticks.h>
26#include <rtems/score/assert.h>
27#include <rtems/score/isrlock.h>
28#include <rtems/score/percpu.h>
29#include <rtems/score/rbtreeimpl.h>
30
31#include <sys/types.h>
32#include <sys/timespec.h>
33
34#ifdef __cplusplus
35extern "C" {
36#endif
37
38/**
39 * @addtogroup RTEMSScoreWatchdog
40 *
41 * @{
42 */
43
44/**
45 * @brief Watchdog states.
46 */
47typedef enum {
48  /**
49   * @brief The watchdog is scheduled and a black node in the red-black tree.
50   */
51  WATCHDOG_SCHEDULED_BLACK,
52
53  /**
54   * @brief The watchdog is scheduled and a red node in the red-black tree.
55   */
56  WATCHDOG_SCHEDULED_RED,
57
58  /**
59   * @brief The watchdog is inactive.
60   */
61  WATCHDOG_INACTIVE,
62
63  /**
64   * @brief The watchdog is on a chain of pending watchdogs.
65   *
66   * This state is used by the timer server for example.
67   */
68  WATCHDOG_PENDING
69} Watchdog_State;
70
71/**
72 * @brief Watchdog initializer for static initialization.
73 *
74 * The processor of this watchdog is set to processor with index zero.
75 *
76 * @see _Watchdog_Preinitialize().
77 */
78#if defined(RTEMS_SMP)
79  #define WATCHDOG_INITIALIZER( routine ) \
80    { \
81      { { { NULL, NULL, NULL, WATCHDOG_INACTIVE } } }, \
82      &_Per_CPU_Information[ 0 ].per_cpu, \
83      ( routine ), \
84      0 \
85    }
86#else
87  #define WATCHDOG_INITIALIZER( routine ) \
88    { \
89      { { { NULL, NULL, NULL, WATCHDOG_INACTIVE } } }, \
90      ( routine ), \
91      0 \
92    }
93#endif
94
95/**
96 * @brief Initializes the watchdog header.
97 *
98 * @param[out] header The header to initialize.
99 */
100RTEMS_INLINE_ROUTINE void _Watchdog_Header_initialize(
101  Watchdog_Header *header
102)
103{
104  _RBTree_Initialize_empty( &header->Watchdogs );
105  header->first = NULL;
106}
107
108/**
109 * @brief Returns the first of the watchdog header.
110 *
111 * @param header The watchdog header to remove the first of.
112 *
113 * @return The first of @a header.
114 */
115RTEMS_INLINE_ROUTINE Watchdog_Control *_Watchdog_Header_first(
116  const Watchdog_Header *header
117)
118{
119  return (Watchdog_Control *) header->first;
120}
121
122/**
123 * @brief Destroys the watchdog header.
124 *
125 * @param header The watchdog header to destroy.
126 */
127RTEMS_INLINE_ROUTINE void _Watchdog_Header_destroy(
128  Watchdog_Header *header
129)
130{
131  /* Do nothing */
132  (void) header;
133}
134
135/**
136 * @brief Performs a watchdog tick.
137 *
138 * @param cpu The processor for this watchdog tick.
139 */
140void _Watchdog_Tick( struct Per_CPU_Control *cpu );
141
142/**
143 * @brief Gets the state of the watchdog.
144 *
145 * @param the_watchdog The watchdog to get the state of.
146 *
147 * @return The RB_COLOR of @a the_watchdog.
148 */
149RTEMS_INLINE_ROUTINE Watchdog_State _Watchdog_Get_state(
150  const Watchdog_Control *the_watchdog
151)
152{
153  return (Watchdog_State) RB_COLOR( &the_watchdog->Node.RBTree, Node );
154}
155
156/**
157 * @brief Sets the state of the watchdog.
158 *
159 * @param[out] the_watchdog The watchdog to set the state of.
160 * @param state The state to set the watchdog to.
161 */
162RTEMS_INLINE_ROUTINE void _Watchdog_Set_state(
163  Watchdog_Control *the_watchdog,
164  Watchdog_State    state
165)
166{
167  RB_COLOR( &the_watchdog->Node.RBTree, Node ) = state;
168}
169
170/**
171 * @brief Gets the watchdog's cpu.
172 *
173 * @param the_watchdog The watchdog to get the cpu of.
174 *
175 * @return The cpu of the watchdog.
176 */
177RTEMS_INLINE_ROUTINE Per_CPU_Control *_Watchdog_Get_CPU(
178  const Watchdog_Control *the_watchdog
179)
180{
181#if defined(RTEMS_SMP)
182  return the_watchdog->cpu;
183#else
184  return _Per_CPU_Get_by_index( 0 );
185#endif
186}
187
188/**
189 * @brief Sets the cpu for the watchdog.
190 *
191 * @param[out] the_watchdog The watchdog to set the cpu of.
192 * @param cpu The cpu to be set as @a the_watchdog's cpu.
193 */
194RTEMS_INLINE_ROUTINE void _Watchdog_Set_CPU(
195  Watchdog_Control *the_watchdog,
196  Per_CPU_Control  *cpu
197)
198{
199#if defined(RTEMS_SMP)
200  the_watchdog->cpu = cpu;
201#else
202  (void) cpu;
203#endif
204}
205
206/**
207 * @brief Pre-initializes a watchdog.
208 *
209 * This routine must be called before a watchdog is used in any way.  The
210 * exception are statically initialized watchdogs via WATCHDOG_INITIALIZER().
211 *
212 * @param[out] the_watchdog The uninitialized watchdog.
213 */
214RTEMS_INLINE_ROUTINE void _Watchdog_Preinitialize(
215  Watchdog_Control *the_watchdog,
216  Per_CPU_Control  *cpu
217)
218{
219  _Watchdog_Set_CPU( the_watchdog, cpu );
220  _Watchdog_Set_state( the_watchdog, WATCHDOG_INACTIVE );
221
222#if defined(RTEMS_DEBUG)
223  the_watchdog->routine = NULL;
224  the_watchdog->expire = 0;
225#endif
226}
227
228/**
229 * @brief Initializes a watchdog with a new service routine.
230 *
231 * The watchdog must be inactive.
232 *
233 * @param[out] the_watchdog The watchdog to initialize.
234 * @param routing The service routine for @a the_watchdog.
235 */
236RTEMS_INLINE_ROUTINE void _Watchdog_Initialize(
237  Watchdog_Control               *the_watchdog,
238  Watchdog_Service_routine_entry  routine
239)
240{
241  _Assert( _Watchdog_Get_state( the_watchdog ) == WATCHDOG_INACTIVE );
242  the_watchdog->routine = routine;
243}
244
245/**
246 * @brief Calls the routine of each not expired watchdog control node.
247 *
248 * @param header The watchdog header.
249 * @param first The first watchdog control node.
250 * @param now The current time to check the expiration time against.
251 * @param lock The lock that is released before calling the routine and then
252 *      acquired after the call.
253 * @param lock_context The lock context for the release before calling the
254 *      routine and for the acquire after.
255 */
256void _Watchdog_Do_tickle(
257  Watchdog_Header  *header,
258  Watchdog_Control *first,
259  uint64_t          now,
260#if defined(RTEMS_SMP)
261  ISR_lock_Control *lock,
262#endif
263  ISR_lock_Context *lock_context
264);
265
266#if defined(RTEMS_SMP)
267  #define _Watchdog_Tickle( header, first, now, lock, lock_context ) \
268    _Watchdog_Do_tickle( header, first, now, lock, lock_context )
269#else
270  #define _Watchdog_Tickle( header, first, now, lock, lock_context ) \
271    _Watchdog_Do_tickle( header, first, now, lock_context )
272#endif
273
274/**
275 * @brief Inserts a watchdog into the set of scheduled watchdogs according to
276 * the specified expiration time.
277 *
278 * The watchdog must be inactive.
279 *
280 * @param[in, out] header The set of scheduler watchdogs to insert into.
281 * @param[in, out] the_watchdog The watchdog to insert.
282 * @param expire The expiration time for the watchdog.
283 */
284void _Watchdog_Insert(
285  Watchdog_Header  *header,
286  Watchdog_Control *the_watchdog,
287  uint64_t          expire
288);
289
290/**
291 * @brief In the case the watchdog is scheduled, then it is removed from the set of
292 * scheduled watchdogs.
293 *
294 * The watchdog must be initialized before this call.
295 *
296 * @param[in, out] header The scheduled watchdogs.
297 * @param[in, out] the_watchdog The watchdog to remove.
298 */
299void _Watchdog_Remove(
300  Watchdog_Header  *header,
301  Watchdog_Control *the_watchdog
302);
303
304/**
305 * @brief In the case the watchdog is scheduled, then it is removed from the set of
306 * scheduled watchdogs.
307 *
308 * The watchdog must be initialized before this call.
309 *
310 * @param[in, out] header The scheduled watchdogs.
311 * @param[in, out] the_watchdog The watchdog to remove.
312 * @param now The current time.
313 *
314 * @retval other The difference of the now and expiration time.
315 * @retval 0 The now time is greater than or equal to the expiration time of
316 * the watchdog.
317 */
318RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Cancel(
319  Watchdog_Header  *header,
320  Watchdog_Control *the_watchdog,
321  uint64_t          now
322)
323{
324  uint64_t expire;
325  uint64_t remaining;
326
327  expire = the_watchdog->expire;
328
329  if ( now < expire ) {
330    remaining = expire - now;
331  } else {
332    remaining = 0;
333  }
334
335  _Watchdog_Remove( header, the_watchdog );
336
337  return remaining;
338}
339
340/**
341 * @brief Checks if the watchdog is scheduled.
342 *
343 * @param the_watchdog The watchdog for the verification.
344 *
345 * @retval true The watchdog is scheduled.
346 * @retval false The watchdog is inactive.
347 */
348RTEMS_INLINE_ROUTINE bool _Watchdog_Is_scheduled(
349  const Watchdog_Control *the_watchdog
350)
351{
352  return _Watchdog_Get_state( the_watchdog ) < WATCHDOG_INACTIVE;
353}
354
355/**
356 * @brief Sets the first node of the header.
357 *
358 * Sets the first node of the header to either the leftmost child node of the
359 *  watchdog control node, or if not present sets it to the right child node of
360 * the watchdog control node. if both are not present, the new first node is
361 * the parent node of the current first node.
362 *
363 * @param[in, out] header The watchdog header.
364 * @param the_watchdog The watchdog control node for the operation.
365 */
366RTEMS_INLINE_ROUTINE void _Watchdog_Next_first(
367  Watchdog_Header  *header,
368  Watchdog_Control *the_watchdog
369)
370{
371  RBTree_Node *node = _RBTree_Right( &the_watchdog->Node.RBTree );
372
373  if ( node != NULL ) {
374    RBTree_Node *left;
375
376    while ( ( left = _RBTree_Left( node ) ) != NULL ) {
377      node = left;
378    }
379
380    header->first = node;
381  } else {
382    header->first = _RBTree_Parent( &the_watchdog->Node.RBTree );
383  }
384}
385
386/**
387 * @brief The maximum watchdog ticks value for the far future.
388 */
389#define WATCHDOG_MAXIMUM_TICKS UINT64_MAX
390
391#define WATCHDOG_NANOSECONDS_PER_SECOND 1000000000
392
393/**
394 * @brief The bits necessary to store 1000000000
395 * (= WATCHDOG_NANOSECONDS_PER_SECOND) nanoseconds.
396 *
397 * The expiration time is an unsigned 64-bit integer.  To store nanoseconds
398 * timeouts we use 30 bits (2**30 == 1073741824) for the nanoseconds and 34
399 * bits for the seconds since UNIX Epoch.  This leads to a year 2514 problem.
400 */
401#define WATCHDOG_BITS_FOR_1E9_NANOSECONDS 30
402
403/**
404 * @brief The maximum number of seconds representable in the nanoseconds
405 * watchdog format.
406 *
407 * We have 2**34 bits for the seconds part.
408 */
409#define WATCHDOG_MAX_SECONDS 0x3ffffffff
410
411/**
412 * @brief Checks if the timespec is a valid timespec for a watchdog.
413 *
414 * @param ts The timespec for the verification.
415 *
416 * @retval true The timespec is a valid timespec.
417 * @retval false The timespec is invalid.
418 */
419RTEMS_INLINE_ROUTINE bool _Watchdog_Is_valid_timespec(
420  const struct timespec *ts
421)
422{
423  return ts != NULL
424    && (unsigned long) ts->tv_nsec < WATCHDOG_NANOSECONDS_PER_SECOND;
425}
426
427/**
428 * @brief Checks if the timespec is a valid interval timespec for a watchdog.
429 *
430 * @param ts The timespec for the verification.
431 *
432 * @retval true The timespec is a valid interval timespec.
433 * @retval false The timespec is invalid.
434 */
435RTEMS_INLINE_ROUTINE bool _Watchdog_Is_valid_interval_timespec(
436  const struct timespec *ts
437)
438{
439  return _Watchdog_Is_valid_timespec( ts ) && ts->tv_sec >= 0;
440}
441
442/**
443 * @brief Adds the delta timespec to the current time if the delta is a valid
444 * interval timespec.
445 *
446 * @param[in, out] now The current time.
447 * @param delta The delta timespec for the addition.
448 *
449 * @retval pointer Pointer to the now timespec.
450 * @retval NULL @a delta is not a valid interval timespec.
451 */
452RTEMS_INLINE_ROUTINE const struct timespec * _Watchdog_Future_timespec(
453  struct timespec       *now,
454  const struct timespec *delta
455)
456{
457  uint64_t sec;
458
459  if ( !_Watchdog_Is_valid_interval_timespec( delta ) ) {
460    return NULL;
461  }
462
463  sec = (uint64_t) now->tv_sec;
464  sec += (uint64_t) delta->tv_sec;
465  now->tv_nsec += delta->tv_nsec;
466
467  /* We have 2 * (2**63 - 1) + 1 == UINT64_MAX */
468  if ( now->tv_nsec >= WATCHDOG_NANOSECONDS_PER_SECOND ) {
469    now->tv_nsec -= WATCHDOG_NANOSECONDS_PER_SECOND;
470    ++sec;
471  }
472
473  if ( sec <= INT64_MAX ) {
474    now->tv_sec = sec;
475  } else {
476    now->tv_sec = INT64_MAX;
477  }
478
479  return now;
480}
481
482/**
483 * @brief Checks if the timespec is too far in the future.
484 *
485 * @param ts The timespec for the verification.
486 *
487 * @retval true @a ts is too far in the future.
488 * @retval false @a ts is not too far in the future.
489 */
490RTEMS_INLINE_ROUTINE bool _Watchdog_Is_far_future_timespec(
491  const struct timespec *ts
492)
493{
494  return ts->tv_sec > WATCHDOG_MAX_SECONDS;
495}
496
497/**
498 * @brief Converts the seconds to ticks.
499 *
500 * @param seconds The seconds to convert to ticks.
501 *
502 * @return @a seconds converted to ticks.
503 */
504RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Ticks_from_seconds(
505  uint32_t seconds
506)
507{
508  uint64_t ticks = seconds;
509
510  ticks <<= WATCHDOG_BITS_FOR_1E9_NANOSECONDS;
511
512  return ticks;
513}
514
515/**
516 * @brief Converts the timespec in ticks.
517 *
518 * @param ts The timespec to convert to ticks.
519 *
520 * @return @a ts converted to ticks.
521 */
522RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Ticks_from_timespec(
523  const struct timespec *ts
524)
525{
526  uint64_t ticks;
527
528  _Assert( _Watchdog_Is_valid_timespec( ts ) );
529  _Assert( ts->tv_sec >= 0 );
530  _Assert( !_Watchdog_Is_far_future_timespec( ts ) );
531
532  ticks = (uint64_t) ts->tv_sec;
533  ticks <<= WATCHDOG_BITS_FOR_1E9_NANOSECONDS;
534  ticks |= (uint32_t) ts->tv_nsec;
535
536  return ticks;
537}
538
539/**
540 * @brief Converts the sbintime in ticks.
541 *
542 * @param sbt The sbintime to convert to ticks.
543 *
544 * @return @a sbt converted to ticks.
545 */
546RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Ticks_from_sbintime( int64_t sbt )
547{
548  uint64_t ticks = ( sbt >> 32 ) << WATCHDOG_BITS_FOR_1E9_NANOSECONDS;
549
550  ticks |= ( (uint64_t) 1000000000 * (uint32_t) sbt ) >> 32;
551
552  return ticks;
553}
554
555/**
556 * @brief Acquires the per cpu watchdog lock in a critical section.
557 *
558 * @param cpu The cpu to acquire the watchdog lock of.
559 * @param lock_context The lock context.
560 */
561RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_acquire_critical(
562  Per_CPU_Control  *cpu,
563  ISR_lock_Context *lock_context
564)
565{
566  _ISR_lock_Acquire( &cpu->Watchdog.Lock, lock_context );
567}
568
569/**
570 * @brief Releases the per cpu watchdog lock in a critical section.
571 *
572 * @param cpu The cpu to release the watchdog lock of.
573 * @param lock_context The lock context.
574 */
575RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_release_critical(
576  Per_CPU_Control  *cpu,
577  ISR_lock_Context *lock_context
578)
579{
580  _ISR_lock_Release( &cpu->Watchdog.Lock, lock_context );
581}
582
583/**
584 * @brief Sets the watchdog's cpu to the given instance and sets its expiration
585 *      time to the watchdog expiration time of the cpu plus the ticks.
586 *
587 * @param[in, out] the_watchdog The watchdog to set the cpu and expiration time of.
588 * @param cpu The cpu for the watchdog.
589 * @param ticks The ticks to add to the expiration time.
590 *
591 * @return The new expiration time of the watchdog.
592 */
593RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Per_CPU_insert_ticks(
594  Watchdog_Control  *the_watchdog,
595  Per_CPU_Control   *cpu,
596  Watchdog_Interval  ticks
597)
598{
599  ISR_lock_Context  lock_context;
600  Watchdog_Header  *header;
601  uint64_t          expire;
602
603  header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_TICKS ];
604
605  _Watchdog_Set_CPU( the_watchdog, cpu );
606
607  _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context );
608  expire = ticks + cpu->Watchdog.ticks;
609  _Watchdog_Insert(header, the_watchdog, expire);
610  _Watchdog_Per_CPU_release_critical( cpu, &lock_context );
611  return expire;
612}
613
614/**
615 * @brief Sets the watchdog's cpu and inserts it with the given expiration time
616 *      in the scheduled watchdogs.
617 *
618 * @param[in, out] the_watchdog The watchdog to set cpu and expiration time of.
619 * @param cpu The cpu for the operation.
620 * @param[in, out] header The scheduled watchdogs.
621 * @param expire The expiration time for the watchdog.
622 *
623 * @return The expiration time of the watchdog.
624 */
625RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Per_CPU_insert(
626  Watchdog_Control *the_watchdog,
627  Per_CPU_Control  *cpu,
628  Watchdog_Header  *header,
629  uint64_t          expire
630)
631{
632  ISR_lock_Context lock_context;
633
634  _Watchdog_Set_CPU( the_watchdog, cpu );
635
636  _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context );
637  _Watchdog_Insert( header, the_watchdog, expire );
638  _Watchdog_Per_CPU_release_critical( cpu, &lock_context );
639  return expire;
640}
641
642/**
643 * @brief Removes the watchdog from the cpu and the scheduled watchdogs.
644 *
645 * @param[in, out] the_watchdog The watchdog to remove.
646 * @param cpu The cpu to remove the watchdog from.
647 * @param[in, out] The scheduled watchdogs.
648 */
649RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove(
650  Watchdog_Control *the_watchdog,
651  Per_CPU_Control  *cpu,
652  Watchdog_Header  *header
653)
654{
655  ISR_lock_Context lock_context;
656
657  _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context );
658  _Watchdog_Remove(
659    header,
660    the_watchdog
661  );
662  _Watchdog_Per_CPU_release_critical( cpu, &lock_context );
663}
664
665/**
666 * @brief Removes the watchdog from the cpu and the scheduled watchdogs.
667 *
668 * @param[in, out] the_watchdog The watchdog to remove.
669 */
670RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove_ticks(
671  Watchdog_Control *the_watchdog
672)
673{
674  Per_CPU_Control *cpu;
675
676  cpu = _Watchdog_Get_CPU( the_watchdog );
677  _Watchdog_Per_CPU_remove(
678    the_watchdog,
679    cpu,
680    &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_TICKS ]
681  );
682}
683
684/** @} */
685
686#ifdef __cplusplus
687}
688#endif
689
690#endif
691/* end of include file */
Note: See TracBrowser for help on using the repository browser.