diff options
Diffstat (limited to 'cpukit/rtems/src/timerserver.c')
-rw-r--r-- | cpukit/rtems/src/timerserver.c | 394 |
1 files changed, 94 insertions, 300 deletions
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,99 +136,35 @@ 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 * higher than any other task in the system. It can be viewed as a low @@ -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; } |