From 03b900d3ed120ea919ea3eded7edbece3488cff3 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 18 Feb 2016 08:36:26 +0100 Subject: score: Replace watchdog handler implementation Use a red-black tree instead of delta chains. Close #2344. Update #2554. Update #2555. Close #2606. --- cpukit/rtems/include/rtems/rtems/ratemonimpl.h | 24 +- cpukit/rtems/include/rtems/rtems/timer.h | 59 +++- cpukit/rtems/include/rtems/rtems/timerimpl.h | 216 +++++++------- cpukit/rtems/src/eventseize.c | 11 +- cpukit/rtems/src/eventsurrender.c | 2 +- cpukit/rtems/src/ratemoncancel.c | 5 +- cpukit/rtems/src/ratemoncreate.c | 3 +- cpukit/rtems/src/ratemondelete.c | 5 +- cpukit/rtems/src/ratemonperiod.c | 38 ++- cpukit/rtems/src/ratemontimeout.c | 50 ++-- cpukit/rtems/src/taskwakeafter.c | 9 +- cpukit/rtems/src/taskwakewhen.c | 18 +- cpukit/rtems/src/timercancel.c | 31 +- cpukit/rtems/src/timercreate.c | 179 +++++++++-- cpukit/rtems/src/timerdelete.c | 14 +- cpukit/rtems/src/timerfireafter.c | 64 +--- cpukit/rtems/src/timerfirewhen.c | 50 +--- cpukit/rtems/src/timergetinfo.c | 13 +- cpukit/rtems/src/timerreset.c | 41 +-- cpukit/rtems/src/timerserver.c | 394 ++++++------------------- cpukit/rtems/src/timerserverfireafter.c | 68 +---- cpukit/rtems/src/timerserverfirewhen.c | 70 +---- 22 files changed, 544 insertions(+), 820 deletions(-) (limited to 'cpukit/rtems') diff --git a/cpukit/rtems/include/rtems/rtems/ratemonimpl.h b/cpukit/rtems/include/rtems/rtems/ratemonimpl.h index 490912eb21..f184c44ba9 100644 --- a/cpukit/rtems/include/rtems/rtems/ratemonimpl.h +++ b/cpukit/rtems/include/rtems/rtems/ratemonimpl.h @@ -129,19 +129,13 @@ RTEMS_INLINE_ROUTINE bool _Rate_monotonic_Is_expired ( /** * @brief Rate Monotonic Timeout * - * This routine is invoked when the period represented - * by ID expires. If the thread which owns this period is blocked - * waiting for the period to expire, then it is readied and the - * period is restarted. If the owning thread is not waiting for the - * period to expire, then the period is placed in the EXPIRED - * state and not restarted. - * - * @param[in] id is the period id - */ -void _Rate_monotonic_Timeout( - rtems_id id, - void *ignored -); + * This routine is invoked when the period represented by the watchdog expires. + * If the thread which owns this period is blocked waiting for the period to + * expire, then it is readied and the period is restarted. If the owning thread + * is not waiting for the period to expire, then the period is placed in the + * EXPIRED state and not restarted. + */ +void _Rate_monotonic_Timeout( Watchdog_Control *watchdog ); /** * @brief _Rate_monotonic_Get_status( @@ -165,7 +159,7 @@ bool _Rate_monotonic_Get_status( ); /** - * @brief Initiate Rate Monotonic Statistics + * @brief Restart Rate Monotonic Period * * This routine is invoked when a period is initiated via an explicit * call to rtems_rate_monotonic_period for the period's first iteration @@ -173,7 +167,7 @@ bool _Rate_monotonic_Get_status( * * @param[in] the_period points to the period being operated upon. */ -void _Rate_monotonic_Initiate_statistics( +void _Rate_monotonic_Restart( Rate_monotonic_Control *the_period ); diff --git a/cpukit/rtems/include/rtems/rtems/timer.h b/cpukit/rtems/include/rtems/rtems/timer.h index 7cc90511ca..032c49525a 100644 --- a/cpukit/rtems/include/rtems/rtems/timer.h +++ b/cpukit/rtems/include/rtems/rtems/timer.h @@ -31,7 +31,7 @@ * COPYRIGHT (c) 1989-2011. * On-Line Applications Research Corporation (OAR). * - * Copyright (c) 2009 embedded brains GmbH. + * Copyright (c) 2009, 2016 embedded brains GmbH. * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -43,6 +43,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -63,39 +64,49 @@ extern "C" { */ /**@{*/ +#define TIMER_CLASS_BIT_TIME_OF_DAY 0x1 + +#define TIMER_CLASS_BIT_ON_TASK 0x2 + +#define TIMER_CLASS_BIT_NOT_DORMANT 0x4 + /** * The following enumerated type details the classes to which a timer * may belong. */ typedef enum { + /** + * This value indicates the timer is currently not in use. + */ + TIMER_DORMANT, + /** * This value indicates the timer is currently in use as an interval * timer which will fire in the clock tick ISR. */ - TIMER_INTERVAL, + TIMER_INTERVAL = TIMER_CLASS_BIT_NOT_DORMANT, /** * This value indicates the timer is currently in use as an interval * timer which will fire in the timer server task. */ - TIMER_INTERVAL_ON_TASK, + TIMER_INTERVAL_ON_TASK = + TIMER_CLASS_BIT_NOT_DORMANT | TIMER_CLASS_BIT_ON_TASK, /** * This value indicates the timer is currently in use as an time of day * timer which will fire in the clock tick ISR. */ - TIMER_TIME_OF_DAY, + TIMER_TIME_OF_DAY = + TIMER_CLASS_BIT_NOT_DORMANT | TIMER_CLASS_BIT_TIME_OF_DAY, /** * This value indicates the timer is currently in use as an time of day * timer which will fire in the timer server task. */ - TIMER_TIME_OF_DAY_ON_TASK, - - /** - * This value indicates the timer is currently not in use. - */ - TIMER_DORMANT + TIMER_TIME_OF_DAY_ON_TASK = + TIMER_CLASS_BIT_NOT_DORMANT | TIMER_CLASS_BIT_TIME_OF_DAY | + TIMER_CLASS_BIT_ON_TASK } Timer_Classes; /** @@ -124,6 +135,16 @@ typedef struct { Watchdog_Control Ticker; /** This field indicates what type of timer this currently is. */ Timer_Classes the_class; + /** This field is the timer service routine. */ + rtems_timer_service_routine_entry routine; + /** This field is the timer service routine user data. */ + void *user_data; + /** This field is the timer interval in ticks or seconds. */ + Watchdog_Interval initial; + /** This field is the timer start time point in ticks. */ + Watchdog_Interval start_time; + /** This field is the timer stop time point in ticks. */ + Watchdog_Interval stop_time; } Timer_Control; /** @@ -296,16 +317,22 @@ rtems_status_code rtems_timer_reset( ); /** - * @brief rtems_timer_initiate_server + * @brief Initiates the timer server. * - * This routine implements the rtems_timer_initiate_server directive. - * It creates and starts the server that executes task-based timers. + * This directive creates and starts the server for task-based timers. * It must be invoked before any task-based timers can be initiated. + * + * @param priority The timer server task priority. + * @param stack_size The stack size in bytes for the timer server task. + * @param attribute_set The timer server task attributes. + * + * @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, - rtems_attribute attribute_set + rtems_task_priority priority, + size_t stack_size, + rtems_attribute attribute_set ); /** diff --git a/cpukit/rtems/include/rtems/rtems/timerimpl.h b/cpukit/rtems/include/rtems/rtems/timerimpl.h index 55be6343c3..e4b4ca2ec4 100644 --- a/cpukit/rtems/include/rtems/rtems/timerimpl.h +++ b/cpukit/rtems/include/rtems/rtems/timerimpl.h @@ -10,6 +10,8 @@ * COPYRIGHT (c) 1989-2011. * On-Line Applications Research Corporation (OAR). * + * Copyright (c) 2016 embedded brains GmbH. + * * 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. @@ -35,81 +37,13 @@ extern "C" { * @{ */ -typedef struct Timer_server_Control Timer_server_Control; +typedef struct Timer_server_Control { + ISR_LOCK_MEMBER( Lock ) -/** - * @brief Method used for task based timers. - */ -typedef void (*Timer_server_Method)( - Timer_server_Control *timer_server, - Timer_Control *timer -); + Chain_Control Pending; -typedef struct { - /** - * @brief This watchdog that will be registered in the system tick mechanic - * for timer server wake-up. - */ - 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 time snapshot of the timer server. - * - * The units may be ticks or seconds. - */ - Watchdog_Interval last_snapshot; - - /** - * @brief Current time snapshot of the timer server. - * - * The units may be ticks or seconds. - */ - Watchdog_Interval current_snapshot; -} Timer_server_Watchdogs; - -struct Timer_server_Control { - /** - * @brief The cancel method of the timer server. - */ - Timer_server_Method cancel; - - /** - * @brief The schedule operation method of the timer server. - */ - Timer_server_Method schedule_operation; - - /** - * @brief Interval watchdogs triggered by the timer server. - */ - Timer_server_Watchdogs Interval_watchdogs; - - /** - * @brief TOD watchdogs triggered by the timer server. - */ - Timer_server_Watchdogs TOD_watchdogs; -}; + Objects_Id server_id; +} Timer_server_Control; /** * @brief Pointer to default timer server control block. @@ -148,64 +82,124 @@ RTEMS_INLINE_ROUTINE void _Timer_Free ( _Objects_Free( &_Timer_Information, &the_timer->Object ); } -/** - * @brief Timer_Get - * - * This function maps timer IDs to timer control blocks. - * If ID corresponds to a local timer, then it returns - * the timer control pointer which maps to ID and location - * is set to OBJECTS_LOCAL. Otherwise, location is set - * to OBJECTS_ERROR and the returned value is undefined. - */ -RTEMS_INLINE_ROUTINE Timer_Control *_Timer_Get ( +RTEMS_INLINE_ROUTINE Timer_Control *_Timer_Get( Objects_Id id, - Objects_Locations *location + Objects_Locations *location, + ISR_lock_Context *lock_context ) { - return (Timer_Control *) - _Objects_Get( &_Timer_Information, id, location ); + return (Timer_Control *) _Objects_Get_isr_disable( + &_Timer_Information, + id, + location, + lock_context + ); } -/** - * @brief Timer_Is_interval_class - * - * This function returns TRUE if the class is that of an INTERVAL - * timer, and FALSE otherwise. - */ -RTEMS_INLINE_ROUTINE bool _Timer_Is_interval_class ( +RTEMS_INLINE_ROUTINE Per_CPU_Control *_Timer_Acquire_critical( + Timer_Control *the_timer, + ISR_lock_Context *lock_context +) +{ + Per_CPU_Control *cpu; + + cpu = _Watchdog_Get_CPU( &the_timer->Ticker ); + _Watchdog_Per_CPU_acquire_critical( cpu, lock_context ); + + return cpu; +} + +RTEMS_INLINE_ROUTINE void _Timer_Release( + Per_CPU_Control *cpu, + ISR_lock_Context *lock_context +) +{ + _Watchdog_Per_CPU_release_critical( cpu, lock_context ); + _ISR_lock_ISR_enable( lock_context ); +} + +RTEMS_INLINE_ROUTINE bool _Timer_Is_interval_class( Timer_Classes the_class ) { - return (the_class == TIMER_INTERVAL) || (the_class == TIMER_INTERVAL_ON_TASK); + Timer_Classes mask = + TIMER_CLASS_BIT_NOT_DORMANT | TIMER_CLASS_BIT_TIME_OF_DAY; + + return ( the_class & mask ) == TIMER_CLASS_BIT_NOT_DORMANT; } -/** - * @brief Timer_Is_time_of_day_class - * - * This function returns TRUE if the class is that of an INTERVAL - * timer, and FALSE otherwise. - */ -RTEMS_INLINE_ROUTINE bool _Timer_Is_timer_of_day_class ( +RTEMS_INLINE_ROUTINE bool _Timer_Is_on_task_class( Timer_Classes the_class ) { - return ( the_class == TIMER_TIME_OF_DAY ); + Timer_Classes mask = + TIMER_CLASS_BIT_NOT_DORMANT | TIMER_CLASS_BIT_ON_TASK; + + return ( the_class & mask ) == mask; } -/** - * @brief Timer_Is_dormant_class - * - * This function returns TRUE if the class is that of a DORMANT - * timer, and FALSE otherwise. - */ -RTEMS_INLINE_ROUTINE bool _Timer_Is_dormant_class ( +RTEMS_INLINE_ROUTINE Per_CPU_Watchdog_index _Timer_Watchdog_header_index( Timer_Classes the_class ) { - return ( the_class == TIMER_DORMANT ); + return ( the_class & TIMER_CLASS_BIT_TIME_OF_DAY ); +} + +RTEMS_INLINE_ROUTINE Watchdog_Interval _Timer_Get_CPU_ticks( + const Per_CPU_Control *cpu +) +{ + return (Watchdog_Interval) cpu->Watchdog.ticks; } -void _Timer_Cancel( Timer_Control *the_timer ); +rtems_status_code _Timer_Fire( + rtems_id id, + rtems_interval interval, + rtems_timer_service_routine_entry routine, + void *user_data, + Timer_Classes the_class, + Watchdog_Service_routine_entry adaptor +); + +rtems_status_code _Timer_Fire_after( + rtems_id id, + rtems_interval ticks, + rtems_timer_service_routine_entry routine, + void *user_data, + Timer_Classes the_class, + Watchdog_Service_routine_entry adaptor +); + +rtems_status_code _Timer_Fire_when( + rtems_id id, + const rtems_time_of_day *wall_time, + rtems_timer_service_routine_entry routine, + void *user_data, + Timer_Classes the_class, + Watchdog_Service_routine_entry adaptor +); + +void _Timer_Cancel( Per_CPU_Control *cpu, Timer_Control *the_timer ); + +void _Timer_Routine_adaptor( Watchdog_Control *the_watchdog ); + +void _Timer_server_Routine_adaptor( Watchdog_Control *the_watchdog ); + +RTEMS_INLINE_ROUTINE void _Timer_server_Acquire_critical( + Timer_server_Control *timer_server, + ISR_lock_Context *lock_context +) +{ + _ISR_lock_Acquire( &timer_server->Lock, lock_context ); +} + +RTEMS_INLINE_ROUTINE void _Timer_server_Release_critical( + Timer_server_Control *timer_server, + ISR_lock_Context *lock_context +) +{ + _ISR_lock_Release( &timer_server->Lock, lock_context ); +} /**@}*/ diff --git a/cpukit/rtems/src/eventseize.c b/cpukit/rtems/src/eventseize.c index 3dc554f61b..0be6bd6f45 100644 --- a/cpukit/rtems/src/eventseize.c +++ b/cpukit/rtems/src/eventseize.c @@ -90,13 +90,12 @@ void _Event_Seize( if ( ticks ) { _Thread_Wait_set_timeout_code( executing, RTEMS_TIMEOUT ); - _Watchdog_Initialize( - &executing->Timer, + _Thread_Timer_insert_relative( + executing, + cpu_self, _Thread_Timeout, - 0, - executing + ticks ); - _Watchdog_Insert_ticks( &executing->Timer, ticks ); } _Thread_Set_state( executing, block_state ); @@ -113,7 +112,7 @@ void _Event_Seize( wait_class | THREAD_WAIT_STATE_BLOCKED ); if ( !success ) { - _Watchdog_Remove_ticks( &executing->Timer ); + _Thread_Timer_remove( executing ); _Thread_Unblock( executing ); } diff --git a/cpukit/rtems/src/eventsurrender.c b/cpukit/rtems/src/eventsurrender.c index 5726cc8d9d..7c4fe2e3f0 100644 --- a/cpukit/rtems/src/eventsurrender.c +++ b/cpukit/rtems/src/eventsurrender.c @@ -121,7 +121,7 @@ void _Event_Surrender( cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _Thread_Lock_release_default( the_thread, lock_context ); - _Watchdog_Remove_ticks( &the_thread->Timer ); + _Thread_Timer_remove( the_thread ); _Thread_Unblock( the_thread ); _Thread_Dispatch_enable( cpu_self ); diff --git a/cpukit/rtems/src/ratemoncancel.c b/cpukit/rtems/src/ratemoncancel.c index 67b230fbfc..2e4d5322db 100644 --- a/cpukit/rtems/src/ratemoncancel.c +++ b/cpukit/rtems/src/ratemoncancel.c @@ -29,6 +29,7 @@ rtems_status_code rtems_rate_monotonic_cancel( { Rate_monotonic_Control *the_period; Objects_Locations location; + ISR_Level level; the_period = _Rate_monotonic_Get( id, &location ); switch ( location ) { @@ -38,7 +39,9 @@ rtems_status_code rtems_rate_monotonic_cancel( _Objects_Put( &the_period->Object ); return RTEMS_NOT_OWNER_OF_RESOURCE; } - _Watchdog_Remove_ticks( &the_period->Timer ); + _ISR_Disable( level ); + _Watchdog_Per_CPU_remove_relative( &the_period->Timer ); + _ISR_Enable( level ); the_period->state = RATE_MONOTONIC_INACTIVE; _Scheduler_Release_job( the_period->owner, 0 ); _Objects_Put( &the_period->Object ); diff --git a/cpukit/rtems/src/ratemoncreate.c b/cpukit/rtems/src/ratemoncreate.c index 1ac4a36b6e..1a5c9b2615 100644 --- a/cpukit/rtems/src/ratemoncreate.c +++ b/cpukit/rtems/src/ratemoncreate.c @@ -65,7 +65,8 @@ rtems_status_code rtems_rate_monotonic_create( the_period->owner = _Thread_Get_executing(); the_period->state = RATE_MONOTONIC_INACTIVE; - _Watchdog_Preinitialize( &the_period->Timer ); + _Watchdog_Preinitialize( &the_period->Timer, _Per_CPU_Get_by_index( 0 ) ); + _Watchdog_Initialize( &the_period->Timer, _Rate_monotonic_Timeout ); _Rate_monotonic_Reset_statistics( the_period ); diff --git a/cpukit/rtems/src/ratemondelete.c b/cpukit/rtems/src/ratemondelete.c index 77cf3fe306..09b9ab6712 100644 --- a/cpukit/rtems/src/ratemondelete.c +++ b/cpukit/rtems/src/ratemondelete.c @@ -29,6 +29,7 @@ rtems_status_code rtems_rate_monotonic_delete( { Rate_monotonic_Control *the_period; Objects_Locations location; + ISR_Level level; _Objects_Allocator_lock(); the_period = _Rate_monotonic_Get( id, &location ); @@ -37,7 +38,9 @@ rtems_status_code rtems_rate_monotonic_delete( case OBJECTS_LOCAL: _Scheduler_Release_job( the_period->owner, 0 ); _Objects_Close( &_Rate_monotonic_Information, &the_period->Object ); - _Watchdog_Remove_ticks( &the_period->Timer ); + _ISR_Disable( level ); + _Watchdog_Per_CPU_remove_relative( &the_period->Timer ); + _ISR_Enable( level ); the_period->state = RATE_MONOTONIC_INACTIVE; _Objects_Put( &the_period->Object ); _Rate_monotonic_Free( the_period ); diff --git a/cpukit/rtems/src/ratemonperiod.c b/cpukit/rtems/src/ratemonperiod.c index 6afe1016bf..58be148f19 100644 --- a/cpukit/rtems/src/ratemonperiod.c +++ b/cpukit/rtems/src/ratemonperiod.c @@ -77,12 +77,11 @@ bool _Rate_monotonic_Get_status( return true; } -void _Rate_monotonic_Initiate_statistics( - Rate_monotonic_Control *the_period -) +void _Rate_monotonic_Restart( Rate_monotonic_Control *the_period ) { Thread_Control *owning_thread = the_period->owner; Timestamp_Control uptime; + ISR_Level level; _TOD_Get_uptime( &uptime ); @@ -113,7 +112,15 @@ void _Rate_monotonic_Initiate_statistics( _Timestamp_Add_to( &the_period->cpu_usage_period_initiated, &ran ); } - _Scheduler_Release_job( the_period->owner, the_period->next_length ); + _Scheduler_Release_job( owning_thread, the_period->next_length ); + + _ISR_Disable( level ); + _Watchdog_Per_CPU_insert_relative( + &the_period->Timer, + _Per_CPU_Get(), + the_period->next_length + ); + _ISR_Enable( level ); } static void _Rate_monotonic_Update_statistics( @@ -238,22 +245,9 @@ rtems_status_code rtems_rate_monotonic_period( if ( the_period->state == RATE_MONOTONIC_INACTIVE ) { _ISR_Enable( level ); - the_period->next_length = length; - - /* - * Baseline statistics information for the beginning of a period. - */ - _Rate_monotonic_Initiate_statistics( the_period ); - the_period->state = RATE_MONOTONIC_ACTIVE; - _Watchdog_Initialize( - &the_period->Timer, - _Rate_monotonic_Timeout, - id, - NULL - ); - - _Watchdog_Insert_ticks( &the_period->Timer, length ); + the_period->next_length = length; + _Rate_monotonic_Restart( the_period ); _Objects_Put( &the_period->Object ); return RTEMS_SUCCESSFUL; } @@ -308,7 +302,11 @@ rtems_status_code rtems_rate_monotonic_period( the_period->state = RATE_MONOTONIC_ACTIVE; the_period->next_length = length; - _Watchdog_Insert_ticks( &the_period->Timer, length ); + _Watchdog_Per_CPU_insert_relative( + &the_period->Timer, + _Per_CPU_Get(), + length + ); _Scheduler_Release_job( the_period->owner, the_period->next_length ); _Objects_Put( &the_period->Object ); return RTEMS_TIMEOUT; diff --git a/cpukit/rtems/src/ratemontimeout.c b/cpukit/rtems/src/ratemontimeout.c index 08f9bd17d7..7c25595a16 100644 --- a/cpukit/rtems/src/ratemontimeout.c +++ b/cpukit/rtems/src/ratemontimeout.c @@ -22,46 +22,30 @@ #include #include -void _Rate_monotonic_Timeout( - Objects_Id id, - void *ignored -) +void _Rate_monotonic_Timeout( Watchdog_Control *watchdog ) { Rate_monotonic_Control *the_period; - Objects_Locations location; Thread_Control *the_thread; /* * When we get here, the Timer is already off the chain so we do not * have to worry about that -- hence no _Watchdog_Remove(). */ - the_period = _Rate_monotonic_Get( id, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - the_thread = the_period->owner; - if ( _States_Is_waiting_for_period( the_thread->current_state ) && - the_thread->Wait.id == the_period->Object.id ) { - _Thread_Unblock( the_thread ); - - _Rate_monotonic_Initiate_statistics( the_period ); - - _Watchdog_Insert_ticks( &the_period->Timer, the_period->next_length ); - } else if ( the_period->state == RATE_MONOTONIC_OWNER_IS_BLOCKING ) { - the_period->state = RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING; - - _Rate_monotonic_Initiate_statistics( the_period ); - - _Watchdog_Insert_ticks( &the_period->Timer, the_period->next_length ); - } else - the_period->state = RATE_MONOTONIC_EXPIRED; - _Objects_Put_without_thread_dispatch( &the_period->Object ); - break; - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* impossible */ -#endif - case OBJECTS_ERROR: - break; + the_period = RTEMS_CONTAINER_OF( watchdog, Rate_monotonic_Control, Timer ); + the_thread = the_period->owner; + + _Thread_Disable_dispatch(); + + if ( _States_Is_waiting_for_period( the_thread->current_state ) && + the_thread->Wait.id == the_period->Object.id ) { + _Thread_Unblock( the_thread ); + _Rate_monotonic_Restart( the_period ); + } else if ( the_period->state == RATE_MONOTONIC_OWNER_IS_BLOCKING ) { + the_period->state = RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING; + _Rate_monotonic_Restart( the_period ); + } else { + the_period->state = RATE_MONOTONIC_EXPIRED; } + + _Thread_Unnest_dispatch(); } diff --git a/cpukit/rtems/src/taskwakeafter.c b/cpukit/rtems/src/taskwakeafter.c index b7f328f5bc..fa5f6f4eed 100644 --- a/cpukit/rtems/src/taskwakeafter.c +++ b/cpukit/rtems/src/taskwakeafter.c @@ -41,13 +41,12 @@ rtems_status_code rtems_task_wake_after( } else { _Thread_Set_state( executing, STATES_DELAYING ); _Thread_Wait_flags_set( executing, THREAD_WAIT_STATE_BLOCKED ); - _Watchdog_Initialize( - &executing->Timer, + _Thread_Timer_insert_relative( + executing, + cpu_self, _Thread_Timeout, - 0, - executing + ticks ); - _Watchdog_Insert_ticks( &executing->Timer, ticks ); } _Thread_Dispatch_enable( cpu_self ); return RTEMS_SUCCESSFUL; diff --git a/cpukit/rtems/src/taskwakewhen.c b/cpukit/rtems/src/taskwakewhen.c index cf0b303cd3..5d6d45afcf 100644 --- a/cpukit/rtems/src/taskwakewhen.c +++ b/cpukit/rtems/src/taskwakewhen.c @@ -28,9 +28,9 @@ rtems_status_code rtems_task_wake_when( rtems_time_of_day *time_buffer ) { - Watchdog_Interval seconds; - Thread_Control *executing; - Per_CPU_Control *cpu_self; + uint32_t seconds; + Thread_Control *executing; + Per_CPU_Control *cpu_self; if ( !_TOD_Is_set() ) return RTEMS_NOT_DEFINED; @@ -52,15 +52,11 @@ rtems_status_code rtems_task_wake_when( executing = _Thread_Executing; _Thread_Set_state( executing, STATES_WAITING_FOR_TIME ); _Thread_Wait_flags_set( executing, THREAD_WAIT_STATE_BLOCKED ); - _Watchdog_Initialize( - &executing->Timer, + _Thread_Timer_insert_absolute( + executing, + cpu_self, _Thread_Timeout, - 0, - executing - ); - _Watchdog_Insert_seconds( - &executing->Timer, - seconds - _TOD_Seconds_since_epoch() + _Watchdog_Ticks_from_seconds( seconds ) ); _Thread_Dispatch_enable( cpu_self ); return RTEMS_SUCCESSFUL; diff --git a/cpukit/rtems/src/timercancel.c b/cpukit/rtems/src/timercancel.c index 1e737a25bb..5d4343e776 100644 --- a/cpukit/rtems/src/timercancel.c +++ b/cpukit/rtems/src/timercancel.c @@ -14,39 +14,24 @@ #include "config.h" #endif -#include -#include -#include -#include #include -#include - -/* - * rtems_timer_cancel - * - * This directive allows a thread to cancel a timer. - * - * Input parameters: - * id - timer id - * - * Output parameters: - * RTEMS_SUCCESSFUL - if successful - * error code - if unsuccessful - */ rtems_status_code rtems_timer_cancel( rtems_id id ) { - Timer_Control *the_timer; - Objects_Locations location; + Timer_Control *the_timer; + Objects_Locations location; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; - the_timer = _Timer_Get( id, &location ); + the_timer = _Timer_Get( id, &location, &lock_context ); switch ( location ) { case OBJECTS_LOCAL: - _Timer_Cancel( the_timer ); - _Objects_Put( &the_timer->Object ); + cpu = _Timer_Acquire_critical( the_timer, &lock_context ); + _Timer_Cancel( cpu, the_timer ); + _Timer_Release( cpu, &lock_context ); return RTEMS_SUCCESSFUL; #if defined(RTEMS_MULTIPROCESSING) diff --git a/cpukit/rtems/src/timercreate.c b/cpukit/rtems/src/timercreate.c index 5c718b94c9..80c1356278 100644 --- a/cpukit/rtems/src/timercreate.c +++ b/cpukit/rtems/src/timercreate.c @@ -18,40 +18,173 @@ #include "config.h" #endif -#include +#include +#include #include #include #include +#include #include -#include +#include #include -void _Timer_Cancel( Timer_Control *the_timer ) +RTEMS_STATIC_ASSERT( + PER_CPU_WATCHDOG_ABSOLUTE == TIMER_CLASS_BIT_TIME_OF_DAY, + TIMER_CLASS_BIT_TIME_OF_DAY +); + +void _Timer_Routine_adaptor( Watchdog_Control *the_watchdog ) { - Timer_server_Control *timer_server; - ISR_Level level; + Timer_Control *the_timer; + Per_CPU_Control *cpu; - /* The timer class must not change during the cancel operation */ - _ISR_Disable( level ); + the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker ); + cpu = _Watchdog_Get_CPU( &the_timer->Ticker ); + the_timer->stop_time = _Timer_Get_CPU_ticks( cpu ); - switch ( the_timer->the_class ) { - case TIMER_INTERVAL: - _Watchdog_Remove_ticks( &the_timer->Ticker ); - break; - case TIMER_TIME_OF_DAY: - _Watchdog_Remove_seconds( &the_timer->Ticker ); - break; - case TIMER_INTERVAL_ON_TASK: - case TIMER_TIME_OF_DAY_ON_TASK: - timer_server = _Timer_server; - (*timer_server->cancel)( timer_server, the_timer ); - break; - default: - _Assert( the_timer->the_class == TIMER_DORMANT ); + ( *the_timer->routine )( the_timer->Object.id, the_timer->user_data ); +} + +rtems_status_code _Timer_Fire( + rtems_id id, + rtems_interval interval, + rtems_timer_service_routine_entry routine, + void *user_data, + Timer_Classes the_class, + Watchdog_Service_routine_entry adaptor +) +{ + Timer_Control *the_timer; + Objects_Locations location; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; + + the_timer = _Timer_Get( id, &location, &lock_context ); + switch ( location ) { + + case OBJECTS_LOCAL: + cpu = _Timer_Acquire_critical( the_timer, &lock_context ); + _Timer_Cancel( cpu, the_timer ); + _Watchdog_Initialize( &the_timer->Ticker, adaptor ); + the_timer->the_class = the_class; + the_timer->routine = routine; + the_timer->user_data = user_data; + the_timer->initial = interval; + the_timer->start_time = _Timer_Get_CPU_ticks( cpu ); + + if ( _Timer_Is_interval_class( the_class ) ) { + _Watchdog_Insert( + &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ], + &the_timer->Ticker, + cpu->Watchdog.ticks + interval + ); + } else { + _Watchdog_Insert( + &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_ABSOLUTE ], + &the_timer->Ticker, + _Watchdog_Ticks_from_seconds( interval ) + ); + } + + _Timer_Release( cpu, &lock_context ); + return RTEMS_SUCCESSFUL; + +#if defined(RTEMS_MULTIPROCESSING) + case OBJECTS_REMOTE: /* should never return this */ +#endif + case OBJECTS_ERROR: break; } - _ISR_Enable( level ); + return RTEMS_INVALID_ID; +} + +rtems_status_code _Timer_Fire_after( + rtems_id id, + rtems_interval ticks, + rtems_timer_service_routine_entry routine, + void *user_data, + Timer_Classes the_class, + Watchdog_Service_routine_entry adaptor +) +{ + if ( ticks == 0 ) + return RTEMS_INVALID_NUMBER; + + if ( !routine ) + return RTEMS_INVALID_ADDRESS; + + return _Timer_Fire( + id, + ticks, + routine, + user_data, + the_class, + adaptor + ); +} + +rtems_status_code _Timer_Fire_when( + rtems_id id, + const rtems_time_of_day *wall_time, + rtems_timer_service_routine_entry routine, + void *user_data, + Timer_Classes the_class, + Watchdog_Service_routine_entry adaptor +) +{ + rtems_interval seconds; + + if ( !_TOD_Is_set() ) + return RTEMS_NOT_DEFINED; + + if ( !routine ) + return RTEMS_INVALID_ADDRESS; + + if ( !_TOD_Validate( wall_time ) ) + return RTEMS_INVALID_CLOCK; + + seconds = _TOD_To_seconds( wall_time ); + if ( seconds <= _TOD_Seconds_since_epoch() ) + return RTEMS_INVALID_CLOCK; + + return _Timer_Fire( + id, + seconds, + routine, + user_data, + the_class, + adaptor + ); +} + +void _Timer_Cancel( Per_CPU_Control *cpu, Timer_Control *the_timer ) +{ + Timer_Classes the_class; + + the_class = the_timer->the_class; + + if ( _Watchdog_Is_scheduled( &the_timer->Ticker ) ) { + the_timer->stop_time = _Timer_Get_CPU_ticks( cpu ); + _Watchdog_Remove( + &cpu->Watchdog.Header[ _Timer_Watchdog_header_index( the_class ) ], + &the_timer->Ticker + ); + } else if ( _Timer_Is_on_task_class( the_class ) ) { + Timer_server_Control *timer_server; + ISR_lock_Context lock_context; + + timer_server = _Timer_server; + _Assert( timer_server != NULL ); + _Timer_server_Acquire_critical( timer_server, &lock_context ); + + if ( _Watchdog_Get_state( &the_timer->Ticker ) == WATCHDOG_PENDING ) { + _Watchdog_Set_state( &the_timer->Ticker, WATCHDOG_INACTIVE ); + _Chain_Extract_unprotected( &the_timer->Ticker.Node.Chain ); + } + + _Timer_server_Release_critical( timer_server, &lock_context ); + } } rtems_status_code rtems_timer_create( @@ -75,7 +208,7 @@ rtems_status_code rtems_timer_create( } the_timer->the_class = TIMER_DORMANT; - _Watchdog_Preinitialize( &the_timer->Ticker ); + _Watchdog_Preinitialize( &the_timer->Ticker, _Per_CPU_Get_snapshot() ); _Objects_Open( &_Timer_Information, diff --git a/cpukit/rtems/src/timerdelete.c b/cpukit/rtems/src/timerdelete.c index 0849ec5ba6..9c413976c4 100644 --- a/cpukit/rtems/src/timerdelete.c +++ b/cpukit/rtems/src/timerdelete.c @@ -18,12 +18,7 @@ #include "config.h" #endif -#include -#include -#include -#include #include -#include rtems_status_code rtems_timer_delete( rtems_id id @@ -31,15 +26,18 @@ rtems_status_code rtems_timer_delete( { Timer_Control *the_timer; Objects_Locations location; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; _Objects_Allocator_lock(); - the_timer = _Timer_Get( id, &location ); + the_timer = _Timer_Get( id, &location, &lock_context ); switch ( location ) { case OBJECTS_LOCAL: _Objects_Close( &_Timer_Information, &the_timer->Object ); - _Timer_Cancel( the_timer ); - _Objects_Put( &the_timer->Object ); + cpu = _Timer_Acquire_critical( the_timer, &lock_context ); + _Timer_Cancel( cpu, the_timer ); + _Timer_Release( cpu, &lock_context ); _Timer_Free( the_timer ); _Objects_Allocator_unlock(); return RTEMS_SUCCESSFUL; diff --git a/cpukit/rtems/src/timerfireafter.c b/cpukit/rtems/src/timerfireafter.c index 84cf46bc37..82bd878cec 100644 --- a/cpukit/rtems/src/timerfireafter.c +++ b/cpukit/rtems/src/timerfireafter.c @@ -18,12 +18,7 @@ #include "config.h" #endif -#include -#include -#include -#include #include -#include rtems_status_code rtems_timer_fire_after( rtems_id id, @@ -32,55 +27,12 @@ rtems_status_code rtems_timer_fire_after( void *user_data ) { - Timer_Control *the_timer; - Objects_Locations location; - ISR_Level level; - - if ( ticks == 0 ) - return RTEMS_INVALID_NUMBER; - - if ( !routine ) - return RTEMS_INVALID_ADDRESS; - - the_timer = _Timer_Get( id, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - _Timer_Cancel( the_timer ); - - _ISR_Disable( level ); - - /* - * Check to see if the watchdog has just been inserted by a - * higher priority interrupt. If so, abandon this insert. - */ - - if ( the_timer->Ticker.state != WATCHDOG_INACTIVE ) { - _ISR_Enable( level ); - _Objects_Put( &the_timer->Object ); - return RTEMS_SUCCESSFUL; - } - - /* - * OK. Now we now the timer was not rescheduled by an interrupt - * so we can atomically initialize it as in use. - */ - - the_timer->the_class = TIMER_INTERVAL; - _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data ); - _ISR_Enable( level ); - - - _Watchdog_Insert_ticks( &the_timer->Ticker, ticks ); - _Objects_Put( &the_timer->Object ); - return RTEMS_SUCCESSFUL; - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* should never return this */ -#endif - case OBJECTS_ERROR: - break; - } - - return RTEMS_INVALID_ID; + return _Timer_Fire_after( + id, + ticks, + routine, + user_data, + TIMER_INTERVAL, + _Timer_Routine_adaptor + ); } diff --git a/cpukit/rtems/src/timerfirewhen.c b/cpukit/rtems/src/timerfirewhen.c index 1acbaf9b8f..eddeb16c4f 100644 --- a/cpukit/rtems/src/timerfirewhen.c +++ b/cpukit/rtems/src/timerfirewhen.c @@ -19,9 +19,6 @@ #endif #include -#include -#include -#include rtems_status_code rtems_timer_fire_when( rtems_id id, @@ -30,43 +27,12 @@ rtems_status_code rtems_timer_fire_when( void *user_data ) { - Timer_Control *the_timer; - Objects_Locations location; - rtems_interval seconds; - - if ( !_TOD_Is_set() ) - return RTEMS_NOT_DEFINED; - - if ( !_TOD_Validate( wall_time ) ) - return RTEMS_INVALID_CLOCK; - - if ( !routine ) - return RTEMS_INVALID_ADDRESS; - - seconds = _TOD_To_seconds( wall_time ); - if ( seconds <= _TOD_Seconds_since_epoch() ) - return RTEMS_INVALID_CLOCK; - - the_timer = _Timer_Get( id, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - _Timer_Cancel( the_timer ); - the_timer->the_class = TIMER_TIME_OF_DAY; - _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data ); - _Watchdog_Insert_seconds( - &the_timer->Ticker, - seconds - _TOD_Seconds_since_epoch() - ); - _Objects_Put( &the_timer->Object ); - return RTEMS_SUCCESSFUL; - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* should never return this */ -#endif - case OBJECTS_ERROR: - break; - } - - return RTEMS_INVALID_ID; + return _Timer_Fire_when( + id, + wall_time, + routine, + user_data, + TIMER_TIME_OF_DAY, + _Timer_Routine_adaptor + ); } diff --git a/cpukit/rtems/src/timergetinfo.c b/cpukit/rtems/src/timergetinfo.c index 17c32e6cf4..a11861c63e 100644 --- a/cpukit/rtems/src/timergetinfo.c +++ b/cpukit/rtems/src/timergetinfo.c @@ -32,19 +32,22 @@ rtems_status_code rtems_timer_get_information( { Timer_Control *the_timer; Objects_Locations location; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; if ( !the_info ) return RTEMS_INVALID_ADDRESS; - the_timer = _Timer_Get( id, &location ); + the_timer = _Timer_Get( id, &location, &lock_context ); switch ( location ) { case OBJECTS_LOCAL: + cpu = _Timer_Acquire_critical( the_timer, &lock_context ); the_info->the_class = the_timer->the_class; - the_info->initial = the_timer->Ticker.initial; - the_info->start_time = the_timer->Ticker.start_time; - the_info->stop_time = the_timer->Ticker.stop_time; - _Objects_Put( &the_timer->Object ); + the_info->initial = the_timer->initial; + the_info->start_time = the_timer->start_time; + the_info->stop_time = the_timer->stop_time; + _Timer_Release( cpu, &lock_context ); return RTEMS_SUCCESSFUL; #if defined(RTEMS_MULTIPROCESSING) diff --git a/cpukit/rtems/src/timerreset.c b/cpukit/rtems/src/timerreset.c index 7ab172ea4f..72c912baa3 100644 --- a/cpukit/rtems/src/timerreset.c +++ b/cpukit/rtems/src/timerreset.c @@ -44,40 +44,29 @@ rtems_status_code rtems_timer_reset( { Timer_Control *the_timer; Objects_Locations location; - rtems_status_code status = RTEMS_SUCCESSFUL; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; + rtems_status_code status; - the_timer = _Timer_Get( id, &location ); + the_timer = _Timer_Get( id, &location, &lock_context ); switch ( location ) { case OBJECTS_LOCAL: - if ( the_timer->the_class == TIMER_INTERVAL ) { - _Watchdog_Reset_ticks( &the_timer->Ticker ); - } else if ( the_timer->the_class == TIMER_INTERVAL_ON_TASK ) { - Timer_server_Control *timer_server = _Timer_server; + cpu = _Timer_Acquire_critical( the_timer, &lock_context ); - /* - * There is no way for a timer to have this class unless - * it was scheduled as a server fire. That requires that - * the Timer Server be initiated. So this error cannot - * occur unless something is internally wrong. - */ - #if defined(RTEMS_DEBUG) - if ( !timer_server ) { - _Objects_Put( &the_timer->Object ); - return RTEMS_INCORRECT_STATE; - } - #endif - (*timer_server->cancel)( timer_server, the_timer ); - (*timer_server->schedule_operation)( timer_server, the_timer ); + if ( _Timer_Is_interval_class( the_timer->the_class ) ) { + _Timer_Cancel( cpu, the_timer ); + _Watchdog_Insert( + &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ], + &the_timer->Ticker, + cpu->Watchdog.ticks + the_timer->initial + ); + status = RTEMS_SUCCESSFUL; } else { - /* - * Must be dormant or time of day timer (e.g. TIMER_DORMANT, - * TIMER_TIME_OF_DAY, or TIMER_TIME_OF_DAY_ON_TASK). We - * can only reset active interval timers. - */ status = RTEMS_NOT_DEFINED; } - _Objects_Put( &the_timer->Object ); + + _Timer_Release( cpu, &lock_context ); return status; #if defined(RTEMS_MULTIPROCESSING) diff --git a/cpukit/rtems/src/timerserver.c b/cpukit/rtems/src/timerserver.c index 7d757809b8..cf06319434 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-2015 embedded brains GmbH. + * Copyright (c) 2009, 2016 embedded brains GmbH. * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -34,193 +34,48 @@ static Timer_server_Control _Timer_server_Default; -static void _Timer_server_Cancel_method( +static void _Timer_server_Acquire( Timer_server_Control *ts, - Timer_Control *timer + ISR_lock_Context *lock_context ) { - 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 Watchdog_Interval _Timer_server_Get_ticks( void ) -{ - return _Watchdog_Ticks_since_boot; + _ISR_lock_ISR_disable_and_acquire( &ts->Lock, lock_context ); } -static Watchdog_Interval _Timer_server_Get_seconds( void ) -{ - return _TOD_Seconds_since_epoch(); -} - -static void _Timer_server_Update_system_watchdog( - Timer_server_Watchdogs *watchdogs, - Watchdog_Header *system_header -) -{ - ISR_lock_Context lock_context; - - _Watchdog_Acquire( &watchdogs->Header, &lock_context ); - - if ( watchdogs->system_watchdog_helper == NULL ) { - Thread_Control *executing; - uint32_t my_generation; - - executing = _Thread_Executing; - watchdogs->system_watchdog_helper = executing; - - 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( - Timer_server_Watchdogs *watchdogs, - Timer_Control *timer, - Watchdog_Header *system_header, - Watchdog_Interval (*get_ticks)( void ) -) -{ - ISR_lock_Context lock_context; - Watchdog_Interval now; - Watchdog_Interval delta; - - _Watchdog_Acquire( &watchdogs->Header, &lock_context ); - - now = (*get_ticks)(); - delta = now - watchdogs->last_snapshot; - watchdogs->last_snapshot = now; - watchdogs->current_snapshot = now; - - if ( watchdogs->system_watchdog_delta > delta ) { - watchdogs->system_watchdog_delta -= delta; - } else { - watchdogs->system_watchdog_delta = 0; - } - - if ( !_Watchdog_Is_empty( &watchdogs->Header ) ) { - Watchdog_Control *first = _Watchdog_First( &watchdogs->Header ); - - if ( first->delta_interval > delta ) { - first->delta_interval -= delta; - } else { - first->delta_interval = 0; - } - } - - _Watchdog_Insert_locked( - &watchdogs->Header, - &timer->Ticker, - &lock_context - ); - - ++watchdogs->generation; - - _Watchdog_Release( &watchdogs->Header, &lock_context ); - - _Timer_server_Update_system_watchdog( watchdogs, system_header ); -} - -static void _Timer_server_Schedule_operation_method( +static void _Timer_server_Release( Timer_server_Control *ts, - Timer_Control *timer + ISR_lock_Context *lock_context ) { - 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 - ); - } + _ISR_lock_Release_and_ISR_enable( &ts->Lock, lock_context ); } -static void _Timer_server_Update_current_snapshot( - Timer_server_Watchdogs *watchdogs, - Watchdog_Interval (*get_ticks)( void ) -) +void _Timer_server_Routine_adaptor( Watchdog_Control *the_watchdog ) { - ISR_lock_Context lock_context; + Timer_Control *the_timer; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; + Timer_server_Control *ts; + bool wakeup; - _Watchdog_Acquire( &watchdogs->Header, &lock_context ); - watchdogs->current_snapshot = (*get_ticks)(); - watchdogs->system_watchdog_delta = 0; - _Watchdog_Release( &watchdogs->Header, &lock_context ); -} + ts = _Timer_server; + _Assert( ts != NULL ); + the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker ); -static void _Timer_server_Tickle( - Timer_server_Watchdogs *watchdogs, - Watchdog_Header *system_header, - Watchdog_Interval (*get_ticks)( void ), - bool ticks -) -{ - ISR_lock_Context lock_context; - Watchdog_Interval now; - Watchdog_Interval last; + _Timer_server_Acquire( ts, &lock_context ); - _Watchdog_Acquire( &watchdogs->Header, &lock_context ); + _Assert( _Watchdog_Get_state( &the_timer->Ticker ) == WATCHDOG_INACTIVE ); + _Watchdog_Set_state( &the_timer->Ticker, WATCHDOG_PENDING ); + cpu = _Watchdog_Get_CPU( &the_timer->Ticker ); + the_timer->stop_time = _Timer_Get_CPU_ticks( cpu ); + wakeup = _Chain_Is_empty( &ts->Pending ); + _Chain_Append_unprotected( &ts->Pending, &the_timer->Ticker.Node.Chain ); - now = watchdogs->current_snapshot; - last = watchdogs->last_snapshot; - watchdogs->last_snapshot = now; + _Timer_server_Release( ts, &lock_context ); - if ( ticks || now >= last ) { - _Watchdog_Adjust_forward_locked( - &watchdogs->Header, - now - last, - &lock_context - ); - } else { - _Watchdog_Adjust_backward_locked( - &watchdogs->Header, - last - now - ); + if ( wakeup ) { + (void) rtems_event_system_send( ts->server_id, RTEMS_EVENT_SYSTEM_SERVER ); } - - ++watchdogs->generation; - - _Watchdog_Release( &watchdogs->Header, &lock_context ); - - _Timer_server_Update_system_watchdog( watchdogs, system_header ); } /** @@ -239,21 +94,38 @@ static rtems_task _Timer_server_Body( Timer_server_Control *ts = (Timer_server_Control *) arg; while ( true ) { - rtems_event_set events; + ISR_lock_Context lock_context; + rtems_event_set events; - _Timer_server_Tickle( - &ts->Interval_watchdogs, - &_Watchdog_Ticks_header, - _Timer_server_Get_ticks, - true - ); + _Timer_server_Acquire( ts, &lock_context ); - _Timer_server_Tickle( - &ts->TOD_watchdogs, - &_Watchdog_Seconds_header, - _Timer_server_Get_seconds, - false - ); + while ( true ) { + Watchdog_Control *the_watchdog; + Timer_Control *the_timer; + rtems_timer_service_routine_entry routine; + Objects_Id id; + void *user_data; + + the_watchdog = (Watchdog_Control *) _Chain_Get_unprotected( &ts->Pending ); + if ( the_watchdog == NULL ) { + break; + } + + _Assert( _Watchdog_Get_state( the_watchdog ) == WATCHDOG_PENDING ); + _Watchdog_Set_state( the_watchdog, WATCHDOG_INACTIVE ); + the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker ); + routine = the_timer->routine; + id = the_timer->Object.id; + user_data = the_timer->user_data; + + _Timer_server_Release( ts, &lock_context ); + + ( *routine )( id, user_data ); + + _Timer_server_Acquire( ts, &lock_context ); + } + + _Timer_server_Release( ts, &lock_context ); (void) rtems_event_system_receive( RTEMS_EVENT_SYSTEM_SERVER, @@ -264,98 +136,34 @@ static rtems_task _Timer_server_Body( } } -static void _Timer_server_Wakeup( - Objects_Id id, - void *arg -) -{ - Timer_server_Control *ts = arg; - - _Timer_server_Update_current_snapshot( - &ts->Interval_watchdogs, - _Timer_server_Get_ticks - ); - - _Timer_server_Update_current_snapshot( - &ts->TOD_watchdogs, - _Timer_server_Get_seconds - ); - - (void) rtems_event_system_send( id, RTEMS_EVENT_SYSTEM_SERVER ); -} - -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; - - now = (*get_ticks)(); - watchdogs->last_snapshot = now; - watchdogs->current_snapshot = now; - - _Watchdog_Header_initialize( &watchdogs->Header ); - _Watchdog_Preinitialize( &watchdogs->System_watchdog ); - _Watchdog_Initialize( - &watchdogs->System_watchdog, - _Timer_server_Wakeup, - id, - ts - ); -} - -/** - * @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. - * - * @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 - * - * @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, - rtems_attribute attribute_set +static rtems_status_code _Timer_server_Initiate( + rtems_task_priority priority, + size_t stack_size, + rtems_attribute attribute_set ) { - rtems_id id; rtems_status_code status; - rtems_task_priority _priority; - static bool initialized = false; - bool tmpInitialized; - Timer_server_Control *ts = &_Timer_server_Default; + rtems_id id; + Timer_server_Control *ts; + + /* + * Just to make sure this is only called once. + */ + if ( _Timer_server != NULL ) { + return RTEMS_INCORRECT_STATE; + } /* * 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 ) return RTEMS_INVALID_PRIORITY; - _priority = PRIORITY_PSEUDO_ISR; + priority = PRIORITY_PSEUDO_ISR; } - /* - * Just to make sure this is only called once. - */ - _Once_Lock(); - tmpInitialized = initialized; - initialized = true; - _Once_Unlock(); - - if ( tmpInitialized ) - return RTEMS_INCORRECT_STATE; - /* * 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 @@ -371,19 +179,18 @@ rtems_status_code rtems_timer_initiate_server( * 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 */ - stack_size, /* let user specify stack size */ + rtems_build_name('T','I','M','E'), + priority, + stack_size, rtems_configuration_is_smp_enabled() ? RTEMS_DEFAULT_MODES : /* no preempt is not supported for SMP */ RTEMS_NO_PREEMPT, /* no preempt is like an interrupt */ /* user may want floating point but we need */ /* system task specified for 0 priority */ attribute_set | RTEMS_SYSTEM_TASK, - &id /* get the id back */ + &id ); - if (status) { - initialized = false; + if (status != RTEMS_SUCCESSFUL) { return status; } @@ -392,26 +199,10 @@ rtems_status_code rtems_timer_initiate_server( * Timer Server so we do not have to have a critical section. */ - _Timer_server_Initialize_watchdogs( - ts, - id, - &ts->Interval_watchdogs, - _Timer_server_Get_ticks - ); - - _Timer_server_Initialize_watchdogs( - ts, - id, - &ts->TOD_watchdogs, - _Timer_server_Get_seconds - ); - - /* - * Initialize the pointer to the timer server methods so applications that - * do not use the Timer Server do not have to pull it in. - */ - ts->cancel = _Timer_server_Cancel_method; - ts->schedule_operation = _Timer_server_Schedule_operation_method; + ts = &_Timer_server_Default; + _ISR_lock_Initialize( &ts->Lock, "Timer Server" ); + _Chain_Initialize_empty( &ts->Pending ); + ts->server_id = id; /* * The default timer server is now available. @@ -426,19 +217,22 @@ rtems_status_code rtems_timer_initiate_server( _Timer_server_Body, (rtems_task_argument) ts ); + _Assert( status == RTEMS_SUCCESSFUL ); - #if defined(RTEMS_DEBUG) - /* - * One would expect a call to rtems_task_delete() here to clean up - * but there is actually no way (in normal circumstances) that the - * start can fail. The id and starting address are known to be - * be good. If this service fails, something is weirdly wrong on the - * target such as a stray write in an ISR or incorrect memory layout. - */ - if (status) { - initialized = false; - } - #endif + return status; +} + +rtems_status_code rtems_timer_initiate_server( + rtems_task_priority priority, + size_t stack_size, + rtems_attribute attribute_set +) +{ + rtems_status_code status; + + _Once_Lock(); + status = _Timer_server_Initiate( priority, stack_size, attribute_set ); + _Once_Unlock(); return status; } diff --git a/cpukit/rtems/src/timerserverfireafter.c b/cpukit/rtems/src/timerserverfireafter.c index 0636782ae0..ce1fd05848 100644 --- a/cpukit/rtems/src/timerserverfireafter.c +++ b/cpukit/rtems/src/timerserverfireafter.c @@ -18,12 +18,7 @@ #include "config.h" #endif -#include -#include -#include -#include #include -#include rtems_status_code rtems_timer_server_fire_after( rtems_id id, @@ -32,60 +27,19 @@ rtems_status_code rtems_timer_server_fire_after( void *user_data ) { - Timer_Control *the_timer; - Objects_Locations location; - ISR_Level level; - Timer_server_Control *timer_server = _Timer_server; + Timer_server_Control *timer_server; + + timer_server = _Timer_server; if ( !timer_server ) return RTEMS_INCORRECT_STATE; - if ( !routine ) - return RTEMS_INVALID_ADDRESS; - - if ( ticks == 0 ) - return RTEMS_INVALID_NUMBER; - - the_timer = _Timer_Get( id, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - _Timer_Cancel( the_timer ); - - _ISR_Disable( level ); - - /* - * Check to see if the watchdog has just been inserted by a - * higher priority interrupt. If so, abandon this insert. - */ - - if ( the_timer->Ticker.state != WATCHDOG_INACTIVE ) { - _ISR_Enable( level ); - _Objects_Put( &the_timer->Object ); - return RTEMS_SUCCESSFUL; - } - - /* - * OK. Now we now the timer was not rescheduled by an interrupt - * so we can atomically initialize it as in use. - */ - - the_timer->the_class = TIMER_INTERVAL_ON_TASK; - _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data ); - the_timer->Ticker.initial = ticks; - _ISR_Enable( level ); - - (*timer_server->schedule_operation)( timer_server, the_timer ); - - _Objects_Put( &the_timer->Object ); - return RTEMS_SUCCESSFUL; - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* should never return this */ -#endif - case OBJECTS_ERROR: - break; - } - - return RTEMS_INVALID_ID; + return _Timer_Fire_after( + id, + ticks, + routine, + user_data, + TIMER_INTERVAL_ON_TASK, + _Timer_server_Routine_adaptor + ); } diff --git a/cpukit/rtems/src/timerserverfirewhen.c b/cpukit/rtems/src/timerserverfirewhen.c index 0069af1c3b..f96a470b7c 100644 --- a/cpukit/rtems/src/timerserverfirewhen.c +++ b/cpukit/rtems/src/timerserverfirewhen.c @@ -19,26 +19,6 @@ #endif #include -#include -#include -#include - -/* - * rtems_timer_server_fire_when - * - * This directive allows a thread to start a timer which will by - * executed by the Timer Server when it fires. - * - * Input parameters: - * id - timer id - * wall_time - time of day to fire timer - * routine - routine to schedule - * user_data - passed as argument to routine when it is fired - * - * Output parameters: - * RTEMS_SUCCESSFUL - if successful - * error code - if unsuccessful - */ rtems_status_code rtems_timer_server_fire_when( rtems_id id, @@ -47,47 +27,19 @@ rtems_status_code rtems_timer_server_fire_when( void *user_data ) { - Timer_Control *the_timer; - Objects_Locations location; - rtems_interval seconds; - Timer_server_Control *timer_server = _Timer_server; + Timer_server_Control *timer_server; + + timer_server = _Timer_server; if ( !timer_server ) return RTEMS_INCORRECT_STATE; - if ( !_TOD_Is_set() ) - return RTEMS_NOT_DEFINED; - - if ( !routine ) - return RTEMS_INVALID_ADDRESS; - - if ( !_TOD_Validate( wall_time ) ) - return RTEMS_INVALID_CLOCK; - - seconds = _TOD_To_seconds( wall_time ); - if ( seconds <= _TOD_Seconds_since_epoch() ) - return RTEMS_INVALID_CLOCK; - - the_timer = _Timer_Get( id, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - _Timer_Cancel( the_timer ); - the_timer->the_class = TIMER_TIME_OF_DAY_ON_TASK; - _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data ); - the_timer->Ticker.initial = seconds - _TOD_Seconds_since_epoch(); - - (*timer_server->schedule_operation)( timer_server, the_timer ); - - _Objects_Put( &the_timer->Object ); - return RTEMS_SUCCESSFUL; - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* should never return this */ -#endif - case OBJECTS_ERROR: - break; - } - - return RTEMS_INVALID_ID; + return _Timer_Fire_when( + id, + wall_time, + routine, + user_data, + TIMER_TIME_OF_DAY_ON_TASK, + _Timer_server_Routine_adaptor + ); } -- cgit v1.2.3