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

5
Last change on this file since 3a4e044 was 3a4e044, checked in by Sebastian Huber <sebastian.huber@…>, on 12/22/17 at 09:35:47

score: Rename _Watchdog_Realtime_from_*()

Rename _Watchdog_Realtime_from_*() to _Watchdog_Ticks_from_*().

Update #3264.

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