Use mostly the standard watchdog operations. Use a system event for synchronization. This implementation is simpler and offers better SMP performance.
Close #2131. --- cpukit/rtems/include/rtems/rtems/event.h | 5 + cpukit/rtems/include/rtems/rtems/timerimpl.h | 51 +- cpukit/rtems/src/timerserver.c | 570 +++++++-------------- cpukit/score/Makefile.am | 2 +- cpukit/score/include/rtems/score/watchdogimpl.h | 59 ++- cpukit/score/src/watchdogadjust.c | 35 +- cpukit/score/src/watchdogadjusttochain.c | 75 --- cpukit/score/src/watchdoginsert.c | 21 +- testsuites/sptests/spintrcritical17/init.c | 163 +++--- .../sptests/spintrcritical17/spintrcritical17.doc | 6 +- 10 files changed, 370 insertions(+), 617 deletions(-) delete mode 100644 cpukit/score/src/watchdogadjusttochain.c diff --git a/cpukit/rtems/include/rtems/rtems/event.h b/cpukit/rtems/include/rtems/rtems/event.h index dce7de1..012452a 100644 --- a/cpukit/rtems/include/rtems/rtems/event.h +++ b/cpukit/rtems/include/rtems/rtems/event.h @@ -319,6 +319,11 @@ rtems_status_code rtems_event_receive ( #define RTEMS_EVENT_SYSTEM_NETWORK_CLOSE RTEMS_EVENT_26 /** + * @brief Reserved system event for the timer server. + */ +#define RTEMS_EVENT_SYSTEM_TIMER_SERVER RTEMS_EVENT_30 + +/** * @brief Reserved system event for transient usage. */ #define RTEMS_EVENT_SYSTEM_TRANSIENT RTEMS_EVENT_31 diff --git a/cpukit/rtems/include/rtems/rtems/timerimpl.h b/cpukit/rtems/include/rtems/rtems/timerimpl.h index 4f200ef..e5b37aa 100644 --- a/cpukit/rtems/include/rtems/rtems/timerimpl.h +++ b/cpukit/rtems/include/rtems/rtems/timerimpl.h @@ -65,24 +65,43 @@ typedef struct { Watchdog_Control System_watchdog; /** + * @brief Remaining delta of the system watchdog. + */ + Watchdog_Interval system_watchdog_delta; + + /** + * @brief Unique identifier of the context which deals currently with the + * system watchdog. + */ + Thread_Control *system_watchdog_helper; + + /** + * @brief Each insert and tickle operation increases the generation count so + * that the system watchdog dealer notices updates of the watchdog chain. + */ + uint32_t generation; + + /** * @brief Watchdog header managed by the timer server. */ Watchdog_Header Header; /** - * @brief Last known time snapshot of the timer server. + * @brief Last time snapshot of the timer server. * * The units may be ticks or seconds. */ - Watchdog_Interval volatile last_snapshot; -} Timer_server_Watchdogs; + Watchdog_Interval last_snapshot; -struct Timer_server_Control { /** - * @brief Timer server thread. + * @brief Current time snapshot of the timer server. + * + * The units may be ticks or seconds. */ - Thread_Control *thread; + Watchdog_Interval current_snapshot; +} Timer_server_Watchdogs; +struct Timer_server_Control { /** * @brief The cancel method of the timer server. */ @@ -102,26 +121,6 @@ struct Timer_server_Control { * @brief TOD watchdogs triggered by the timer server. */ Timer_server_Watchdogs TOD_watchdogs; - - /** - * @brief Chain of timers scheduled for insert. - * - * This pointer is not @c NULL whenever the interval and TOD chains are - * processed. After the processing this list will be checked and if - * necessary the processing will be restarted. Processing of these chains - * can be only interrupted through interrupts. - */ - Chain_Control *volatile insert_chain; - - /** - * @brief Indicates that the timer server is active or not. - * - * The server is active after the delay on a system watchdog. The activity - * period of the server ends when no more watchdogs managed by the server - * fire. The system watchdogs must not be manipulated when the server is - * active. - */ - bool volatile active; }; /** diff --git a/cpukit/rtems/src/timerserver.c b/cpukit/rtems/src/timerserver.c index 15cbdfd..db38f48 100644 --- a/cpukit/rtems/src/timerserver.c +++ b/cpukit/rtems/src/timerserver.c @@ -15,7 +15,7 @@ /* COPYRIGHT (c) 1989-2008. * On-Line Applications Research Corporation (OAR). * - * Copyright (c) 2009 embedded brains GmbH. + * Copyright (c) 2009-2015 embedded brains GmbH. * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -26,200 +26,128 @@ #include "config.h" #endif +#include <rtems.h> #include <rtems/rtems/timerimpl.h> #include <rtems/rtems/tasksimpl.h> -#include <rtems/score/isrlevel.h> -#include <rtems/score/threadimpl.h> #include <rtems/score/todimpl.h> static Timer_server_Control _Timer_server_Default; -static void _Timer_server_Stop_interval_system_watchdog( - Timer_server_Control *ts +static void _Timer_server_Cancel_method( + Timer_server_Control *ts, + Timer_Control *timer ) { - _Watchdog_Remove_ticks( &ts->Interval_watchdogs.System_watchdog ); + if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) { + _Watchdog_Remove( &ts->Interval_watchdogs.Header, &timer->Ticker ); + } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) { + _Watchdog_Remove( &ts->TOD_watchdogs.Header, &timer->Ticker ); + } } -static void _Timer_server_Reset_interval_system_watchdog( - Timer_server_Control *ts -) +static Watchdog_Interval _Timer_server_Get_ticks( void ) { - ISR_Level level; - - _Timer_server_Stop_interval_system_watchdog( ts ); - - _ISR_Disable( level ); - if ( !_Watchdog_Is_empty( &ts->Interval_watchdogs.Header ) ) { - Watchdog_Interval delta_interval = - _Watchdog_First( &ts->Interval_watchdogs.Header )->delta_interval; - _ISR_Enable( level ); - - /* - * The unit is TICKS here. - */ - _Watchdog_Insert_ticks( - &ts->Interval_watchdogs.System_watchdog, - delta_interval - ); - } else { - _ISR_Enable( level ); - } + return _Watchdog_Ticks_since_boot; } -static void _Timer_server_Stop_tod_system_watchdog( - Timer_server_Control *ts -) +static Watchdog_Interval _Timer_server_Get_seconds( void ) { - _Watchdog_Remove_seconds( &ts->TOD_watchdogs.System_watchdog ); + return _TOD_Seconds_since_epoch(); } -static void _Timer_server_Reset_tod_system_watchdog( - Timer_server_Control *ts +static void _Timer_server_Update_system_watchdog( + Timer_server_Watchdogs *watchdogs, + Watchdog_Header *system_header ) { - ISR_Level level; + ISR_lock_Context lock_context; - _Timer_server_Stop_tod_system_watchdog( ts ); + _Watchdog_Acquire( &watchdogs->Header, &lock_context ); - _ISR_Disable( level ); - if ( !_Watchdog_Is_empty( &ts->TOD_watchdogs.Header ) ) { - Watchdog_Interval delta_interval = - _Watchdog_First( &ts->TOD_watchdogs.Header )->delta_interval; - _ISR_Enable( level ); + if ( watchdogs->system_watchdog_helper == NULL ) { + Thread_Control *executing; + uint32_t my_generation; - /* - * The unit is SECONDS here. - */ - _Watchdog_Insert_seconds( - &ts->TOD_watchdogs.System_watchdog, - delta_interval - ); - } else { - _ISR_Enable( level ); - } -} + executing = _Thread_Executing; + watchdogs->system_watchdog_helper = executing; -static void _Timer_server_Insert_timer( - Timer_server_Control *ts, - Timer_Control *timer -) -{ - if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) { - _Watchdog_Insert( &ts->Interval_watchdogs.Header, &timer->Ticker ); - } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) { - _Watchdog_Insert( &ts->TOD_watchdogs.Header, &timer->Ticker ); + do { + my_generation = watchdogs->generation; + + if ( !_Watchdog_Is_empty( &watchdogs->Header ) ) { + Watchdog_Control *first; + Watchdog_Interval delta; + + first = _Watchdog_First( &watchdogs->Header ); + delta = first->delta_interval; + + if ( + watchdogs->System_watchdog.state == WATCHDOG_INACTIVE + || delta != watchdogs->system_watchdog_delta + ) { + watchdogs->system_watchdog_delta = delta; + _Watchdog_Release( &watchdogs->Header, &lock_context ); + + _Watchdog_Remove( system_header, &watchdogs->System_watchdog ); + watchdogs->System_watchdog.initial = delta; + _Watchdog_Insert( system_header, &watchdogs->System_watchdog ); + + _Watchdog_Acquire( &watchdogs->Header, &lock_context ); + } + } + } while ( watchdogs->generation != my_generation ); + + watchdogs->system_watchdog_helper = NULL; } + + _Watchdog_Release( &watchdogs->Header, &lock_context ); } -static void _Timer_server_Insert_timer_and_make_snapshot( - Timer_server_Control *ts, - Timer_Control *timer +static void _Timer_server_Insert_timer( + Timer_server_Watchdogs *watchdogs, + Timer_Control *timer, + Watchdog_Header *system_header, + Watchdog_Interval (*get_ticks)( void ) ) { - Watchdog_Control *first_watchdog; - Watchdog_Interval delta_interval; - Watchdog_Interval last_snapshot; - Watchdog_Interval snapshot; + ISR_lock_Context lock_context; + Watchdog_Interval now; Watchdog_Interval delta; - ISR_Level level; - /* - * We have to update the time snapshots here, because otherwise we may have - * problems with the integer range of the delta values. The time delta DT - * from the last snapshot to now may be arbitrarily long. The last snapshot - * is the reference point for the delta chain. Thus if we do not update the - * reference point we have to add DT to the initial delta of the watchdog - * being inserted. This could result in an integer overflow. - */ + _Watchdog_Acquire( &watchdogs->Header, &lock_context ); - _Thread_Disable_dispatch(); + now = (*get_ticks)(); + delta = now - watchdogs->last_snapshot; + watchdogs->last_snapshot = now; + watchdogs->current_snapshot = now; - if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) { - /* - * We have to advance the last known ticks value of the server and update - * the watchdog chain accordingly. - */ - _ISR_Disable( level ); - snapshot = _Watchdog_Ticks_since_boot; - last_snapshot = ts->Interval_watchdogs.last_snapshot; - if ( !_Watchdog_Is_empty( &ts->Interval_watchdogs.Header ) ) { - first_watchdog = _Watchdog_First( &ts->Interval_watchdogs.Header ); - - /* - * We assume adequate unsigned arithmetic here. - */ - delta = snapshot - last_snapshot; - - delta_interval = first_watchdog->delta_interval; - if (delta_interval > delta) { - delta_interval -= delta; - } else { - delta_interval = 0; - } - first_watchdog->delta_interval = delta_interval; - } - ts->Interval_watchdogs.last_snapshot = snapshot; - _ISR_Enable( level ); + if ( watchdogs->system_watchdog_delta > delta ) { + watchdogs->system_watchdog_delta -= delta; + } else { + watchdogs->system_watchdog_delta = 0; + } - _Watchdog_Insert( &ts->Interval_watchdogs.Header, &timer->Ticker ); + if ( !_Watchdog_Is_empty( &watchdogs->Header ) ) { + Watchdog_Control *first = _Watchdog_First( &watchdogs->Header ); - if ( !ts->active ) { - _Timer_server_Reset_interval_system_watchdog( ts ); - } - } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) { - /* - * We have to advance the last known seconds value of the server and update - * the watchdog chain accordingly. - */ - _ISR_Disable( level ); - snapshot = (Watchdog_Interval) _TOD_Seconds_since_epoch(); - last_snapshot = ts->TOD_watchdogs.last_snapshot; - if ( !_Watchdog_Is_empty( &ts->TOD_watchdogs.Header ) ) { - first_watchdog = _Watchdog_First( &ts->TOD_watchdogs.Header ); - delta_interval = first_watchdog->delta_interval; - if ( snapshot > last_snapshot ) { - /* - * We advanced in time. - */ - delta = snapshot - last_snapshot; - if (delta_interval > delta) { - delta_interval -= delta; - } else { - delta_interval = 0; - } - } else { - /* - * Someone put us in the past. - */ - delta = last_snapshot - snapshot; - delta_interval += delta; - } - first_watchdog->delta_interval = delta_interval; + if ( first->delta_interval > delta ) { + first->delta_interval -= delta; + } else { + first->delta_interval = 0; } - ts->TOD_watchdogs.last_snapshot = snapshot; - _ISR_Enable( level ); + } - _Watchdog_Insert( &ts->TOD_watchdogs.Header, &timer->Ticker ); + _Watchdog_Insert_locked( + &watchdogs->Header, + &timer->Ticker, + &lock_context + ); - if ( !ts->active ) { - _Timer_server_Reset_tod_system_watchdog( ts ); - } - } + ++watchdogs->generation; - _Thread_Enable_dispatch(); -} + _Watchdog_Release( &watchdogs->Header, &lock_context ); -static void _Timer_server_Cancel_method( - Timer_server_Control *ts, - Timer_Control *timer -) -{ - if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) { - _Watchdog_Remove( &ts->Interval_watchdogs.Header, &timer->Ticker ); - } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) { - _Watchdog_Remove( &ts->TOD_watchdogs.Header, &timer->Ticker ); - } + _Timer_server_Update_system_watchdog( watchdogs, system_header ); } static void _Timer_server_Schedule_operation_method( @@ -227,143 +155,71 @@ static void _Timer_server_Schedule_operation_method( Timer_Control *timer ) { - if ( ts->insert_chain == NULL ) { - _Timer_server_Insert_timer_and_make_snapshot( ts, timer ); - } else { - /* - * We interrupted a critical section of the timer server. The timer - * server is not preemptible, so we must be in interrupt context here. No - * thread dispatch will happen until the timer server finishes its - * critical section. We have to use the protected chain methods because - * we may be interrupted by a higher priority interrupt. - */ - _Chain_Append( ts->insert_chain, &timer->Object.Node ); + if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) { + _Timer_server_Insert_timer( + &ts->Interval_watchdogs, + timer, + &_Watchdog_Ticks_header, + _Timer_server_Get_ticks + ); + } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) { + _Timer_server_Insert_timer( + &ts->TOD_watchdogs, + timer, + &_Watchdog_Seconds_header, + _Timer_server_Get_seconds + ); } } -static void _Timer_server_Process_interval_watchdogs( +static void _Timer_server_Update_current_snapshot( Timer_server_Watchdogs *watchdogs, - Chain_Control *fire_chain + Watchdog_Interval (*get_ticks)( void ) ) { - Watchdog_Interval snapshot = _Watchdog_Ticks_since_boot; + ISR_lock_Context lock_context; - /* - * We assume adequate unsigned arithmetic here. - */ - Watchdog_Interval delta = snapshot - watchdogs->last_snapshot; - - watchdogs->last_snapshot = snapshot; - - _Watchdog_Adjust_to_chain( &watchdogs->Header, delta, fire_chain ); + _Watchdog_Acquire( &watchdogs->Header, &lock_context ); + watchdogs->current_snapshot = (*get_ticks)(); + watchdogs->system_watchdog_delta = 0; + _Watchdog_Release( &watchdogs->Header, &lock_context ); } -static void _Timer_server_Process_tod_watchdogs( +static void _Timer_server_Tickle( Timer_server_Watchdogs *watchdogs, - Chain_Control *fire_chain + Watchdog_Header *system_header, + Watchdog_Interval (*get_ticks)( void ), + bool ticks ) { - Watchdog_Interval snapshot = (Watchdog_Interval) _TOD_Seconds_since_epoch(); - Watchdog_Interval last_snapshot = watchdogs->last_snapshot; - Watchdog_Interval delta; - - /* - * Process the seconds chain. Start by checking that the Time - * of Day (TOD) has not been set backwards. If it has then - * we want to adjust the watchdogs->Header to indicate this. - */ - if ( snapshot > last_snapshot ) { - /* - * This path is for normal forward movement and cases where the - * TOD has been set forward. - */ - delta = snapshot - last_snapshot; - _Watchdog_Adjust_to_chain( &watchdogs->Header, delta, fire_chain ); - - } else if ( snapshot < last_snapshot ) { - /* - * The current TOD is before the last TOD which indicates that - * TOD has been set backwards. - */ - delta = last_snapshot - snapshot; - _Watchdog_Adjust_backward( &watchdogs->Header, delta ); - } - - watchdogs->last_snapshot = snapshot; -} - -static void _Timer_server_Process_insertions( Timer_server_Control *ts ) -{ - while ( true ) { - Timer_Control *timer = (Timer_Control *) _Chain_Get( ts->insert_chain ); + ISR_lock_Context lock_context; + Watchdog_Interval now; + Watchdog_Interval last; - if ( timer == NULL ) { - break; - } - - _Timer_server_Insert_timer( ts, timer ); - } -} - -static void _Timer_server_Get_watchdogs_that_fire_now( - Timer_server_Control *ts, - Chain_Control *insert_chain, - Chain_Control *fire_chain -) -{ - /* - * Afterwards all timer inserts are directed to this chain and the interval - * and TOD chains will be no more modified by other parties. - */ - ts->insert_chain = insert_chain; + _Watchdog_Acquire( &watchdogs->Header, &lock_context ); - while ( true ) { - ISR_Level level; + now = watchdogs->current_snapshot; + last = watchdogs->last_snapshot; + watchdogs->last_snapshot = now; - /* - * Remove all the watchdogs that need to fire so we can invoke them. - */ - _Timer_server_Process_interval_watchdogs( - &ts->Interval_watchdogs, - fire_chain + if ( ticks || now >= last ) { + _Watchdog_Adjust_forward_locked( + &watchdogs->Header, + now - last, + &lock_context + ); + } else { + _Watchdog_Adjust_backward_locked( + &watchdogs->Header, + last - now ); - _Timer_server_Process_tod_watchdogs( &ts->TOD_watchdogs, fire_chain ); - - /* - * The insertions have to take place here, because they reference the - * current time. The previous process methods take a snapshot of the - * current time. In case someone inserts a watchdog with an initial value - * of zero it will be processed in the next iteration of the timer server - * body loop. - */ - _Timer_server_Process_insertions( ts ); - - _ISR_Disable( level ); - if ( _Chain_Is_empty( insert_chain ) ) { - ts->insert_chain = NULL; - _ISR_Enable( level ); - - break; - } else { - _ISR_Enable( level ); - } } -} -/* FIXME: This locking approach for SMP is improvable! */ + ++watchdogs->generation; -static void _Timer_server_SMP_lock_aquire( void ) -{ -#if defined( RTEMS_SMP ) - _Thread_Disable_dispatch(); -#endif -} + _Watchdog_Release( &watchdogs->Header, &lock_context ); -static void _Timer_server_SMP_lock_release( void ) -{ -#if defined( RTEMS_SMP ) - _Thread_Enable_dispatch(); -#endif + _Timer_server_Update_system_watchdog( watchdogs, system_header ); } /** @@ -380,81 +236,73 @@ static rtems_task _Timer_server_Body( ) { Timer_server_Control *ts = (Timer_server_Control *) arg; - Chain_Control insert_chain; - Chain_Control fire_chain; - _Chain_Initialize_empty( &insert_chain ); - _Chain_Initialize_empty( &fire_chain ); + while ( true ) { + rtems_event_set events; - _Timer_server_SMP_lock_aquire(); + _Timer_server_Tickle( + &ts->Interval_watchdogs, + &_Watchdog_Ticks_header, + _Timer_server_Get_ticks, + true + ); - while ( true ) { - _Timer_server_Get_watchdogs_that_fire_now( ts, &insert_chain, &fire_chain ); - - if ( !_Chain_Is_empty( &fire_chain ) ) { - /* - * Fire the watchdogs. - */ - while ( true ) { - Watchdog_Control *watchdog; - ISR_Level level; - - /* - * It is essential that interrupts are disable here since an interrupt - * service routine may remove a watchdog from the chain. - */ - _ISR_Disable( level ); - watchdog = (Watchdog_Control *) _Chain_Get_unprotected( &fire_chain ); - if ( watchdog != NULL ) { - watchdog->state = WATCHDOG_INACTIVE; - _ISR_Enable( level ); - } else { - _ISR_Enable( level ); - - break; - } + _Timer_server_Tickle( + &ts->TOD_watchdogs, + &_Watchdog_Seconds_header, + _Timer_server_Get_seconds, + false + ); - _Timer_server_SMP_lock_release(); + (void) rtems_event_system_receive( + RTEMS_EVENT_SYSTEM_TIMER_SERVER, + RTEMS_EVENT_ALL | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + } +} - /* - * The timer server may block here and wait for resources or time. - * The system watchdogs are inactive and will remain inactive since - * the active flag of the timer server is true. - */ - (*watchdog->routine)( watchdog->id, watchdog->user_data ); +static void _Timer_server_Wakeup( + Objects_Id id, + void *arg +) +{ + Timer_server_Control *ts = arg; - _Timer_server_SMP_lock_aquire(); - } - } else { - ts->active = false; + _Timer_server_Update_current_snapshot( + &ts->Interval_watchdogs, + _Timer_server_Get_ticks + ); - /* - * Block until there is something to do. - */ -#if !defined( RTEMS_SMP ) - _Thread_Disable_dispatch(); -#endif - _Thread_Set_state( ts->thread, STATES_DELAYING ); - _Timer_server_Reset_interval_system_watchdog( ts ); - _Timer_server_Reset_tod_system_watchdog( ts ); -#if !defined( RTEMS_SMP ) - _Thread_Enable_dispatch(); -#endif + _Timer_server_Update_current_snapshot( + &ts->TOD_watchdogs, + _Timer_server_Get_seconds + ); - _Timer_server_SMP_lock_release(); - _Timer_server_SMP_lock_aquire(); + (void) rtems_event_system_send( id, RTEMS_EVENT_SYSTEM_TIMER_SERVER ); +} - ts->active = true; +static void _Timer_server_Initialize_watchdogs( + Timer_server_Control *ts, + rtems_id id, + Timer_server_Watchdogs *watchdogs, + Watchdog_Interval (*get_ticks)( void ) +) +{ + Watchdog_Interval now; - /* - * Maybe an interrupt did reset the system timers, so we have to stop - * them here. Since we are active now, there will be no more resets - * until we are inactive again. - */ - _Timer_server_Stop_interval_system_watchdog( ts ); - _Timer_server_Stop_tod_system_watchdog( ts ); - } - } + now = (*get_ticks)(); + watchdogs->last_snapshot = now; + watchdogs->current_snapshot = now; + + _Watchdog_Header_initialize( &watchdogs->Header ); + _Watchdog_Initialize( + &watchdogs->System_watchdog, + _Timer_server_Wakeup, + id, + ts + ); } /** @@ -542,36 +390,18 @@ rtems_status_code rtems_timer_initiate_server( * Timer Server so we do not have to have a critical section. */ - /* - * We work with the TCB pointer, not the ID, so we need to convert - * to a TCB pointer from here out. - */ - ts->thread = (Thread_Control *)_Objects_Get_local_object( - &_RTEMS_tasks_Information, - _Objects_Get_index(id) + _Timer_server_Initialize_watchdogs( + ts, + id, + &ts->Interval_watchdogs, + _Timer_server_Get_ticks ); - /* - * Initialize the timer lists that the server will manage. - */ - _Watchdog_Header_initialize( &ts->Interval_watchdogs.Header ); - _Watchdog_Header_initialize( &ts->TOD_watchdogs.Header ); - - /* - * Initialize the timers that will be used to control when the - * Timer Server wakes up and services the task-based timers. - */ - _Watchdog_Initialize( - &ts->Interval_watchdogs.System_watchdog, - _Thread_Delay_ended, - 0, - ts->thread - ); - _Watchdog_Initialize( - &ts->TOD_watchdogs.System_watchdog, - _Thread_Delay_ended, - 0, - ts->thread + _Timer_server_Initialize_watchdogs( + ts, + id, + &ts->TOD_watchdogs, + _Timer_server_Get_seconds ); /* @@ -581,12 +411,6 @@ rtems_status_code rtems_timer_initiate_server( ts->cancel = _Timer_server_Cancel_method; ts->schedule_operation = _Timer_server_Schedule_operation_method; - ts->Interval_watchdogs.last_snapshot = _Watchdog_Ticks_since_boot; - ts->TOD_watchdogs.last_snapshot = (Watchdog_Interval) _TOD_Seconds_since_epoch(); - - ts->insert_chain = NULL; - ts->active = false; - /* * The default timer server is now available. */ diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index af7da2a..3eb2caa 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -324,7 +324,7 @@ libscore_a_SOURCES += src/coretod.c src/coretodset.c src/coretodget.c \ ## WATCHDOG_C_FILES libscore_a_SOURCES += src/watchdog.c src/watchdogadjust.c \ - src/watchdogadjusttochain.c src/watchdoginsert.c src/watchdogremove.c + src/watchdoginsert.c src/watchdogremove.c libscore_a_SOURCES += src/watchdogtickssinceboot.c ## USEREXT_C_FILES diff --git a/cpukit/score/include/rtems/score/watchdogimpl.h b/cpukit/score/include/rtems/score/watchdogimpl.h index dfe50e6..6804bf2 100644 --- a/cpukit/score/include/rtems/score/watchdogimpl.h +++ b/cpukit/score/include/rtems/score/watchdogimpl.h @@ -165,6 +165,22 @@ void _Watchdog_Adjust_backward( ); /** + * @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 +); + +/** * @brief Adjusts the header watchdog chain in the forward direction for units * ticks. * @@ -179,24 +195,22 @@ void _Watchdog_Adjust_forward( ); /** - * @brief Adjusts the @a header watchdog chain in the forward - * @a direction for @a units_arg ticks. + * @brief Adjusts the watchdogs in forward direction in a locked context. * - * This routine adjusts the @a header watchdog chain in the forward - * @a direction for @a units_arg ticks. + * 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 is the watchdog chain to adjust - * @param[in] units_arg is the number of units to adjust @a header - * @param[in] to_fire is a pointer to an initialized Chain_Control to which - * all watchdog instances that are to be fired will be placed. + * @param[in] header The watchdog header. + * @param[in] units The units of ticks to adjust. + * @param[in] lock_context The lock context. * - * @note This always adjusts forward. + * @see _Watchdog_Adjust_forward(). */ -void _Watchdog_Adjust_to_chain( +void _Watchdog_Adjust_forward_locked( Watchdog_Header *header, - Watchdog_Interval units_arg, - Chain_Control *to_fire - + Watchdog_Interval units, + ISR_lock_Context *lock_context ); /** @@ -216,6 +230,25 @@ void _Watchdog_Insert ( ); /** + * @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, + Watchdog_Control *the_watchdog, + ISR_lock_Context *lock_context +); + +/** * @brief This routine is invoked at appropriate intervals to update * the @a header watchdog chain. * diff --git a/cpukit/score/src/watchdogadjust.c b/cpukit/score/src/watchdogadjust.c index 04fc1a5..32b5f79 100644 --- a/cpukit/score/src/watchdogadjust.c +++ b/cpukit/score/src/watchdogadjust.c @@ -19,26 +19,18 @@ #endif #include <rtems/score/watchdogimpl.h> -#include <rtems/score/chainimpl.h> -#include <rtems/score/isrlevel.h> -void _Watchdog_Adjust_backward( +void _Watchdog_Adjust_backward_locked( Watchdog_Header *header, Watchdog_Interval units ) { - ISR_lock_Context lock_context; - - _Watchdog_Acquire( header, &lock_context ); - if ( !_Watchdog_Is_empty( header ) ) { _Watchdog_First( header )->delta_interval += units; } - - _Watchdog_Release( header, &lock_context ); } -void _Watchdog_Adjust_forward( +void _Watchdog_Adjust_backward( Watchdog_Header *header, Watchdog_Interval units ) @@ -46,7 +38,16 @@ void _Watchdog_Adjust_forward( ISR_lock_Context lock_context; _Watchdog_Acquire( header, &lock_context ); + _Watchdog_Adjust_backward_locked( header, units ); + _Watchdog_Release( header, &lock_context ); +} +void _Watchdog_Adjust_forward_locked( + Watchdog_Header *header, + Watchdog_Interval units, + ISR_lock_Context *lock_context +) +{ while ( !_Watchdog_Is_empty( header ) && units > 0 ) { Watchdog_Control *first = _Watchdog_First( header ); @@ -57,13 +58,23 @@ void _Watchdog_Adjust_forward( units -= first->delta_interval; first->delta_interval = 1; - _Watchdog_Release( header, &lock_context ); + _Watchdog_Release( header, lock_context ); _Watchdog_Tickle( header ); - _Watchdog_Acquire( header, &lock_context ); + _Watchdog_Acquire( header, lock_context ); } } +} +void _Watchdog_Adjust_forward( + Watchdog_Header *header, + Watchdog_Interval units +) +{ + ISR_lock_Context lock_context; + + _Watchdog_Acquire( header, &lock_context ); + _Watchdog_Adjust_forward_locked( header, units, &lock_context ); _Watchdog_Release( header, &lock_context ); } diff --git a/cpukit/score/src/watchdogadjusttochain.c b/cpukit/score/src/watchdogadjusttochain.c deleted file mode 100644 index b3063e4..0000000 --- a/cpukit/score/src/watchdogadjusttochain.c +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @file - * - * @brief Watchdog Adjust to Chain - * @ingroup ScoreWatchdog - */ - -/* - * COPYRIGHT (c) 1989-2009. - * 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. - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include <rtems/score/watchdogimpl.h> -#include <rtems/score/isrlevel.h> - -void _Watchdog_Adjust_to_chain( - Watchdog_Header *header, - Watchdog_Interval units_arg, - Chain_Control *to_fire - -) -{ - Watchdog_Interval units = units_arg; - ISR_lock_Context lock_context; - Watchdog_Control *first; - - _Watchdog_Acquire( header, &lock_context ); - - while ( 1 ) { - if ( _Watchdog_Is_empty( header ) ) { - break; - } - first = _Watchdog_First( header ); - - /* - * If it is longer than "units" until the first element on the chain - * fires, then bump it and quit. - */ - if ( units < first->delta_interval ) { - first->delta_interval -= units; - break; - } - - /* - * The first set happens in less than units, so take all of them - * off the chain and adjust units to reflect this. - */ - units -= first->delta_interval; - first->delta_interval = 0; - - while ( 1 ) { - _Chain_Extract_unprotected( &first->Node ); - _Chain_Append_unprotected( to_fire, &first->Node ); - - _Watchdog_Flash( header, &lock_context ); - - if ( _Watchdog_Is_empty( header ) ) - break; - first = _Watchdog_First( header ); - if ( first->delta_interval != 0 ) - break; - } - } - - _Watchdog_Release( header, &lock_context ); -} - diff --git a/cpukit/score/src/watchdoginsert.c b/cpukit/score/src/watchdoginsert.c index 6d2df82..6b81c7b 100644 --- a/cpukit/score/src/watchdoginsert.c +++ b/cpukit/score/src/watchdoginsert.c @@ -47,15 +47,12 @@ static void _Watchdog_Insert_fixup( } } -void _Watchdog_Insert( +void _Watchdog_Insert_locked( Watchdog_Header *header, - Watchdog_Control *the_watchdog + Watchdog_Control *the_watchdog, + ISR_lock_Context *lock_context ) { - ISR_lock_Context lock_context; - - _Watchdog_Acquire( header, &lock_context ); - if ( the_watchdog->state == WATCHDOG_INACTIVE ) { Watchdog_Iterator iterator; Chain_Node *current; @@ -86,7 +83,7 @@ void _Watchdog_Insert( iterator.delta_interval = delta - delta_next; iterator.current = next; - _Watchdog_Flash( header, &lock_context ); + _Watchdog_Flash( header, lock_context ); if ( the_watchdog->state != WATCHDOG_BEING_INSERTED ) { goto abort_insert; @@ -105,6 +102,16 @@ abort_insert: _Chain_Extract_unprotected( &iterator.Node ); } +} +void _Watchdog_Insert( + Watchdog_Header *header, + Watchdog_Control *the_watchdog +) +{ + ISR_lock_Context lock_context; + + _Watchdog_Acquire( header, &lock_context ); + _Watchdog_Insert_locked( header, the_watchdog, &lock_context ); _Watchdog_Release( header, &lock_context ); } diff --git a/testsuites/sptests/spintrcritical17/init.c b/testsuites/sptests/spintrcritical17/init.c index 9dde48a..238493e 100644 --- a/testsuites/sptests/spintrcritical17/init.c +++ b/testsuites/sptests/spintrcritical17/init.c @@ -1,10 +1,11 @@ /* - * Copyright (c) 2009 - * embedded brains GmbH - * Obere Lagerstr. 30 - * D-82178 Puchheim - * Germany - * <rt...@embedded-brains.de> + * Copyright (c) 2009-2014 embedded brains GmbH. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rt...@embedded-brains.de> * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -22,141 +23,91 @@ const char rtems_test_name[] = "SPINTRCRITICAL 17"; -/* forward declarations to avoid warnings */ -rtems_task Init(rtems_task_argument argument); - -#define TIMER_COUNT 4 - -#define TIMER_TRIGGER 0 -#define TIMER_RESET 1 -#define TIMER_NEVER_INTERVAL 2 -#define TIMER_NEVER_TOD 3 - -static rtems_id timer [TIMER_COUNT]; +typedef struct { + rtems_id timer1; + rtems_id timer2; + bool done; +} test_context; -static rtems_time_of_day tod; - -static volatile bool case_hit; - -static void never_callback(rtems_id timer, void *arg) -{ - rtems_test_assert(false); -} +static test_context ctx_instance; -static void reset_tod_timer(void) +static void never(rtems_id timer_id, void *arg) { - rtems_status_code sc = RTEMS_SUCCESSFUL; - - sc = rtems_timer_server_fire_when( - timer [TIMER_NEVER_TOD], - &tod, - never_callback, - NULL - ); - directive_failed_with_level(sc, "rtems_timer_server_fire_after", -1); + rtems_test_assert(0); } -static void reset_callback(rtems_id timer_id, void *arg) +static void fire(rtems_id timer_id, void *arg) { - rtems_status_code sc = RTEMS_SUCCESSFUL; - - sc = rtems_timer_reset(timer [TIMER_RESET]); - directive_failed_with_level(sc, "rtems_timer_reset", -1); - - sc = rtems_timer_reset(timer [TIMER_NEVER_INTERVAL]); - directive_failed_with_level(sc, "rtems_timer_reset", -1); - - reset_tod_timer(); - - if (!case_hit) { - case_hit = _Timer_server->insert_chain != NULL; + /* The arg is NULL */ + test_context *ctx = &ctx_instance; + rtems_status_code sc; + + if (!ctx->done) { + ctx->done = + _Timer_server->Interval_watchdogs.system_watchdog_helper != NULL; + + if (ctx->done) { + sc = rtems_timer_server_fire_after(ctx->timer2, 100, never, NULL); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + } } } -static void trigger_callback(rtems_id timer_id, void *arg) +static bool test_body(void *arg) { - rtems_status_code sc = RTEMS_SUCCESSFUL; + test_context *ctx = arg; + rtems_status_code sc; - if (case_hit) { - TEST_END(); + sc = rtems_timer_reset(ctx->timer1); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); - rtems_test_exit(0); - } else if (interrupt_critical_section_test_support_delay()) { - puts("test case not hit, give up"); - - rtems_test_exit(0); - } - - sc = rtems_timer_reset(timer [TIMER_TRIGGER]); - directive_failed(sc, "rtems_timer_reset"); + return ctx->done; } -rtems_task Init( rtems_task_argument ignored ) +static void Init(rtems_task_argument ignored) { - rtems_status_code sc = RTEMS_SUCCESSFUL; - size_t i = 0; + test_context *ctx = &ctx_instance; + rtems_status_code sc; TEST_BEGIN(); - build_time(&tod, 4, 12, 2009, 9, 34, 11, 0); - sc = rtems_clock_set(&tod); - directive_failed(sc, "rtems_clock_set"); - - ++tod.year; + sc = rtems_timer_create( + rtems_build_name('T', 'I', 'M', '1'), + &ctx->timer1 + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); - for (i = 0; i < TIMER_COUNT; ++i) { - sc = rtems_timer_create( - rtems_build_name('T', 'I', 'M', '0' + i), - &timer [i] - ); - directive_failed(sc, "rtems_timer_create"); - } + sc = rtems_timer_create( + rtems_build_name('T', 'I', 'M', '2'), + &ctx->timer2 + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); sc = rtems_timer_initiate_server( RTEMS_MINIMUM_PRIORITY, RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_ATTRIBUTES ); - directive_failed(sc, "rtems_timer_initiate_server"); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); - sc = rtems_timer_server_fire_after( - timer [TIMER_NEVER_INTERVAL], - 2, - never_callback, - NULL - ); - directive_failed(sc, "rtems_timer_server_fire_after"); - - reset_tod_timer(); - - sc = rtems_timer_fire_after( - timer [TIMER_RESET], - 1, - reset_callback, - NULL - ); - directive_failed(sc, "rtems_timer_fire_after"); - - sc = rtems_timer_server_fire_after( - timer [TIMER_TRIGGER], - 1, - trigger_callback, - NULL - ); - directive_failed(sc, "rtems_timer_server_fire_after"); + sc = rtems_timer_server_fire_after(ctx->timer1, 1000, never, NULL); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); - interrupt_critical_section_test_support_initialize(NULL); + interrupt_critical_section_test(test_body, ctx, fire); + rtems_test_assert(ctx->done); - rtems_task_delete(RTEMS_SELF); + TEST_END(); + rtems_test_exit(0); } #define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER -#define CONFIGURE_MICROSECONDS_PER_TICK 2000 +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 #define CONFIGURE_MAXIMUM_TASKS 2 -#define CONFIGURE_MAXIMUM_TIMERS 4 +#define CONFIGURE_MAXIMUM_TIMERS 3 +#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION diff --git a/testsuites/sptests/spintrcritical17/spintrcritical17.doc b/testsuites/sptests/spintrcritical17/spintrcritical17.doc index 3be8e60..809a966 100644 --- a/testsuites/sptests/spintrcritical17/spintrcritical17.doc +++ b/testsuites/sptests/spintrcritical17/spintrcritical17.doc @@ -1,4 +1,4 @@ -# Copyright (c) 2009 embedded brains GmbH. +# Copyright (c) 2009-2015 embedded brains GmbH. # # The license and distribution terms for this file may be # found in the file LICENSE in this distribution or at @@ -11,9 +11,7 @@ test set name: spintrcritical17 directives: - _Timer_server_Get_watchdogs_that_fire_now - _Timer_server_Schedule_operation_method - _Timer_server_Process_insertions + _Timer_server_Update_system_watchdog concepts: -- 1.8.4.5 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel