summaryrefslogtreecommitdiffstats
path: root/cpukit/include/rtems/score/watchdogimpl.h
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/include/rtems/score/watchdogimpl.h')
-rw-r--r--cpukit/include/rtems/score/watchdogimpl.h574
1 files changed, 574 insertions, 0 deletions
diff --git a/cpukit/include/rtems/score/watchdogimpl.h b/cpukit/include/rtems/score/watchdogimpl.h
new file mode 100644
index 0000000000..f219a70768
--- /dev/null
+++ b/cpukit/include/rtems/score/watchdogimpl.h
@@ -0,0 +1,574 @@
+/**
+ * @file
+ *
+ * @brief Inlined Routines in the Watchdog Handler
+ *
+ * This file contains the static inline implementation of all inlined
+ * routines in the Watchdog Handler.
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2004.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifndef _RTEMS_SCORE_WATCHDOGIMPL_H
+#define _RTEMS_SCORE_WATCHDOGIMPL_H
+
+#include <rtems/score/watchdog.h>
+#include <rtems/score/assert.h>
+#include <rtems/score/isrlock.h>
+#include <rtems/score/percpu.h>
+#include <rtems/score/rbtreeimpl.h>
+
+#include <sys/types.h>
+#include <sys/timespec.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup ScoreWatchdog
+ * @{
+ */
+
+/**
+ * @brief Watchdog states.
+ */
+typedef enum {
+ /**
+ * @brief The watchdog is scheduled and a black node in the red-black tree.
+ */
+ WATCHDOG_SCHEDULED_BLACK,
+
+ /**
+ * @brief The watchdog is scheduled and a red node in the red-black tree.
+ */
+ WATCHDOG_SCHEDULED_RED,
+
+ /**
+ * @brief The watchdog is inactive.
+ */
+ WATCHDOG_INACTIVE,
+
+ /**
+ * @brief The watchdog is on a chain of pending watchdogs.
+ *
+ * This state is used by the timer server for example.
+ */
+ WATCHDOG_PENDING
+} Watchdog_State;
+
+/**
+ * @brief Watchdog initializer for static initialization.
+ *
+ * The processor of this watchdog is set to processor with index zero.
+ *
+ * @see _Watchdog_Preinitialize().
+ */
+#if defined(RTEMS_SMP)
+ #define WATCHDOG_INITIALIZER( routine ) \
+ { \
+ { { { NULL, NULL, NULL, WATCHDOG_INACTIVE } } }, \
+ &_Per_CPU_Information[ 0 ].per_cpu, \
+ ( routine ), \
+ 0 \
+ }
+#else
+ #define WATCHDOG_INITIALIZER( routine ) \
+ { \
+ { { { NULL, NULL, NULL, WATCHDOG_INACTIVE } } }, \
+ ( routine ), \
+ 0 \
+ }
+#endif
+
+RTEMS_INLINE_ROUTINE void _Watchdog_Header_initialize(
+ Watchdog_Header *header
+)
+{
+ _RBTree_Initialize_empty( &header->Watchdogs );
+ header->first = NULL;
+}
+
+RTEMS_INLINE_ROUTINE void _Watchdog_Header_destroy(
+ Watchdog_Header *header
+)
+{
+ /* Do nothing */
+ (void) header;
+}
+
+/**
+ * @brief Performs a watchdog tick.
+ *
+ * @param cpu The processor for this watchdog tick.
+ */
+void _Watchdog_Tick( struct Per_CPU_Control *cpu );
+
+RTEMS_INLINE_ROUTINE Watchdog_State _Watchdog_Get_state(
+ const Watchdog_Control *the_watchdog
+)
+{
+ return RB_COLOR( &the_watchdog->Node.RBTree, Node );
+}
+
+RTEMS_INLINE_ROUTINE void _Watchdog_Set_state(
+ Watchdog_Control *the_watchdog,
+ Watchdog_State state
+)
+{
+ RB_COLOR( &the_watchdog->Node.RBTree, Node ) = state;
+}
+
+RTEMS_INLINE_ROUTINE Per_CPU_Control *_Watchdog_Get_CPU(
+ const Watchdog_Control *the_watchdog
+)
+{
+#if defined(RTEMS_SMP)
+ return the_watchdog->cpu;
+#else
+ return _Per_CPU_Get_by_index( 0 );
+#endif
+}
+
+RTEMS_INLINE_ROUTINE void _Watchdog_Set_CPU(
+ Watchdog_Control *the_watchdog,
+ Per_CPU_Control *cpu
+)
+{
+#if defined(RTEMS_SMP)
+ the_watchdog->cpu = cpu;
+#else
+ (void) cpu;
+#endif
+}
+
+/**
+ * @brief Pre-initializes a watchdog.
+ *
+ * This routine must be called before a watchdog is used in any way. The
+ * exception are statically initialized watchdogs via WATCHDOG_INITIALIZER().
+ *
+ * @param[in] the_watchdog The uninitialized watchdog.
+ */
+RTEMS_INLINE_ROUTINE void _Watchdog_Preinitialize(
+ Watchdog_Control *the_watchdog,
+ Per_CPU_Control *cpu
+)
+{
+ _Watchdog_Set_CPU( the_watchdog, cpu );
+ _Watchdog_Set_state( the_watchdog, WATCHDOG_INACTIVE );
+
+#if defined(RTEMS_DEBUG)
+ the_watchdog->routine = NULL;
+ the_watchdog->expire = 0;
+#endif
+}
+
+/**
+ * @brief Initializes a watchdog with a new service routine.
+ *
+ * The watchdog must be inactive.
+ */
+RTEMS_INLINE_ROUTINE void _Watchdog_Initialize(
+ Watchdog_Control *the_watchdog,
+ Watchdog_Service_routine_entry routine
+)
+{
+ _Assert( _Watchdog_Get_state( the_watchdog ) == WATCHDOG_INACTIVE );
+ the_watchdog->routine = routine;
+}
+
+void _Watchdog_Do_tickle(
+ Watchdog_Header *header,
+ uint64_t now,
+#if defined(RTEMS_SMP)
+ ISR_lock_Control *lock,
+#endif
+ ISR_lock_Context *lock_context
+);
+
+#if defined(RTEMS_SMP)
+ #define _Watchdog_Tickle( header, now, lock, lock_context ) \
+ _Watchdog_Do_tickle( header, now, lock, lock_context )
+#else
+ #define _Watchdog_Tickle( header, now, lock, lock_context ) \
+ _Watchdog_Do_tickle( header, now, lock_context )
+#endif
+
+/**
+ * @brief Inserts a watchdog into the set of scheduled watchdogs according to
+ * the specified expiration time.
+ *
+ * The watchdog must be inactive.
+ */
+void _Watchdog_Insert(
+ Watchdog_Header *header,
+ Watchdog_Control *the_watchdog,
+ uint64_t expire
+);
+
+/**
+ * @brief In case the watchdog is scheduled, then it is removed from the set of
+ * scheduled watchdogs.
+ *
+ * The watchdog must be initialized before this call.
+ */
+void _Watchdog_Remove(
+ Watchdog_Header *header,
+ Watchdog_Control *the_watchdog
+);
+
+/**
+ * @brief In case the watchdog is scheduled, then it is removed from the set of
+ * scheduled watchdogs.
+ *
+ * The watchdog must be initialized before this call.
+ *
+ * @retval 0 The now time is greater than or equal to the expiration time of
+ * the watchdog.
+ * @retval other The difference of the now and expiration time.
+ */
+RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Cancel(
+ Watchdog_Header *header,
+ Watchdog_Control *the_watchdog,
+ uint64_t now
+)
+{
+ uint64_t expire;
+ uint64_t remaining;
+
+ expire = the_watchdog->expire;
+
+ if ( now < expire ) {
+ remaining = expire - now;
+ } else {
+ remaining = 0;
+ }
+
+ _Watchdog_Remove( header, the_watchdog );
+
+ return remaining;
+}
+
+RTEMS_INLINE_ROUTINE bool _Watchdog_Is_scheduled(
+ const Watchdog_Control *the_watchdog
+)
+{
+ return _Watchdog_Get_state( the_watchdog ) < WATCHDOG_INACTIVE;
+}
+
+RTEMS_INLINE_ROUTINE void _Watchdog_Next_first(
+ Watchdog_Header *header,
+ Watchdog_Control *the_watchdog
+)
+{
+ RBTree_Node *node = _RBTree_Right( &the_watchdog->Node.RBTree );
+
+ if ( node != NULL ) {
+ RBTree_Node *left;
+
+ while ( ( left = _RBTree_Left( node ) ) != NULL ) {
+ node = left;
+ }
+
+ header->first = node;
+ } else {
+ header->first = _RBTree_Parent( &the_watchdog->Node.RBTree );
+ }
+}
+
+/**
+ * @brief The maximum watchdog ticks value for the far future.
+ */
+#define WATCHDOG_MAXIMUM_TICKS UINT64_MAX
+
+#define WATCHDOG_NANOSECONDS_PER_SECOND 1000000000
+
+/**
+ * @brief The bits necessary to store 1000000000
+ * (= WATCHDOG_NANOSECONDS_PER_SECOND) nanoseconds.
+ *
+ * The expiration time is an unsigned 64-bit integer. To store absolute
+ * timeouts we use 30 bits (2**30 == 1073741824) for the nanoseconds and 34
+ * bits for the seconds since UNIX Epoch. This leads to a year 2514 problem.
+ */
+#define WATCHDOG_BITS_FOR_1E9_NANOSECONDS 30
+
+/**
+ * @brief The maximum number of seconds representable in the realtime watchdog
+ * format.
+ *
+ * We have 2**34 bits for the seconds part.
+ */
+#define WATCHDOG_REALTIME_MAX_SECONDS 0x3ffffffff
+
+RTEMS_INLINE_ROUTINE bool _Watchdog_Is_valid_timespec(
+ const struct timespec *ts
+)
+{
+ return ts != NULL
+ && (unsigned long) ts->tv_nsec < WATCHDOG_NANOSECONDS_PER_SECOND;
+}
+
+RTEMS_INLINE_ROUTINE bool _Watchdog_Is_valid_interval_timespec(
+ const struct timespec *ts
+)
+{
+ return _Watchdog_Is_valid_timespec( ts ) && ts->tv_sec >= 0;
+}
+
+RTEMS_INLINE_ROUTINE const struct timespec * _Watchdog_Future_timespec(
+ struct timespec *now,
+ const struct timespec *delta
+)
+{
+ uint64_t sec;
+
+ if ( !_Watchdog_Is_valid_interval_timespec( delta ) ) {
+ return NULL;
+ }
+
+ sec = (uint64_t) now->tv_sec;
+ sec += (uint64_t) delta->tv_sec;
+ now->tv_nsec += delta->tv_nsec;
+
+ /* We have 2 * (2**63 - 1) + 1 == UINT64_MAX */
+ if ( now->tv_nsec >= WATCHDOG_NANOSECONDS_PER_SECOND ) {
+ now->tv_nsec -= WATCHDOG_NANOSECONDS_PER_SECOND;
+ ++sec;
+ }
+
+ if ( sec <= INT64_MAX ) {
+ now->tv_sec = sec;
+ } else {
+ now->tv_sec = INT64_MAX;
+ }
+
+ return now;
+}
+
+RTEMS_INLINE_ROUTINE bool _Watchdog_Is_far_future_monotonic_timespec(
+ const struct timespec *ts
+)
+{
+ return ts->tv_sec >= _Watchdog_Monotonic_max_seconds;
+}
+
+RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Monotonic_from_timespec(
+ const struct timespec *ts
+)
+{
+ uint64_t ticks;
+
+ _Assert( _Watchdog_Is_valid_timespec( ts ) );
+ _Assert( ts->tv_sec >= 0 );
+ _Assert( !_Watchdog_Is_far_future_monotonic_timespec( ts ) );
+
+ ticks = (uint64_t) ts->tv_sec * _Watchdog_Ticks_per_second;
+ ticks += (unsigned long) ts->tv_nsec / _Watchdog_Nanoseconds_per_tick;
+
+ return ticks;
+}
+
+RTEMS_INLINE_ROUTINE bool _Watchdog_Is_far_future_realtime_timespec(
+ const struct timespec *ts
+)
+{
+ return ts->tv_sec > WATCHDOG_REALTIME_MAX_SECONDS;
+}
+
+RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Realtime_from_seconds(
+ uint32_t seconds
+)
+{
+ uint64_t ticks = seconds;
+
+ ticks <<= WATCHDOG_BITS_FOR_1E9_NANOSECONDS;
+
+ return ticks;
+}
+
+RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Realtime_from_timespec(
+ const struct timespec *ts
+)
+{
+ uint64_t ticks;
+
+ _Assert( _Watchdog_Is_valid_timespec( ts ) );
+ _Assert( ts->tv_sec >= 0 );
+ _Assert( !_Watchdog_Is_far_future_realtime_timespec( ts ) );
+
+ ticks = (uint64_t) ts->tv_sec;
+ ticks <<= WATCHDOG_BITS_FOR_1E9_NANOSECONDS;
+ ticks |= (uint32_t) ts->tv_nsec;
+
+ return ticks;
+}
+
+RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Realtime_from_sbintime(
+ sbintime_t sbt
+)
+{
+ uint64_t ticks = ( sbt >> 32 ) << WATCHDOG_BITS_FOR_1E9_NANOSECONDS;
+
+ ticks |= ( (uint64_t) 1000000000 * (uint32_t) sbt ) >> 32;
+
+ return ticks;
+}
+
+RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_acquire_critical(
+ Per_CPU_Control *cpu,
+ ISR_lock_Context *lock_context
+)
+{
+ _ISR_lock_Acquire( &cpu->Watchdog.Lock, lock_context );
+}
+
+RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_release_critical(
+ Per_CPU_Control *cpu,
+ ISR_lock_Context *lock_context
+)
+{
+ _ISR_lock_Release( &cpu->Watchdog.Lock, lock_context );
+}
+
+RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Per_CPU_insert_ticks(
+ Watchdog_Control *the_watchdog,
+ Per_CPU_Control *cpu,
+ Watchdog_Interval ticks
+)
+{
+ ISR_lock_Context lock_context;
+ Watchdog_Header *header;
+ uint64_t expire;
+
+ header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_MONOTONIC ];
+
+ _Watchdog_Set_CPU( the_watchdog, cpu );
+
+ _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context );
+ expire = ticks + cpu->Watchdog.ticks;
+ _Watchdog_Insert(header, the_watchdog, expire);
+ _Watchdog_Per_CPU_release_critical( cpu, &lock_context );
+ return expire;
+}
+
+RTEMS_INLINE_ROUTINE bool _Watchdog_Per_CPU_lazy_insert_monotonic(
+ Watchdog_Control *the_watchdog,
+ Per_CPU_Control *cpu,
+ uint64_t expire
+)
+{
+ ISR_lock_Context lock_context;
+ Watchdog_Header *header;
+ bool insert;
+
+ header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_MONOTONIC ];
+
+ _Watchdog_Set_CPU( the_watchdog, cpu );
+
+ _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context );
+ insert = ( expire > cpu->Watchdog.ticks );
+
+ if ( insert ) {
+ _Watchdog_Insert(header, the_watchdog, expire);
+ }
+
+ _Watchdog_Per_CPU_release_critical( cpu, &lock_context );
+ return insert;
+}
+
+RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Per_CPU_insert_realtime(
+ Watchdog_Control *the_watchdog,
+ Per_CPU_Control *cpu,
+ uint64_t expire
+)
+{
+ ISR_lock_Context lock_context;
+ Watchdog_Header *header;
+
+ header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_REALTIME ];
+
+ _Watchdog_Set_CPU( the_watchdog, cpu );
+
+ _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context );
+ _Watchdog_Insert(header, the_watchdog, expire);
+ _Watchdog_Per_CPU_release_critical( cpu, &lock_context );
+ return expire;
+}
+
+RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove(
+ Watchdog_Control *the_watchdog,
+ Per_CPU_Control *cpu,
+ Watchdog_Header *header
+)
+{
+ ISR_lock_Context lock_context;
+
+ _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context );
+ _Watchdog_Remove(
+ header,
+ the_watchdog
+ );
+ _Watchdog_Per_CPU_release_critical( cpu, &lock_context );
+}
+
+RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove_monotonic(
+ Watchdog_Control *the_watchdog
+)
+{
+ Per_CPU_Control *cpu;
+
+ cpu = _Watchdog_Get_CPU( the_watchdog );
+ _Watchdog_Per_CPU_remove(
+ the_watchdog,
+ cpu,
+ &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_MONOTONIC ]
+ );
+}
+
+RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove_realtime(
+ Watchdog_Control *the_watchdog
+)
+{
+ Per_CPU_Control *cpu;
+
+ cpu = _Watchdog_Get_CPU( the_watchdog );
+ _Watchdog_Per_CPU_remove(
+ the_watchdog,
+ cpu,
+ &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_REALTIME ]
+ );
+}
+
+RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_tickle_realtime(
+ Per_CPU_Control *cpu,
+ uint64_t now
+)
+{
+ ISR_lock_Context lock_context;
+
+ _ISR_lock_ISR_disable_and_acquire( &cpu->Watchdog.Lock, &lock_context );
+ _Watchdog_Tickle(
+ &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_REALTIME ],
+ now,
+ &cpu->Watchdog.Lock,
+ &lock_context
+ );
+}
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* end of include file */