source: rtems/cpukit/include/rtems/score/watchdogimpl.h @ 3f0ad2b

Last change on this file since 3f0ad2b was a89ecaa1, checked in by Sebastian Huber <sebastian.huber@…>, on 05/18/21 at 10:50:41

score: Simplify thread queue timeout handling

Add Thread_queue_Context::timeout_absolute to specify an absolute or
relative timeout. This avoid having to get the current time twice for
timeouts relative to the current time. It moves also functionality to
common code.

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