[PATCH 4/4] score: New timer server implementation
Gedare Bloom
gedare at rtems.org
Fri Apr 17 14:17:46 UTC 2015
Tested on / results?
On Fri, Apr 17, 2015 at 4:55 AM, Sebastian Huber
<sebastian.huber at 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
> - * <rtems at embedded-brains.de>
> + * Copyright (c) 2009-2014 embedded brains GmbH.
> + *
> + * embedded brains GmbH
> + * Dornierstr. 4
> + * 82178 Puchheim
> + * Germany
> + * <rtems at 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 at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
More information about the devel
mailing list