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

Last change on this file since ccc6695 was ccc6695, checked in by Sebastian Huber <sebastian.huber@…>, on Nov 8, 2018 at 10:50:24 AM

score: Introduce <rtems/score/watchdogticks.h>

Separate the definitions related to watchdog ticks from the watchdog
structures.

Update #3598.

  • 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 ScoreWatchdog
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(
402  sbintime_t sbt
403)
404{
405  uint64_t ticks = ( sbt >> 32 ) << WATCHDOG_BITS_FOR_1E9_NANOSECONDS;
406
407  ticks |= ( (uint64_t) 1000000000 * (uint32_t) sbt ) >> 32;
408
409  return ticks;
410}
411
412RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_acquire_critical(
413  Per_CPU_Control  *cpu,
414  ISR_lock_Context *lock_context
415)
416{
417  _ISR_lock_Acquire( &cpu->Watchdog.Lock, lock_context );
418}
419
420RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_release_critical(
421  Per_CPU_Control  *cpu,
422  ISR_lock_Context *lock_context
423)
424{
425  _ISR_lock_Release( &cpu->Watchdog.Lock, lock_context );
426}
427
428RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Per_CPU_insert_ticks(
429  Watchdog_Control  *the_watchdog,
430  Per_CPU_Control   *cpu,
431  Watchdog_Interval  ticks
432)
433{
434  ISR_lock_Context  lock_context;
435  Watchdog_Header  *header;
436  uint64_t          expire;
437
438  header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_TICKS ];
439
440  _Watchdog_Set_CPU( the_watchdog, cpu );
441
442  _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context );
443  expire = ticks + cpu->Watchdog.ticks;
444  _Watchdog_Insert(header, the_watchdog, expire);
445  _Watchdog_Per_CPU_release_critical( cpu, &lock_context );
446  return expire;
447}
448
449RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Per_CPU_insert(
450  Watchdog_Control *the_watchdog,
451  Per_CPU_Control  *cpu,
452  Watchdog_Header  *header,
453  uint64_t          expire
454)
455{
456  ISR_lock_Context lock_context;
457
458  _Watchdog_Set_CPU( the_watchdog, cpu );
459
460  _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context );
461  _Watchdog_Insert( header, the_watchdog, expire );
462  _Watchdog_Per_CPU_release_critical( cpu, &lock_context );
463  return expire;
464}
465
466RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove(
467  Watchdog_Control *the_watchdog,
468  Per_CPU_Control  *cpu,
469  Watchdog_Header  *header
470)
471{
472  ISR_lock_Context lock_context;
473
474  _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context );
475  _Watchdog_Remove(
476    header,
477    the_watchdog
478  );
479  _Watchdog_Per_CPU_release_critical( cpu, &lock_context );
480}
481
482RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove_ticks(
483  Watchdog_Control *the_watchdog
484)
485{
486  Per_CPU_Control *cpu;
487
488  cpu = _Watchdog_Get_CPU( the_watchdog );
489  _Watchdog_Per_CPU_remove(
490    the_watchdog,
491    cpu,
492    &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_TICKS ]
493  );
494}
495
496/** @} */
497
498#ifdef __cplusplus
499}
500#endif
501
502#endif
503/* end of include file */
Note: See TracBrowser for help on using the repository browser.