Tested on / results?
On Fri, Apr 17, 2015 at 4:55 AM, Sebastian Huber <sebastian.hu...@embedded-brains.de> wrote: > Use mostly the standard watchdog operations. Use a system event for > synchronization. This implementation is simpler and offers better SMP > performance. > > Update #2307. > --- > 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 f0cd676..e84d4e5 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 \ > src/watchdogtickle.c > libscore_a_SOURCES += src/watchdogtickssinceboot.c > > diff --git a/cpukit/score/include/rtems/score/watchdogimpl.h > b/cpukit/score/include/rtems/score/watchdogimpl.h > index 304392b..84c5a6d 100644 > --- a/cpukit/score/include/rtems/score/watchdogimpl.h > +++ b/cpukit/score/include/rtems/score/watchdogimpl.h > @@ -175,6 +175,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. > * > @@ -189,24 +205,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 > ); > > /** > @@ -226,6 +240,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 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel