diff options
Diffstat (limited to 'cpukit/rtems/src/timercreate.c')
-rw-r--r-- | cpukit/rtems/src/timercreate.c | 179 |
1 files changed, 156 insertions, 23 deletions
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 <rtems/system.h> +#include <rtems/rtems/timerimpl.h> +#include <rtems/rtems/clock.h> #include <rtems/rtems/status.h> #include <rtems/rtems/support.h> #include <rtems/score/assert.h> +#include <rtems/score/chainimpl.h> #include <rtems/score/thread.h> -#include <rtems/rtems/timerimpl.h> +#include <rtems/score/todimpl.h> #include <rtems/score/watchdogimpl.h> -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, |