diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-02-18 08:36:26 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-03-04 13:36:10 +0100 |
commit | 03b900d3ed120ea919ea3eded7edbece3488cff3 (patch) | |
tree | 182781fc14fe15fd67caeb80e46f1c58495839c2 /cpukit/score/include | |
parent | score: Distribute clock tick to all online CPUs (diff) | |
download | rtems-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 'cpukit/score/include')
-rw-r--r-- | cpukit/score/include/rtems/score/mrsp.h | 7 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/mrspimpl.h | 32 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/percpu.h | 53 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/schedulerimpl.h | 16 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/thread.h | 13 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/threadimpl.h | 61 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/todimpl.h | 17 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/watchdog.h | 89 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/watchdogimpl.h | 601 |
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 + ); } /** @} */ |