summaryrefslogtreecommitdiffstats
path: root/cpukit/score/include/rtems
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-02-18 08:36:26 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2016-03-04 13:36:10 +0100
commit03b900d3ed120ea919ea3eded7edbece3488cff3 (patch)
tree182781fc14fe15fd67caeb80e46f1c58495839c2 /cpukit/score/include/rtems
parentscore: Distribute clock tick to all online CPUs (diff)
downloadrtems-03b900d3ed120ea919ea3eded7edbece3488cff3.tar.bz2
score: Replace watchdog handler implementation
Use a red-black tree instead of delta chains. Close #2344. Update #2554. Update #2555. Close #2606.
Diffstat (limited to '')
-rw-r--r--cpukit/score/include/rtems/score/mrsp.h7
-rw-r--r--cpukit/score/include/rtems/score/mrspimpl.h32
-rw-r--r--cpukit/score/include/rtems/score/percpu.h53
-rw-r--r--cpukit/score/include/rtems/score/schedulerimpl.h16
-rw-r--r--cpukit/score/include/rtems/score/thread.h13
-rw-r--r--cpukit/score/include/rtems/score/threadimpl.h61
-rw-r--r--cpukit/score/include/rtems/score/todimpl.h17
-rw-r--r--cpukit/score/include/rtems/score/watchdog.h89
-rw-r--r--cpukit/score/include/rtems/score/watchdogimpl.h601
9 files changed, 462 insertions, 427 deletions
diff --git a/cpukit/score/include/rtems/score/mrsp.h b/cpukit/score/include/rtems/score/mrsp.h
index 08f96ac4ac..cb3de67e26 100644
--- a/cpukit/score/include/rtems/score/mrsp.h
+++ b/cpukit/score/include/rtems/score/mrsp.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2014, 2016 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
@@ -128,6 +128,11 @@ typedef struct {
* MRSP_TIMEOUT. State changes are protected by the MrsP control lock.
*/
volatile MRSP_Status status;
+
+ /**
+ * @brief Watchdog for timeouts.
+ */
+ Watchdog_Control Watchdog;
} MRSP_Rival;
/**
diff --git a/cpukit/score/include/rtems/score/mrspimpl.h b/cpukit/score/include/rtems/score/mrspimpl.h
index bc9ed4b511..7638fb5975 100644
--- a/cpukit/score/include/rtems/score/mrspimpl.h
+++ b/cpukit/score/include/rtems/score/mrspimpl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2014, 2016 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
@@ -159,18 +159,13 @@ RTEMS_INLINE_ROUTINE void _MRSP_Set_ceiling_priority(
mrsp->ceiling_priorities[ scheduler_index ] = ceiling_priority;
}
-RTEMS_INLINE_ROUTINE void _MRSP_Timeout(
- Objects_Id id,
- void *arg
-)
+RTEMS_INLINE_ROUTINE void _MRSP_Timeout( Watchdog_Control *watchdog )
{
- MRSP_Rival *rival = arg;
+ MRSP_Rival *rival = RTEMS_CONTAINER_OF( watchdog, MRSP_Rival, Watchdog );
MRSP_Control *mrsp = rival->resource;
Thread_Control *thread = rival->thread;
ISR_lock_Context lock_context;
- (void) id;
-
_ISR_lock_ISR_disable_and_acquire( &mrsp->Lock, &lock_context );
if ( rival->status == MRSP_WAIT_FOR_OWNERSHIP ) {
@@ -209,6 +204,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
bool initial_life_protection;
Per_CPU_Control *cpu_self;
ISR_lock_Context giant_lock_context;
+ ISR_Level level;
rival.thread = executing;
rival.resource = mrsp;
@@ -236,13 +232,11 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
_Thread_Raise_priority( executing, ceiling_priority );
if ( timeout > 0 ) {
- _Watchdog_Initialize(
- &executing->Timer,
- _MRSP_Timeout,
- 0,
- &rival
- );
- _Watchdog_Insert_ticks( &executing->Timer, timeout );
+ _Watchdog_Preinitialize( &rival.Watchdog, cpu_self );
+ _Watchdog_Initialize( &rival.Watchdog, _MRSP_Timeout );
+ _ISR_Disable_without_giant( level );
+ _Watchdog_Per_CPU_insert_relative( &rival.Watchdog, cpu_self, timeout );
+ _ISR_Enable_without_giant( level );
}
initial_life_protection = _Thread_Set_life_protection( true );
@@ -258,7 +252,13 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
_Thread_Set_life_protection( initial_life_protection );
if ( timeout > 0 ) {
- _Watchdog_Remove_ticks( &executing->Timer );
+ _ISR_Disable_without_giant( level );
+ _Watchdog_Per_CPU_remove(
+ &rival.Watchdog,
+ cpu_self,
+ &cpu_self->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ]
+ );
+ _ISR_Enable_without_giant( level );
if ( status == MRSP_TIMEOUT ) {
_MRSP_Restore_priority( executing, initial_priority );
diff --git a/cpukit/score/include/rtems/score/percpu.h b/cpukit/score/include/rtems/score/percpu.h
index 39be1e3367..22017889b3 100644
--- a/cpukit/score/include/rtems/score/percpu.h
+++ b/cpukit/score/include/rtems/score/percpu.h
@@ -23,10 +23,11 @@
#include <rtems/asm.h>
#else
#include <rtems/score/assert.h>
- #include <rtems/score/isrlevel.h>
+ #include <rtems/score/isrlock.h>
#include <rtems/score/smp.h>
#include <rtems/score/smplock.h>
#include <rtems/score/timestamp.h>
+ #include <rtems/score/watchdog.h>
#endif
#ifdef __cplusplus
@@ -41,7 +42,7 @@ extern "C" {
* processor.
*/
#if defined( RTEMS_PROFILING )
- #define PER_CPU_CONTROL_SIZE_LOG2 8
+ #define PER_CPU_CONTROL_SIZE_LOG2 9
#else
#define PER_CPU_CONTROL_SIZE_LOG2 7
#endif
@@ -226,6 +227,32 @@ typedef struct {
} Per_CPU_Stats;
/**
+ * @brief Per-CPU watchdog header index.
+ */
+typedef enum {
+ /**
+ * @brief Index for relative per-CPU watchdog header.
+ *
+ * The reference time point for this header is current ticks value
+ * during insert. Time is measured in clock ticks.
+ */
+ PER_CPU_WATCHDOG_RELATIVE,
+
+ /**
+ * @brief Index for absolute per-CPU watchdog header.
+ *
+ * The reference time point for this header is the POSIX Epoch. Time is
+ * measured in nanoseconds since POSIX Epoch.
+ */
+ PER_CPU_WATCHDOG_ABSOLUTE,
+
+ /**
+ * @brief Count of per-CPU watchdog headers.
+ */
+ PER_CPU_WATCHDOG_COUNT
+} Per_CPU_Watchdog_index;
+
+/**
* @brief Per CPU Core Structure
*
* This structure is used to hold per core state information.
@@ -309,6 +336,28 @@ typedef struct Per_CPU_Control {
/** This is the time of the last context switch on this CPU. */
Timestamp_Control time_of_last_context_switch;
+ /**
+ * @brief Watchdog state for this processor.
+ */
+ struct {
+ /**
+ * @brief Protects all watchdog operations on this processor.
+ */
+ ISR_LOCK_MEMBER( Lock )
+
+ /**
+ * @brief Watchdog ticks on this processor used for relative watchdogs.
+ */
+ uint64_t ticks;
+
+ /**
+ * @brief Header for watchdogs.
+ *
+ * @see Per_CPU_Watchdog_index.
+ */
+ Watchdog_Header Header[ PER_CPU_WATCHDOG_COUNT ];
+ } Watchdog;
+
#if defined( RTEMS_SMP )
/**
* @brief This lock protects some parts of the low-level thread dispatching.
diff --git a/cpukit/score/include/rtems/score/schedulerimpl.h b/cpukit/score/include/rtems/score/schedulerimpl.h
index cadebfd02f..d50c36a7b9 100644
--- a/cpukit/score/include/rtems/score/schedulerimpl.h
+++ b/cpukit/score/include/rtems/score/schedulerimpl.h
@@ -452,19 +452,13 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Release_job(
* scheduler which support standard RTEMS features, this includes
* time-slicing management.
*/
-RTEMS_INLINE_ROUTINE void _Scheduler_Tick( void )
+RTEMS_INLINE_ROUTINE void _Scheduler_Tick( const Per_CPU_Control *cpu )
{
- uint32_t cpu_count = _SMP_Get_processor_count();
- uint32_t cpu_index;
+ const Scheduler_Control *scheduler = _Scheduler_Get_by_CPU( cpu );
+ Thread_Control *executing = cpu->executing;
- for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
- const Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );
- const Scheduler_Control *scheduler = _Scheduler_Get_by_CPU( cpu );
- Thread_Control *executing = cpu->executing;
-
- if ( scheduler != NULL && executing != NULL ) {
- ( *scheduler->Operations.tick )( scheduler, executing );
- }
+ if ( scheduler != NULL && executing != NULL ) {
+ ( *scheduler->Operations.tick )( scheduler, executing );
}
}
diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h
index 73776b3ec1..44b706d7ff 100644
--- a/cpukit/score/include/rtems/score/thread.h
+++ b/cpukit/score/include/rtems/score/thread.h
@@ -347,6 +347,15 @@ typedef struct {
} Thread_Wait_information;
/**
+ * @brief Information required to manage a thread timer.
+ */
+typedef struct {
+ ISR_LOCK_MEMBER( Lock )
+ Watchdog_Header *header;
+ Watchdog_Control Watchdog;
+} Thread_Timer_information;
+
+/**
* The following defines the control block used to manage
* each thread proxy.
*
@@ -400,7 +409,7 @@ typedef struct {
/** This field is the blocking information for this proxy. */
Thread_Wait_information Wait;
/** This field is the Watchdog used to manage proxy delays and timeouts. */
- Watchdog_Control Timer;
+ Thread_Timer_information Timer;
#if defined(RTEMS_MULTIPROCESSING)
/** This field is the received response packet in an MP system. */
MP_packet_Prefix *receive_packet;
@@ -728,7 +737,7 @@ struct _Thread_Control {
/** This field is the blocking information for this thread. */
Thread_Wait_information Wait;
/** This field is the Watchdog used to manage thread delays and timeouts. */
- Watchdog_Control Timer;
+ Thread_Timer_information Timer;
#if defined(RTEMS_MULTIPROCESSING)
/** This field is the received response packet in an MP system. */
MP_packet_Prefix *receive_packet;
diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h
index 1377543118..ec9851dba0 100644
--- a/cpukit/score/include/rtems/score/threadimpl.h
+++ b/cpukit/score/include/rtems/score/threadimpl.h
@@ -33,6 +33,7 @@
#include <rtems/score/threadqimpl.h>
#include <rtems/score/todimpl.h>
#include <rtems/score/freechain.h>
+#include <rtems/score/watchdogimpl.h>
#include <rtems/config.h>
#ifdef __cplusplus
@@ -1472,10 +1473,64 @@ RTEMS_INLINE_ROUTINE void _Thread_Wait_set_timeout_code(
/**
* @brief General purpose thread wait timeout.
*
- * @param[in] id Unused.
- * @param[in] arg The thread.
+ * @param[in] watchdog The thread timer watchdog.
*/
-void _Thread_Timeout( Objects_Id id, void *arg );
+void _Thread_Timeout( Watchdog_Control *watchdog );
+
+RTEMS_INLINE_ROUTINE void _Thread_Timer_insert_relative(
+ Thread_Control *the_thread,
+ Per_CPU_Control *cpu,
+ Watchdog_Service_routine_entry routine,
+ Watchdog_Interval ticks
+)
+{
+ ISR_lock_Context lock_context;
+
+ _ISR_lock_ISR_disable_and_acquire( &the_thread->Timer.Lock, &lock_context );
+
+ the_thread->Timer.header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ];
+ the_thread->Timer.Watchdog.routine = routine;
+ _Watchdog_Per_CPU_insert_relative( &the_thread->Timer.Watchdog, cpu, ticks );
+
+ _ISR_lock_Release_and_ISR_enable( &the_thread->Timer.Lock, &lock_context );
+}
+
+RTEMS_INLINE_ROUTINE void _Thread_Timer_insert_absolute(
+ Thread_Control *the_thread,
+ Per_CPU_Control *cpu,
+ Watchdog_Service_routine_entry routine,
+ uint64_t expire
+)
+{
+ ISR_lock_Context lock_context;
+
+ _ISR_lock_ISR_disable_and_acquire( &the_thread->Timer.Lock, &lock_context );
+
+ the_thread->Timer.header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_ABSOLUTE ];
+ the_thread->Timer.Watchdog.routine = routine;
+ _Watchdog_Per_CPU_insert_absolute( &the_thread->Timer.Watchdog, cpu, expire );
+
+ _ISR_lock_Release_and_ISR_enable( &the_thread->Timer.Lock, &lock_context );
+}
+
+RTEMS_INLINE_ROUTINE void _Thread_Timer_remove( Thread_Control *the_thread )
+{
+ ISR_lock_Context lock_context;
+
+ _ISR_lock_ISR_disable_and_acquire( &the_thread->Timer.Lock, &lock_context );
+
+ _Watchdog_Per_CPU_remove(
+ &the_thread->Timer.Watchdog,
+#if defined(RTEMS_SMP)
+ the_thread->Timer.Watchdog.cpu,
+#else
+ _Per_CPU_Get(),
+#endif
+ the_thread->Timer.header
+ );
+
+ _ISR_lock_Release_and_ISR_enable( &the_thread->Timer.Lock, &lock_context );
+}
RTEMS_INLINE_ROUTINE void _Thread_Debug_set_real_processor(
Thread_Control *the_thread,
diff --git a/cpukit/score/include/rtems/score/todimpl.h b/cpukit/score/include/rtems/score/todimpl.h
index b61651cdba..b1f8a6d6b6 100644
--- a/cpukit/score/include/rtems/score/todimpl.h
+++ b/cpukit/score/include/rtems/score/todimpl.h
@@ -132,15 +132,6 @@ extern "C" {
*/
typedef struct {
/**
- * @brief Time of day seconds trigger.
- *
- * This value specifies the nanoseconds since the last time of day second.
- * It is updated and evaluated in _TOD_Tickle_ticks(). It is set in
- * _TOD_Set_with_timestamp().
- */
- uint32_t seconds_trigger;
-
- /**
* @brief Indicates if the time of day is set.
*
* This is true if the application has set the current
@@ -273,14 +264,6 @@ static inline uint32_t _TOD_Seconds_since_epoch( void )
}
/**
- * @brief Increments time of day at each clock tick.
- *
- * This routine increments the ticks field of the current time of
- * day at each clock tick.
- */
-void _TOD_Tickle_ticks( void );
-
-/**
* @brief Gets number of ticks in a second.
*
* This method returns the number of ticks in a second.
diff --git a/cpukit/score/include/rtems/score/watchdog.h b/cpukit/score/include/rtems/score/watchdog.h
index bad7269051..c582dbd1ae 100644
--- a/cpukit/score/include/rtems/score/watchdog.h
+++ b/cpukit/score/include/rtems/score/watchdog.h
@@ -20,7 +20,11 @@
#ifndef _RTEMS_SCORE_WATCHDOG_H
#define _RTEMS_SCORE_WATCHDOG_H
-#include <rtems/score/object.h>
+#include <rtems/score/basedefs.h>
+#include <rtems/score/chain.h>
+#include <rtems/score/rbtree.h>
+
+struct Per_CPU_Control;
#ifdef __cplusplus
extern "C" {
@@ -39,6 +43,8 @@ extern "C" {
*/
/**@{*/
+typedef struct Watchdog_Control Watchdog_Control;
+
/**
* @brief Type is used to specify the length of intervals.
*
@@ -58,10 +64,8 @@ typedef void Watchdog_Service_routine;
*
* This type define a pointer to a watchdog service routine.
*/
-typedef Watchdog_Service_routine ( *Watchdog_Service_routine_entry )(
- Objects_Id,
- void *
- );
+typedef Watchdog_Service_routine
+ ( *Watchdog_Service_routine_entry )( Watchdog_Control * );
/**
* @brief The constant for indefinite wait.
@@ -72,22 +76,20 @@ typedef Watchdog_Service_routine ( *Watchdog_Service_routine_entry )(
#define WATCHDOG_NO_TIMEOUT 0
/**
- * @brief Set of the states which a watchdog timer may be at any given time.
- *
- * This enumerated type is the set of the states in which a
- * watchdog timer may be at any given time.
+ * @brief The watchdog header to manage scheduled watchdogs.
*/
+typedef struct {
+ /**
+ * @brief Red-black tree of scheduled watchdogs sorted by expiration time.
+ */
+ RBTree_Control Watchdogs;
-typedef enum {
- /** This is the state when the watchdog is off all chains */
- WATCHDOG_INACTIVE,
- /** This is the state when the watchdog is off all chains, but we are
- * currently searching for the insertion point.
+ /**
+ * @brief The scheduled watchdog with the earliest expiration time or NULL in
+ * case no watchdog is scheduled.
*/
- WATCHDOG_BEING_INSERTED,
- /** This is the state when the watchdog is on a chain, and allowed to fire. */
- WATCHDOG_ACTIVE
-} Watchdog_States;
+ RBTree_Node *first;
+} Watchdog_Header;
/**
* @brief The control block used to manage each watchdog timer.
@@ -95,30 +97,35 @@ typedef enum {
* The following record defines the control block used
* to manage each watchdog timer.
*/
-typedef struct {
- /** This field is a Chain Node structure and allows this to be placed on
- * chains for set management.
- */
- Chain_Node Node;
- /** This field is the state of the watchdog. */
- Watchdog_States state;
- /** This field is the initially requested interval. */
- Watchdog_Interval initial;
- /** This field is the remaining portion of the interval. */
- Watchdog_Interval delta_interval;
- /** This field is the number of system clock ticks when this was scheduled. */
- Watchdog_Interval start_time;
- /** This field is the number of system clock ticks when this was suspended. */
- Watchdog_Interval stop_time;
- /** This field is the function to invoke. */
- Watchdog_Service_routine_entry routine;
- /** This field is the Id to pass as an argument to the routine. */
- Objects_Id id;
- /** This field is an untyped pointer to user data that is passed to the
- * watchdog handler routine.
+struct Watchdog_Control {
+ /**
+ * @brief Nodes for the watchdog.
*/
- void *user_data;
-} Watchdog_Control;
+ union {
+ /**
+ * @brief this field is a red-black tree node structure and allows this to
+ * be placed on a red-black tree used to manage the scheduled watchdogs.
+ */
+ RBTree_Node RBTree;
+
+ /**
+ * @brief this field is a chain node structure and allows this to be placed
+ * on a chain used to manage pending watchdogs by the timer server.
+ */
+ Chain_Node Chain;
+ } Node;
+
+#if defined(RTEMS_SMP)
+ /** @brief This field references the processor of this watchdog control. */
+ struct Per_CPU_Control *cpu;
+#endif
+
+ /** @brief This field is the function to invoke. */
+ Watchdog_Service_routine_entry routine;
+
+ /** @brief This field is the expiration time point. */
+ uint64_t expire;
+};
/**
* @brief The watchdog ticks counter.
diff --git a/cpukit/score/include/rtems/score/watchdogimpl.h b/cpukit/score/include/rtems/score/watchdogimpl.h
index 49ac2a12b1..2b24cc68e5 100644
--- a/cpukit/score/include/rtems/score/watchdogimpl.h
+++ b/cpukit/score/include/rtems/score/watchdogimpl.h
@@ -21,9 +21,11 @@
#include <rtems/score/watchdog.h>
#include <rtems/score/assert.h>
-#include <rtems/score/chainimpl.h>
#include <rtems/score/isrlock.h>
#include <rtems/score/percpu.h>
+#include <rtems/score/rbtreeimpl.h>
+
+#include <sys/timespec.h>
#ifdef __cplusplus
extern "C" {
@@ -35,241 +37,116 @@ extern "C" {
*/
/**
- * @brief Watchdog initializer for static initialization.
- *
- * @see _Watchdog_Initialize().
- */
-#define WATCHDOG_INITIALIZER( routine, id, user_data ) \
- { \
- { NULL, NULL }, \
- WATCHDOG_INACTIVE, \
- 0, 0, 0, 0, \
- ( routine ), ( id ), ( user_data ) \
- }
-
-/**
- * @brief Iterator item to synchronize concurrent insert, remove and tickle
- * operations.
+ * @brief Watchdog states.
*/
-typedef struct {
+typedef enum {
/**
- * @brief A node for a Watchdog_Header::Iterators chain.
+ * @brief The watchdog is scheduled and a black node in the red-black tree.
*/
- Chain_Node Node;
+ WATCHDOG_SCHEDULED_BLACK,
/**
- * @brief The current delta interval of the new watchdog to insert.
+ * @brief The watchdog is scheduled and a red node in the red-black tree.
*/
- Watchdog_Interval delta_interval;
+ WATCHDOG_SCHEDULED_RED,
/**
- * @brief The current watchdog of the chain on the way to insert the new
- * watchdog.
+ * @brief The watchdog is inactive.
*/
- Chain_Node *current;
-} Watchdog_Iterator;
-
-/**
- * @brief Watchdog header.
- */
-typedef struct {
- /**
- * @brief ISR lock to protect this watchdog chain.
- */
- ISR_LOCK_MEMBER( Lock )
+ WATCHDOG_INACTIVE,
/**
- * @brief The chain of active or transient watchdogs.
- */
- Chain_Control Watchdogs;
-
- /**
- * @brief Currently active iterators.
+ * @brief The watchdog is on a chain of pending watchdogs.
*
- * The iterators are registered in _Watchdog_Insert() and updated in case the
- * watchdog chain changes.
+ * This state is used by the timer server for example.
*/
- Chain_Control Iterators;
-} Watchdog_Header;
+ WATCHDOG_PENDING
+} Watchdog_State;
/**
- * @brief Watchdog chain which is managed at ticks.
+ * @brief Watchdog initializer for static initialization.
*
- * This is the watchdog chain which is managed at ticks.
- */
-extern Watchdog_Header _Watchdog_Ticks_header;
-
-/**
- * @brief Watchdog chain which is managed at second boundaries.
+ * The processor of this watchdog is set to processor with index zero.
*
- * This is the watchdog chain which is managed at second boundaries.
+ * @see _Watchdog_Preinitialize().
*/
-extern Watchdog_Header _Watchdog_Seconds_header;
-
-RTEMS_INLINE_ROUTINE void _Watchdog_Acquire(
- Watchdog_Header *header,
- ISR_lock_Context *lock_context
-)
-{
- _ISR_lock_ISR_disable_and_acquire( &header->Lock, lock_context );
-}
+#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_Release(
- Watchdog_Header *header,
- ISR_lock_Context *lock_context
+RTEMS_INLINE_ROUTINE void _Watchdog_Header_initialize(
+ Watchdog_Header *header
)
{
- _ISR_lock_Release_and_ISR_enable( &header->Lock, lock_context );
+ _RBTree_Initialize_empty( &header->Watchdogs );
+ header->first = NULL;
}
-RTEMS_INLINE_ROUTINE void _Watchdog_Flash(
- Watchdog_Header *header,
- ISR_lock_Context *lock_context
+RTEMS_INLINE_ROUTINE void _Watchdog_Header_destroy(
+ Watchdog_Header *header
)
{
- _ISR_lock_Flash( &header->Lock, lock_context );
+ /* Do nothing */
+ (void) header;
}
/**
- * @brief Initialize the watchdog handler.
- *
- * This routine initializes the watchdog handler. The watchdog
- * synchronization flag is initialized and the watchdog chains are
- * initialized and emptied.
- */
-void _Watchdog_Handler_initialization( void );
-
-/**
* @brief Performs a watchdog tick.
*
* @param cpu The processor for this watchdog tick.
*/
-void _Watchdog_Tick( Per_CPU_Control *cpu );
-
-/**
- * @brief Removes @a the_watchdog from the watchdog chain.
- *
- * This routine removes @a the_watchdog from the watchdog chain on which
- * it resides and returns the state @a the_watchdog timer was in.
- *
- * @param[in] header The watchdog chain.
- * @param[in] the_watchdog will be removed
- * @retval the state in which @a the_watchdog was in when removed
- */
-Watchdog_States _Watchdog_Remove (
- Watchdog_Header *header,
- Watchdog_Control *the_watchdog
-);
-
-/**
- * @brief Adjusts the header watchdog chain in the backward direction for
- * units ticks.
- *
- * @param[in] header The watchdog chain.
- * @param[in] units The units of ticks to adjust.
- */
-void _Watchdog_Adjust_backward(
- Watchdog_Header *header,
- Watchdog_Interval units
-);
-
-/**
- * @brief Adjusts the watchdogs in backward direction in a locked context.
- *
- * The caller must be the owner of the watchdog lock and will be the owner
- * after the call.
- *
- * @param[in] header The watchdog header.
- * @param[in] units The units of ticks to adjust.
- *
- * @see _Watchdog_Adjust_forward().
- */
-void _Watchdog_Adjust_backward_locked(
- Watchdog_Header *header,
- Watchdog_Interval units
-);
+void _Watchdog_Tick( struct Per_CPU_Control *cpu );
-/**
- * @brief Adjusts the header watchdog chain in the forward direction for units
- * ticks.
- *
- * This may lead to several _Watchdog_Tickle() invocations.
- *
- * @param[in] header The watchdog chain.
- * @param[in] units The units of ticks to adjust.
- */
-void _Watchdog_Adjust_forward(
- Watchdog_Header *header,
- Watchdog_Interval units
-);
+RTEMS_INLINE_ROUTINE Watchdog_State _Watchdog_Get_state(
+ const Watchdog_Control *the_watchdog
+)
+{
+ return RB_COLOR( &the_watchdog->Node.RBTree, Node );
+}
-/**
- * @brief Adjusts the watchdogs in forward direction in a locked context.
- *
- * The caller must be the owner of the watchdog lock and will be the owner
- * after the call. This function may release and acquire the watchdog lock
- * internally.
- *
- * @param[in] header The watchdog header.
- * @param[in] units The units of ticks to adjust.
- * @param[in] lock_context The lock context.
- *
- * @see _Watchdog_Adjust_forward().
- */
-void _Watchdog_Adjust_forward_locked(
- Watchdog_Header *header,
- Watchdog_Interval units,
- ISR_lock_Context *lock_context
-);
+RTEMS_INLINE_ROUTINE void _Watchdog_Set_state(
+ Watchdog_Control *the_watchdog,
+ Watchdog_State state
+)
+{
+ RB_COLOR( &the_watchdog->Node.RBTree, Node ) = state;
+}
-/**
- * @brief Inserts @a the_watchdog into the @a header watchdog chain
- * for a time of @a units.
- *
- * This routine inserts @a the_watchdog into the @a header watchdog chain
- * for a time of @a units.
- * Update the delta interval counters.
- *
- * @param[in] header is @a the_watchdog list to insert @a the_watchdog on
- * @param[in] the_watchdog is the watchdog to insert
- */
-void _Watchdog_Insert (
- Watchdog_Header *header,
- Watchdog_Control *the_watchdog
-);
+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
+}
-/**
- * @brief Inserts the watchdog in a locked context.
- *
- * The caller must be the owner of the watchdog lock and will be the owner
- * after the call. This function may release and acquire the watchdog lock
- * internally.
- *
- * @param[in] header The watchdog header.
- * @param[in] the_watchdog The watchdog.
- * @param[in] lock_context The lock context.
- *
- * @see _Watchdog_Insert().
- */
-void _Watchdog_Insert_locked(
- Watchdog_Header *header,
+RTEMS_INLINE_ROUTINE void _Watchdog_Set_CPU(
Watchdog_Control *the_watchdog,
- ISR_lock_Context *lock_context
-);
-
-/**
- * @brief This routine is invoked at appropriate intervals to update
- * the @a header watchdog chain.
- *
- * This routine is invoked at appropriate intervals to update
- * the @a header watchdog chain.
- * This routine decrements the delta counter in response to a tick.
- *
- * @param[in] header is the watchdog chain to tickle
- */
-void _Watchdog_Tickle (
- Watchdog_Header *header
-);
+ Per_CPU_Control *cpu
+)
+{
+#if defined(RTEMS_SMP)
+ the_watchdog->cpu = cpu;
+#else
+ (void) cpu;
+#endif
+}
/**
* @brief Pre-initializes a watchdog.
@@ -280,228 +157,284 @@ void _Watchdog_Tickle (
* @param[in] the_watchdog The uninitialized watchdog.
*/
RTEMS_INLINE_ROUTINE void _Watchdog_Preinitialize(
- Watchdog_Control *the_watchdog
+ Watchdog_Control *the_watchdog,
+ Per_CPU_Control *cpu
)
{
- the_watchdog->state = WATCHDOG_INACTIVE;
+ _Watchdog_Set_CPU( the_watchdog, cpu );
+ _Watchdog_Set_state( the_watchdog, WATCHDOG_INACTIVE );
+
#if defined(RTEMS_DEBUG)
the_watchdog->routine = NULL;
- the_watchdog->id = 0;
- the_watchdog->user_data = NULL;
+ the_watchdog->expire = 0;
#endif
}
/**
- * This routine initializes the specified watchdog. The watchdog is
- * made inactive, the watchdog id and handler routine are set to the
- * specified values.
+ * @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,
- Objects_Id id,
- void *user_data
+ Watchdog_Service_routine_entry routine
)
{
- _Assert( the_watchdog->state == WATCHDOG_INACTIVE );
- the_watchdog->routine = routine;
- the_watchdog->id = id;
- the_watchdog->user_data = user_data;
+ _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
+
/**
- * This routine returns true if the watchdog timer is in the ACTIVE
- * state, and false otherwise.
+ * @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
+);
-RTEMS_INLINE_ROUTINE bool _Watchdog_Is_active(
+/**
+ * @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
-)
-{
-
- return ( the_watchdog->state == WATCHDOG_ACTIVE );
-
-}
+);
/**
- * This routine activates THE_WATCHDOG timer which is already
- * on a watchdog chain.
+ * @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 void _Watchdog_Activate(
- Watchdog_Control *the_watchdog
+RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Cancel(
+ Watchdog_Header *header,
+ Watchdog_Control *the_watchdog,
+ uint64_t now
)
{
+ uint64_t expire;
+ uint64_t remaining;
- the_watchdog->state = WATCHDOG_ACTIVE;
+ expire = the_watchdog->expire;
-}
-
-/**
- * This routine is invoked at each clock tick to update the ticks
- * watchdog chain.
- */
-
-RTEMS_INLINE_ROUTINE void _Watchdog_Tickle_ticks( void )
-{
+ if ( now < expire ) {
+ remaining = expire - now;
+ } else {
+ remaining = 0;
+ }
- _Watchdog_Tickle( &_Watchdog_Ticks_header );
+ _Watchdog_Remove( header, the_watchdog );
+ return remaining;
}
-/**
- * This routine is invoked at each clock tick to update the seconds
- * watchdog chain.
- */
-
-RTEMS_INLINE_ROUTINE void _Watchdog_Tickle_seconds( void )
+RTEMS_INLINE_ROUTINE bool _Watchdog_Is_scheduled(
+ const Watchdog_Control *the_watchdog
+)
{
-
- _Watchdog_Tickle( &_Watchdog_Seconds_header );
-
+ return _Watchdog_Get_state( the_watchdog ) < WATCHDOG_INACTIVE;
}
-/**
- * This routine inserts THE_WATCHDOG into the ticks watchdog chain
- * for a time of UNITS ticks. The INSERT_MODE indicates whether
- * THE_WATCHDOG is to be activated automatically or later, explicitly
- * by the caller.
- */
-
-RTEMS_INLINE_ROUTINE void _Watchdog_Insert_ticks(
- Watchdog_Control *the_watchdog,
- Watchdog_Interval units
+RTEMS_INLINE_ROUTINE void _Watchdog_Next_first(
+ Watchdog_Header *header,
+ Watchdog_Control *the_watchdog
)
{
+ RBTree_Node *node = _RBTree_Right( &the_watchdog->Node.RBTree );
- the_watchdog->initial = units;
+ if ( node != NULL ) {
+ RBTree_Node *left;
- _Watchdog_Insert( &_Watchdog_Ticks_header, the_watchdog );
+ while ( ( left = _RBTree_Left( node ) ) != NULL ) {
+ node = left;
+ }
+ header->first = node;
+ } else {
+ header->first = _RBTree_Parent( &the_watchdog->Node.RBTree );
+ }
}
/**
- * This routine inserts THE_WATCHDOG into the seconds watchdog chain
- * for a time of UNITS seconds. The INSERT_MODE indicates whether
- * THE_WATCHDOG is to be activated automatically or later, explicitly
- * by the caller.
+ * @brief The bits necessary to store 1000000000 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
-RTEMS_INLINE_ROUTINE void _Watchdog_Insert_seconds(
- Watchdog_Control *the_watchdog,
- Watchdog_Interval units
+RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Ticks_from_seconds(
+ uint32_t seconds
)
{
+ uint64_t ticks = seconds;
- the_watchdog->initial = units;
-
- _Watchdog_Insert( &_Watchdog_Seconds_header, the_watchdog );
+ ticks <<= WATCHDOG_BITS_FOR_1E9_NANOSECONDS;
+ return ticks;
}
-RTEMS_INLINE_ROUTINE Watchdog_States _Watchdog_Remove_ticks(
- Watchdog_Control *the_watchdog
+RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Ticks_from_timespec(
+ const struct timespec *ts
)
{
- return _Watchdog_Remove( &_Watchdog_Ticks_header, the_watchdog );
+ /*
+ * The seconds are in time_t which is a signed integer. Thus this cast is
+ * subject to the year 2038 problem in case time_t is a 32-bit integer.
+ */
+ uint64_t ticks = (uint64_t) ts->tv_sec;
+
+ _Assert( ticks < 0x400000000 );
+ _Assert( ts->tv_nsec >= 0 );
+ _Assert( ts->tv_nsec < 1000000000 );
+
+ ticks <<= WATCHDOG_BITS_FOR_1E9_NANOSECONDS;
+ ticks |= ts->tv_nsec;
+
+ return ticks;
}
-RTEMS_INLINE_ROUTINE Watchdog_States _Watchdog_Remove_seconds(
- Watchdog_Control *the_watchdog
+RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_acquire_critical(
+ Per_CPU_Control *cpu,
+ ISR_lock_Context *lock_context
)
{
- return _Watchdog_Remove( &_Watchdog_Seconds_header, the_watchdog );
+ _ISR_lock_Acquire( &cpu->Watchdog.Lock, lock_context );
}
-/**
- * This routine resets THE_WATCHDOG timer to its state at INSERT
- * time. This routine is valid only on interval watchdog timers
- * and is used to make an interval watchdog timer fire "every" so
- * many ticks.
- */
-
-RTEMS_INLINE_ROUTINE void _Watchdog_Reset_ticks(
- Watchdog_Control *the_watchdog
+RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_release_critical(
+ Per_CPU_Control *cpu,
+ ISR_lock_Context *lock_context
)
{
-
- _Watchdog_Remove_ticks( the_watchdog );
-
- _Watchdog_Insert( &_Watchdog_Ticks_header, the_watchdog );
-
+ _ISR_lock_Release( &cpu->Watchdog.Lock, lock_context );
}
-/**
- * This routine returns a pointer to the watchdog timer following
- * THE_WATCHDOG on the watchdog chain.
- */
-
-RTEMS_INLINE_ROUTINE Watchdog_Control *_Watchdog_Next(
- Watchdog_Control *the_watchdog
+RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_insert_relative(
+ Watchdog_Control *the_watchdog,
+ Per_CPU_Control *cpu,
+ uint32_t ticks
)
{
+ ISR_lock_Context lock_context;
- return ( (Watchdog_Control *) the_watchdog->Node.next );
+ _Watchdog_Set_CPU( the_watchdog, cpu );
+ _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context );
+ _Watchdog_Insert(
+ &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ],
+ the_watchdog,
+ cpu->Watchdog.ticks + ticks
+ );
+ _Watchdog_Per_CPU_release_critical( cpu, &lock_context );
}
-/**
- * This routine returns a pointer to the watchdog timer preceding
- * THE_WATCHDOG on the watchdog chain.
- */
-
-RTEMS_INLINE_ROUTINE Watchdog_Control *_Watchdog_Previous(
- Watchdog_Control *the_watchdog
+RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_insert_absolute(
+ Watchdog_Control *the_watchdog,
+ Per_CPU_Control *cpu,
+ uint64_t expire
)
{
+ ISR_lock_Context lock_context;
- return ( (Watchdog_Control *) the_watchdog->Node.previous );
+ _Watchdog_Set_CPU( the_watchdog, cpu );
+ _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context );
+ _Watchdog_Insert(
+ &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_ABSOLUTE ],
+ the_watchdog,
+ expire
+ );
+ _Watchdog_Per_CPU_release_critical( cpu, &lock_context );
}
-/**
- * This routine returns a pointer to the first watchdog timer
- * on the watchdog chain HEADER.
- */
-
-RTEMS_INLINE_ROUTINE Watchdog_Control *_Watchdog_First(
- Watchdog_Header *header
+RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove(
+ Watchdog_Control *the_watchdog,
+ Per_CPU_Control *cpu,
+ Watchdog_Header *header
)
{
-
- return ( (Watchdog_Control *) _Chain_First( &header->Watchdogs ) );
-
+ 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 );
}
-/**
- * This routine returns a pointer to the last watchdog timer
- * on the watchdog chain HEADER.
- */
-
-RTEMS_INLINE_ROUTINE Watchdog_Control *_Watchdog_Last(
- Watchdog_Header *header
+RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove_relative(
+ Watchdog_Control *the_watchdog
)
{
-
- return ( (Watchdog_Control *) _Chain_Last( &header->Watchdogs ) );
-
+ Per_CPU_Control *cpu;
+
+ cpu = _Watchdog_Get_CPU( the_watchdog );
+ _Watchdog_Per_CPU_remove(
+ the_watchdog,
+ cpu,
+ &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ]
+ );
}
-RTEMS_INLINE_ROUTINE bool _Watchdog_Is_empty(
- const Watchdog_Header *header
+RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove_absolute(
+ Watchdog_Control *the_watchdog
)
{
- return _Chain_Is_empty( &header->Watchdogs );
+ Per_CPU_Control *cpu;
+
+ cpu = _Watchdog_Get_CPU( the_watchdog );
+ _Watchdog_Per_CPU_remove(
+ the_watchdog,
+ cpu,
+ &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_ABSOLUTE ]
+ );
}
-RTEMS_INLINE_ROUTINE void _Watchdog_Header_initialize(
- Watchdog_Header *header
+RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_tickle_absolute(
+ Per_CPU_Control *cpu,
+ uint64_t now
)
{
- _ISR_lock_Initialize( &header->Lock, "Watchdog" );
- _Chain_Initialize_empty( &header->Watchdogs );
- _Chain_Initialize_empty( &header->Iterators );
+ ISR_lock_Context lock_context;
+
+ _ISR_lock_ISR_disable_and_acquire( &cpu->Watchdog.Lock, &lock_context );
+ _Watchdog_Tickle(
+ &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_ABSOLUTE ],
+ now,
+ &cpu->Watchdog.Lock,
+ &lock_context
+ );
}
/** @} */