From 109ace3a1f0f6f26d974a1ed8e9595aa0eef0885 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Wed, 3 Dec 2008 20:58:29 +0000 Subject: 2008-12-03 Joel Sherrill PR 1347/cpukit * rtems/include/rtems/rtems/timer.h, rtems/src/rtemstimer.c, rtems/src/timerreset.c, rtems/src/timerserver.c, rtems/src/timerserverfireafter.c, rtems/src/timerserverfirewhen.c, score/Makefile.am, score/include/rtems/score/watchdog.h: Rework Timer Server to ensure that the context allows for blocking, allocating memory, and acquiring semaphores and mutexes. * score/src/watchdogadjusttochain.c: New file. --- cpukit/ChangeLog | 11 + cpukit/rtems/include/rtems/rtems/timer.h | 107 ++------ cpukit/rtems/src/rtemstimer.c | 1 + cpukit/rtems/src/timerreset.c | 9 +- cpukit/rtems/src/timerserver.c | 401 +++++++++++++++++++--------- cpukit/rtems/src/timerserverfireafter.c | 10 +- cpukit/rtems/src/timerserverfirewhen.c | 10 +- cpukit/score/Makefile.am | 4 +- cpukit/score/include/rtems/score/watchdog.h | 19 ++ cpukit/score/src/watchdogadjusttochain.c | 67 +++++ 10 files changed, 406 insertions(+), 233 deletions(-) create mode 100644 cpukit/score/src/watchdogadjusttochain.c (limited to 'cpukit') diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog index ecb3983f4f..d8cf203be9 100644 --- a/cpukit/ChangeLog +++ b/cpukit/ChangeLog @@ -1,3 +1,14 @@ +2008-12-03 Joel Sherrill + + PR 1347/cpukit + * rtems/include/rtems/rtems/timer.h, rtems/src/rtemstimer.c, + rtems/src/timerreset.c, rtems/src/timerserver.c, + rtems/src/timerserverfireafter.c, rtems/src/timerserverfirewhen.c, + score/Makefile.am, score/include/rtems/score/watchdog.h: Rework Timer + Server to ensure that the context allows for blocking, allocating + memory, and acquiring semaphores and mutexes. + * score/src/watchdogadjusttochain.c: New file. + 2008-12-03 Joel Sherrill PR 1346/cpukit diff --git a/cpukit/rtems/include/rtems/rtems/timer.h b/cpukit/rtems/include/rtems/rtems/timer.h index a7d6029620..711995e983 100644 --- a/cpukit/rtems/include/rtems/rtems/timer.h +++ b/cpukit/rtems/include/rtems/rtems/timer.h @@ -58,7 +58,12 @@ extern "C" { /** * @defgroup ClassicTimer Classic API Timer * - * This encapsulates functionality which XXX + * This encapsulates functionality related to the Classic API Timer + * Manager. This manager provides functionality which allows the + * application to schedule the execution of methods at a specified + * time in the future. These methods may be scheduled based upon + * interval or wall time and may be executed in either the clock tick + * ISR or in a special dedicated timer server task. */ /**@{*/ @@ -125,32 +130,6 @@ RTEMS_TIMER_EXTERN Objects_Information _Timer_Information; */ RTEMS_TIMER_EXTERN Thread_Control *_Timer_Server; -/** - * This chain contains the list of interval timers that are - * executed in the context of the Timer Server. - * - * @note This is extern'ed because they do not have to be in the - * minimum footprint. It is only really required when - * task-based timers are used. Since task-based timers can - * not be started until the server is initiated, this structure - * does not have to be initialized until then. This is declared - * in the same file as _Timer_Server_body. - */ -extern Chain_Control _Timer_Ticks_chain; - -/** - * This chain contains the list of time of day timers that are - * executed in the context of the Timer Server. - * - * @note This is extern'ed because they do not have to be in the - * minimum footprint. It is only really required when - * task-based timers are used. Since task-based timers can - * not be started until the server is initiated, this structure - * does not have to be initialized until then. This is declared - * in the same file as _Timer_Server_body. - */ -extern Chain_Control _Timer_Seconds_chain; - /** * The following records define the control block used to manage * each timer. @@ -173,18 +152,6 @@ void _Timer_Manager_initialization( uint32_t maximum_timers ); -/** - * @brief _Timer_Server_body - * - * This is the server for task based timers. This task executes whenever - * a task-based timer should fire. It services both "after" and "when" - * timers. It is not created automatically but must be created explicitly - * by the application before task-based timers may be initiated. - */ -Thread _Timer_Server_body( - uint32_t ignored -); - /** * @brief rtems_timer_create * @@ -353,63 +320,19 @@ rtems_status_code rtems_timer_get_information( ); /** - * Macros and routines that expose the mechanisms required to service - * the Timer Server timer. These stop the timer, synchronize it with - * the current time, and restart it. + * This type defines the method used to schedule the insertion of task + * based timers. */ -extern Watchdog_Control _Timer_Seconds_timer; - -/** - * This method is used to temporarily disable updates to the - * Ticks Timer Chain managed by the Timer Server. - */ -#define _Timer_Server_stop_ticks_timer() \ - _Watchdog_Remove( &_Timer_Server->Timer ) - -/** - * This method is used to temporarily disable updates to the - * Seconds Timer Chain managed by the Timer Server. - */ -#define _Timer_Server_stop_seconds_timer() \ - _Watchdog_Remove( &_Timer_Seconds_timer ); - -/** - * This is a helper function which processes the ticks chain when - * needed. It advances time for the ticks chain which results in - * timers firing. - */ -void _Timer_Server_process_ticks_chain(void); - -/** - * This is a helper function which processes the seconds chain when - * needed. It advances time for the seconds chain which results in - * timers firing. - */ -void _Timer_Server_process_seconds_chain(void); - -/** - * This method resets a timer and places it on the Ticks chain. It - * is assumed that the timer has already been canceled. - */ -#define _Timer_Server_reset_ticks_timer() \ - do { \ - if ( !_Chain_Is_empty( &_Timer_Ticks_chain ) ) { \ - _Watchdog_Insert_ticks( &_Timer_Server->Timer, \ - ((Watchdog_Control *)_Timer_Ticks_chain.first)->delta_interval ); \ - } \ - } while (0) +typedef void (*Timer_Server_schedule_operation_t)( + Timer_Control *the_timer +); /** - * This method resets a timer and places it on the Seconds chain. It - * is assumed that the timer has already been canceled. + * This variable will point to the schedule operation method once the + * timer server is initialized. */ -#define _Timer_Server_reset_seconds_timer() \ - do { \ - if ( !_Chain_Is_empty( &_Timer_Seconds_chain ) ) { \ - _Watchdog_Insert_seconds( &_Timer_Seconds_timer, \ - ((Watchdog_Control *)_Timer_Seconds_chain.first)->delta_interval ); \ - } \ - } while (0) +RTEMS_TIMER_EXTERN Timer_Server_schedule_operation_t + _Timer_Server_schedule_operation; #ifndef __RTEMS_APPLICATION__ #include diff --git a/cpukit/rtems/src/rtemstimer.c b/cpukit/rtems/src/rtemstimer.c index 909bb9b15a..a7dd750656 100644 --- a/cpukit/rtems/src/rtemstimer.c +++ b/cpukit/rtems/src/rtemstimer.c @@ -62,4 +62,5 @@ void _Timer_Manager_initialization( */ _Timer_Server = NULL; + _Timer_Server_schedule_operation = NULL; } diff --git a/cpukit/rtems/src/timerreset.c b/cpukit/rtems/src/timerreset.c index 7fea9fa7d5..1688051f8a 100644 --- a/cpukit/rtems/src/timerreset.c +++ b/cpukit/rtems/src/timerreset.c @@ -56,11 +56,12 @@ rtems_status_code rtems_timer_reset( _Watchdog_Insert( &_Watchdog_Ticks_chain, &the_timer->Ticker ); break; case TIMER_INTERVAL_ON_TASK: - _Timer_Server_stop_ticks_timer(); + if ( !_Timer_Server_schedule_operation ) { + _Thread_Enable_dispatch(); + return RTEMS_INCORRECT_STATE; + } _Watchdog_Remove( &the_timer->Ticker ); - _Timer_Server_process_ticks_chain(); - _Watchdog_Insert( &_Timer_Ticks_chain, &the_timer->Ticker ); - _Timer_Server_reset_ticks_timer(); + (*_Timer_Server_schedule_operation)( the_timer ); break; case TIMER_TIME_OF_DAY: case TIMER_TIME_OF_DAY_ON_TASK: diff --git a/cpukit/rtems/src/timerserver.c b/cpukit/rtems/src/timerserver.c index a96b45272e..9c4ea90b50 100644 --- a/cpukit/rtems/src/timerserver.c +++ b/cpukit/rtems/src/timerserver.c @@ -1,8 +1,18 @@ -/* +/** + * @file timerserver.c + * * Timer Manager - rtems_timer_initiate_server directive along with - * the Timer Server Body and support routines + * the Timer Server Body and support routines * - * COPYRIGHT (c) 1989-2008. + * @note Data specific to the Timer Server is declared in this + * file as the Timer Server so it does not have to be in the + * minimum footprint. It is only really required when + * task-based timers are used. Since task-based timers can + * not be started until the server is initiated, this structure + * does not have to be initialized until then. + */ + +/* COPYRIGHT (c) 1989-2008. * On-Line Applications Research Corporation (OAR). * * The license and distribution terms for this file may be @@ -29,115 +39,319 @@ #include #include -/* - * The following chains contain the list of interval timers that are +/** + * This chain contains the list of interval timers that are * executed in the context of the Timer Server. - * - * NOTE: These are prototyped in rtems/timer/timer.h but since we - * do not actually use them until after the Timer Server is - * initiated, we can actually declare them here and avoid forcing - * them into the minimum footprint. */ - Chain_Control _Timer_Ticks_chain; + +/** + * This chain contains the list of time of day timers that are + * executed in the context of the Timer Server. + */ Chain_Control _Timer_Seconds_chain; -/* - * These variables keep track of the last time the Timer Server actually - * processed the chain. +/** + * This chain holds the set of timers to be inserted when the + * server runs again. */ +Chain_Control _Timer_To_be_inserted; -Watchdog_Interval _Timer_Server_seconds_last_time; +/** + * This variables keeps track of the last time the Timer Server actually + * processed the ticks chain. + */ Watchdog_Interval _Timer_Server_ticks_last_time; -/* - * The timer used to control when the Timer Server wakes up to service - * "when" timers. +/** + * This variable keeps track of the last time the Timer Server actually + * processed the seconds chain. */ +Watchdog_Interval _Timer_Server_seconds_last_time; +/** + * This is the timer used to control when the Timer Server wakes up to + * service "when" timers. + * + * @note The timer in the Timer Server TCB is used for ticks timer. + */ Watchdog_Control _Timer_Seconds_timer; -/*PAGE +/** + * This method is used to temporarily disable updates to the + * Ticks Timer Chain managed by the Timer Server. + */ +#define _Timer_Server_stop_ticks_timer() \ + _Watchdog_Remove( &_Timer_Server->Timer ) + +/** + * This method is used to temporarily disable updates to the + * Seconds Timer Chain managed by the Timer Server. + */ +#define _Timer_Server_stop_seconds_timer() \ + _Watchdog_Remove( &_Timer_Seconds_timer ); + +/** + * This method resets a timer and places it on the Ticks chain. It + * is assumed that the timer has already been canceled. + */ +#define _Timer_Server_reset_ticks_timer() \ + do { \ + if ( !_Chain_Is_empty( &_Timer_Ticks_chain ) ) { \ + _Watchdog_Insert_ticks( &_Timer_Server->Timer, \ + ((Watchdog_Control *)_Timer_Ticks_chain.first)->delta_interval ); \ + } \ + } while (0) + +/** + * This method resets a timer and places it on the Seconds chain. It + * is assumed that the timer has already been canceled. + */ +#define _Timer_Server_reset_seconds_timer() \ + do { \ + if ( !_Chain_Is_empty( &_Timer_Seconds_chain ) ) { \ + _Watchdog_Insert_seconds( &_Timer_Seconds_timer, \ + ((Watchdog_Control *)_Timer_Seconds_chain.first)->delta_interval ); \ + } \ + } while (0) + +/** + * @brief _Timer_Server_process_insertions + * + * This method processes the set of timers scheduled for insertion + * onto one of the Timer Server chains. + * + * @note It is only to be called from the Timer Server task. + */ +static void _Timer_Server_process_insertions(void) +{ + Timer_Control *the_timer; + + while ( 1 ) { + the_timer = (Timer_Control *) _Chain_Get( &_Timer_To_be_inserted ); + if ( the_timer == NULL ) + break; + + if ( the_timer->the_class == TIMER_INTERVAL_ON_TASK ) { + _Watchdog_Insert( &_Timer_Ticks_chain, &the_timer->Ticker ); + } else if ( the_timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) { + _Watchdog_Insert( &_Timer_Seconds_chain, &the_timer->Ticker ); + } + } +} + +/** + * @brief _Timer_Server_process_ticks_chain + * + * This routine is responsible for adjusting the list of task-based + * interval timers to reflect the passage of time. + * + * @param[in] to_fire will contain the set of timers that are to be fired. + * + * @note It is only to be called from the Timer Server task. + */ +static void _Timer_Server_process_ticks_chain( + Chain_Control *to_fire +) +{ + Watchdog_Interval snapshot; + Watchdog_Interval ticks; + + snapshot = _Watchdog_Ticks_since_boot; + if ( snapshot >= _Timer_Server_ticks_last_time ) + ticks = snapshot - _Timer_Server_ticks_last_time; + else + ticks = (0xFFFFFFFF - _Timer_Server_ticks_last_time) + snapshot; + + _Timer_Server_ticks_last_time = snapshot; + _Watchdog_Adjust_to_chain( &_Timer_Ticks_chain, ticks, to_fire ); +} + +/** + * @brief _Timer_Server_process_seconds_chain * - * _Timer_Server_body + * This routine is responsible for adjusting the list of task-based + * time of day timers to reflect the passage of time. + * + * @param[in] to_fire will contain the set of timers that are to be fired. + * + * @note It is only to be called from the Timer Server task. + */ +static void _Timer_Server_process_seconds_chain( + Chain_Control *to_fire +) +{ + Watchdog_Interval snapshot; + Watchdog_Interval ticks; + + /* + * 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 _Timer_Seconds_chain to indicate this. + */ + snapshot = _TOD_Seconds_since_epoch; + if ( snapshot > _Timer_Server_seconds_last_time ) { + /* + * This path is for normal forward movement and cases where the + * TOD has been set forward. + */ + ticks = snapshot - _Timer_Server_seconds_last_time; + _Watchdog_Adjust_to_chain( &_Timer_Seconds_chain, ticks, to_fire ); + + } else if ( snapshot < _Timer_Server_seconds_last_time ) { + /* + * The current TOD is before the last TOD which indicates that + * TOD has been set backwards. + */ + ticks = _Timer_Server_seconds_last_time - snapshot; + _Watchdog_Adjust( &_Timer_Seconds_chain, WATCHDOG_BACKWARD, ticks ); + } + _Timer_Server_seconds_last_time = snapshot; +} + +/** + * @brief _Timer_Server_body * * This is the server for task based timers. This task executes whenever * a task-based timer should fire. It services both "after" and "when" * timers. It is not created automatically but must be created explicitly * by the application before task-based timers may be initiated. * - * Input parameters: - * Ignored - the task argument is ignored - * - * Output parameters: NONE + * @param[in] ignored is the the task argument that is ignored */ - Thread _Timer_Server_body( uint32_t ignored ) { + Chain_Control to_fire; + + _Chain_Initialize_empty( &to_fire ); + /* * Initialize the "last time" markers to indicate the timer that * the server was initiated. */ - _Timer_Server_ticks_last_time = _Watchdog_Ticks_since_boot; _Timer_Server_seconds_last_time = _TOD_Seconds_since_epoch; + /* + * Insert the timers that were inserted before we got to run. + * This should be done with dispatching disabled. + */ _Thread_Disable_dispatch(); + _Timer_Server_process_insertions(); + _Thread_Enable_dispatch(); + while(1) { /* * Block until there is something to do. */ - + _Thread_Disable_dispatch(); _Thread_Set_state( _Timer_Server, STATES_DELAYING ); _Timer_Server_reset_ticks_timer(); _Timer_Server_reset_seconds_timer(); _Thread_Enable_dispatch(); + /******************************************************************** + ******************************************************************** + **** TIMER SERVER BLOCKS HERE **** + ******************************************************************** + ********************************************************************/ + + /* + * Disable dispatching while processing the timers since we want + * the removal of the timers from the chain to be atomic. + * + * NOTE: Dispatching is disabled for interrupt based TSRs. + * Dispatching is enabled for task based TSRs so they + * can temporarily malloc memory or block. + * _ISR_Nest_level is 0 for task-based TSRs and non-zero + * for the others. + */ + _Thread_Disable_dispatch(); + /* * At this point, at least one of the timers this task relies * upon has fired. Stop them both while we process any outstanding * timers. Before we block, we will restart them. */ + _Timer_Server_stop_ticks_timer(); + _Timer_Server_stop_seconds_timer(); - _Timer_Server_stop_ticks_timer(); - _Timer_Server_stop_seconds_timer(); + /* + * Remove all the timers that need to fire so we can invoke them + * outside the critical section. + */ + _Timer_Server_process_ticks_chain( &to_fire ); + _Timer_Server_process_seconds_chain( &to_fire ); /* - * Disable dispatching while processing the timers since we want - * to mimic the environment that non-task-based TSRs execute in. - * This ensures that the primary difference is that _ISR_Nest_level - * is 0 for task-based timers and non-zero for the others. + * Insert the timers that have been requested to be inserted. */ + _Timer_Server_process_insertions(); - _Thread_Disable_dispatch(); - _Timer_Server_process_ticks_chain(); - _Timer_Server_process_seconds_chain(); + /* + * Enable dispatching to process the set that are ready "to fire." + */ + _Thread_Enable_dispatch(); + + /* + * Now we actually invoke the TSR for all the timers that fired. + * This is done with dispatching + */ + while (1) { + Watchdog_Control *watch; + ISR_Level level; + + _ISR_Disable( level ); + watch = (Watchdog_Control *) _Chain_Get_unprotected( &to_fire ); + if ( watch == NULL ) { + _ISR_Enable( level ); + break; + } + + watch->state = WATCHDOG_INACTIVE; + _ISR_Enable( level ); + + (*watch->routine)( watch->id, watch->user_data ); + } } return 0; /* unreached - only to remove warnings */ } -/*PAGE +/** + * This method schedules the insertion of timers on the proper list. It + * wakes up the Timer Server task to process the insertion. * - * rtems_timer_initiate_server + * @param[in] the_timer is the timer to insert + * + * @note It is highly likely the executing task will be preempted after + * the directive invoking this is executed. + */ +static void _Timer_Server_schedule_operation_method( + Timer_Control *the_timer +) +{ + _Chain_Append( &_Timer_To_be_inserted, &the_timer->Object.Node ); + _Watchdog_Remove( &_Timer_Server->Timer ); + _Thread_Delay_ended( _Timer_Server->Object.id, NULL ); +} + +/** + * @brief rtems_timer_initiate_server * * This directive creates and starts the server for task-based timers. * It must be invoked before any task-based timers can be initiated. * - * Input parameters: - * priority - timer server priority - * stack_size - stack size in bytes - * attribute_set - timer server attributes + * @param[in] priority is the timer server priority + * @param[in] stack_size is the stack size in bytes + * @param[in] attribute_set is the timer server attributes * - * Output parameters: - * RTEMS_SUCCESSFUL - if successful - * error code - if unsuccessful + * @return This method returns RTEMS_SUCCESSFUL if successful and an + * error code otherwise. */ - - rtems_status_code rtems_timer_initiate_server( uint32_t priority, uint32_t stack_size, @@ -151,11 +365,10 @@ rtems_status_code rtems_timer_initiate_server( bool tmpInitialized; /* - * Make sure the requested priority is valid. The if is + * Make sure the requested priority is valid. The if is * structured so we check it is invalid before looking for * a specific invalid value as the default. */ - _priority = priority; if ( !_RTEMS_tasks_Priority_is_valid( priority ) ) { if ( priority != RTEMS_TIMER_SERVER_DEFAULT_PRIORITY ) @@ -166,7 +379,6 @@ rtems_status_code rtems_timer_initiate_server( /* * Just to make sure this is only called once. */ - _Thread_Disable_dispatch(); tmpInitialized = initialized; initialized = true; @@ -175,6 +387,11 @@ rtems_status_code rtems_timer_initiate_server( if ( tmpInitialized ) return RTEMS_INCORRECT_STATE; + /* + * Initialize the set of timers to be inserted by the server. + */ + _Chain_Initialize_empty( &_Timer_To_be_inserted ); + /* * Create the Timer Server with the name the name of "TIME". The attribute * RTEMS_SYSTEM_TASK allows us to set a priority to 0 which will makes it @@ -189,7 +406,6 @@ rtems_status_code rtems_timer_initiate_server( * Otherwise, the priority ceiling for the mutex used to protect the * GNAT run-time is violated. */ - status = rtems_task_create( _Objects_Build_name('T','I','M','E'), /* "TIME" */ _priority, /* create with priority 1 since 0 is illegal */ @@ -217,7 +433,6 @@ rtems_status_code rtems_timer_initiate_server( * NOTE: Setting the pointer to the Timer Server TCB to a value other than * NULL indicates that task-based timer support is initialized. */ - _Timer_Server = (Thread_Control *)_Objects_Get_local_object( &_RTEMS_tasks_Information, _Objects_Get_index(id) @@ -226,7 +441,6 @@ rtems_status_code rtems_timer_initiate_server( /* * Initialize the timer lists that the server will manage. */ - _Chain_Initialize_empty( &_Timer_Ticks_chain ); _Chain_Initialize_empty( &_Timer_Seconds_chain ); @@ -234,13 +448,18 @@ rtems_status_code rtems_timer_initiate_server( * Initialize the timers that will be used to control when the * Timer Server wakes up and services the task-based timers. */ - _Watchdog_Initialize( &_Timer_Server->Timer, _Thread_Delay_ended, id, NULL ); _Watchdog_Initialize( &_Timer_Seconds_timer, _Thread_Delay_ended, id, NULL ); + /* - * Start the timer server + * Initialize the pointer to the timer reset method so applications + * that do not use the Timer Server do not have to pull it in. */ + _Timer_Server_schedule_operation = _Timer_Server_schedule_operation_method; + /* + * Start the timer server + */ status = rtems_task_start( id, /* the id from create */ (rtems_task_entry) _Timer_Server_body, /* the timer server entry point */ @@ -259,75 +478,3 @@ rtems_status_code rtems_timer_initiate_server( return status; } - -/*PAGE - * - * _Timer_Server_process_ticks_chain - * - * This routine is responsible for adjusting the list of task-based - * interval timers to reflect the passage of time. - * - * Input parameters: NONE - * - * Output parameters: NONE - */ - -void _Timer_Server_process_ticks_chain(void) -{ - Watchdog_Interval snapshot; - Watchdog_Interval ticks; - - snapshot = _Watchdog_Ticks_since_boot; - if ( snapshot >= _Timer_Server_ticks_last_time ) - ticks = snapshot - _Timer_Server_ticks_last_time; - else - ticks = (0xFFFFFFFF - _Timer_Server_ticks_last_time) + snapshot; - - _Timer_Server_ticks_last_time = snapshot; - _Watchdog_Adjust( &_Timer_Ticks_chain, WATCHDOG_FORWARD, ticks ); -} - -/*PAGE - * - * _Timer_Server_process_seconds_chain - * - * This routine is responsible for adjusting the list of task-based - * time of day timers to reflect the passage of time. - * - * Input parameters: NONE - * - * Output parameters: NONE - */ - -void _Timer_Server_process_seconds_chain(void) -{ - Watchdog_Interval snapshot; - Watchdog_Interval ticks; - - /* - * 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 _Timer_Seconds_chain to indicate this. - */ - - snapshot = _TOD_Seconds_since_epoch; - if ( snapshot > _Timer_Server_seconds_last_time ) { - /* - * This path is for normal forward movement and cases where the - * TOD has been set forward. - */ - - ticks = snapshot - _Timer_Server_seconds_last_time; - _Watchdog_Adjust( &_Timer_Seconds_chain, WATCHDOG_FORWARD, ticks ); - - } else if ( snapshot < _Timer_Server_seconds_last_time ) { - /* - * The current TOD is before the last TOD which indicates that - * TOD has been set backwards. - */ - - ticks = _Timer_Server_seconds_last_time - snapshot; - _Watchdog_Adjust( &_Timer_Seconds_chain, WATCHDOG_BACKWARD, ticks ); - } - _Timer_Server_seconds_last_time = snapshot; -} diff --git a/cpukit/rtems/src/timerserverfireafter.c b/cpukit/rtems/src/timerserverfireafter.c index 568f53be1e..d23edee60c 100644 --- a/cpukit/rtems/src/timerserverfireafter.c +++ b/cpukit/rtems/src/timerserverfireafter.c @@ -92,10 +92,12 @@ rtems_status_code rtems_timer_server_fire_after( the_timer->Ticker.initial = ticks; _ISR_Enable( level ); - _Timer_Server_stop_ticks_timer(); - _Timer_Server_process_ticks_chain(); - _Watchdog_Insert( &_Timer_Ticks_chain, &the_timer->Ticker ); - _Timer_Server_reset_ticks_timer(); + /* + * _Timer_Server_schedule_operation != NULL because we checked that + * _Timer_Server was != NULL above. Both are set at the same time. + */ + + (*_Timer_Server_schedule_operation)( the_timer ); _Thread_Enable_dispatch(); return RTEMS_SUCCESSFUL; diff --git a/cpukit/rtems/src/timerserverfirewhen.c b/cpukit/rtems/src/timerserverfirewhen.c index cece25e926..a1f2caee6f 100644 --- a/cpukit/rtems/src/timerserverfirewhen.c +++ b/cpukit/rtems/src/timerserverfirewhen.c @@ -79,10 +79,12 @@ rtems_status_code rtems_timer_server_fire_when( _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data ); the_timer->Ticker.initial = seconds - _TOD_Seconds_since_epoch; - _Timer_Server_stop_seconds_timer(); - _Timer_Server_process_seconds_chain(); - _Watchdog_Insert( &_Timer_Seconds_chain, &the_timer->Ticker ); - _Timer_Server_reset_seconds_timer(); + /* + * _Timer_Server_schedule_operation != NULL because we checked that + * _Timer_Server was != NULL above. Both are set at the same time. + */ + + (*_Timer_Server_schedule_operation)( the_timer ); _Thread_Enable_dispatch(); return RTEMS_SUCCESSFUL; diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index 0ea422fce6..ab38b23237 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -173,8 +173,8 @@ 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/watchdoginsert.c src/watchdogremove.c src/watchdogtickle.c \ - src/watchdogreport.c src/watchdogreportchain.c + src/watchdogadjusttochain.c src/watchdoginsert.c src/watchdogremove.c \ + src/watchdogtickle.c src/watchdogreport.c src/watchdogreportchain.c ## USEREXT_C_FILES libscore_a_SOURCES += src/userextaddapiset.c src/userextaddset.c \ diff --git a/cpukit/score/include/rtems/score/watchdog.h b/cpukit/score/include/rtems/score/watchdog.h index 5cc1498d5b..f542a51fae 100644 --- a/cpukit/score/include/rtems/score/watchdog.h +++ b/cpukit/score/include/rtems/score/watchdog.h @@ -220,6 +220,25 @@ void _Watchdog_Adjust ( Watchdog_Interval units ); +/** @brief Watchdog Adjust to Chain + * + * This routine adjusts the @a header watchdog chain in the forward + * @a direction for @a units_arg ticks. + * + * @param[in] header is the watchdog chain to adjust + * @param[in] units 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. + * + * @note This always adjusts forward. + */ +void _Watchdog_Adjust_to_chain( + Chain_Control *header, + Watchdog_Interval units_arg, + Chain_Control *to_fire + +); + /** @brief Watchdog Insert * * This routine inserts @a the_watchdog into the @a header watchdog chain diff --git a/cpukit/score/src/watchdogadjusttochain.c b/cpukit/score/src/watchdogadjusttochain.c new file mode 100644 index 0000000000..5a03208ee0 --- /dev/null +++ b/cpukit/score/src/watchdogadjusttochain.c @@ -0,0 +1,67 @@ +/** + * @file watchdogadjusttochain.c + * + * This is used by the Timer Server task. + */ + +/* COPYRIGHT (c) 1989-2008. + * 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.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +void _Watchdog_Adjust_to_chain( + Chain_Control *header, + Watchdog_Interval units_arg, + Chain_Control *to_fire + +) +{ + Watchdog_Interval units = units_arg; + ISR_Level level; + Chain_Node *node; + + if ( !units ) { + return; + } + _ISR_Disable( level ); + + if ( !_Chain_Is_empty( header ) ) { + while ( units ) { + if ( units < _Watchdog_First( header )->delta_interval ) { + _Watchdog_First( header )->delta_interval -= units; + break; + } else { + units -= _Watchdog_First( header )->delta_interval; + _Watchdog_First( header )->delta_interval = 0; + + do { + node = _Chain_Get_unprotected( header ); + _Chain_Append_unprotected( to_fire, node ); + + _ISR_Flash( level ); + + } while ( !_Chain_Is_empty( header ) && + _Watchdog_First( header )->delta_interval == 0 ); + + if ( _Chain_Is_empty( header ) ) + break; + } + } + + } + _ISR_Enable( level ); +} + -- cgit v1.2.3