summaryrefslogtreecommitdiffstats
path: root/cpukit/rtems/src/timerserver.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/rtems/src/timerserver.c')
-rw-r--r--cpukit/rtems/src/timerserver.c394
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;
}