[PATCH 09/45] score: New timer server implementation
Sebastian Huber
sebastian.huber at embedded-brains.de
Fri May 15 11:41:09 UTC 2015
Use mostly the standard watchdog operations. Use a system event for
synchronization. This implementation is simpler and offers better SMP
performance.
Close #2131.
---
cpukit/rtems/include/rtems/rtems/event.h | 5 +
cpukit/rtems/include/rtems/rtems/timerimpl.h | 51 +-
cpukit/rtems/src/timerserver.c | 570 +++++++--------------
cpukit/score/Makefile.am | 2 +-
cpukit/score/include/rtems/score/watchdogimpl.h | 59 ++-
cpukit/score/src/watchdogadjust.c | 35 +-
cpukit/score/src/watchdogadjusttochain.c | 75 ---
cpukit/score/src/watchdoginsert.c | 21 +-
testsuites/sptests/spintrcritical17/init.c | 163 +++---
.../sptests/spintrcritical17/spintrcritical17.doc | 6 +-
10 files changed, 370 insertions(+), 617 deletions(-)
delete mode 100644 cpukit/score/src/watchdogadjusttochain.c
diff --git a/cpukit/rtems/include/rtems/rtems/event.h b/cpukit/rtems/include/rtems/rtems/event.h
index dce7de1..012452a 100644
--- a/cpukit/rtems/include/rtems/rtems/event.h
+++ b/cpukit/rtems/include/rtems/rtems/event.h
@@ -319,6 +319,11 @@ rtems_status_code rtems_event_receive (
#define RTEMS_EVENT_SYSTEM_NETWORK_CLOSE RTEMS_EVENT_26
/**
+ * @brief Reserved system event for the timer server.
+ */
+#define RTEMS_EVENT_SYSTEM_TIMER_SERVER RTEMS_EVENT_30
+
+/**
* @brief Reserved system event for transient usage.
*/
#define RTEMS_EVENT_SYSTEM_TRANSIENT RTEMS_EVENT_31
diff --git a/cpukit/rtems/include/rtems/rtems/timerimpl.h b/cpukit/rtems/include/rtems/rtems/timerimpl.h
index 4f200ef..e5b37aa 100644
--- a/cpukit/rtems/include/rtems/rtems/timerimpl.h
+++ b/cpukit/rtems/include/rtems/rtems/timerimpl.h
@@ -65,24 +65,43 @@ typedef struct {
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 known time snapshot of the timer server.
+ * @brief Last time snapshot of the timer server.
*
* The units may be ticks or seconds.
*/
- Watchdog_Interval volatile last_snapshot;
-} Timer_server_Watchdogs;
+ Watchdog_Interval last_snapshot;
-struct Timer_server_Control {
/**
- * @brief Timer server thread.
+ * @brief Current time snapshot of the timer server.
+ *
+ * The units may be ticks or seconds.
*/
- Thread_Control *thread;
+ Watchdog_Interval current_snapshot;
+} Timer_server_Watchdogs;
+struct Timer_server_Control {
/**
* @brief The cancel method of the timer server.
*/
@@ -102,26 +121,6 @@ struct Timer_server_Control {
* @brief TOD watchdogs triggered by the timer server.
*/
Timer_server_Watchdogs TOD_watchdogs;
-
- /**
- * @brief Chain of timers scheduled for insert.
- *
- * This pointer is not @c NULL whenever the interval and TOD chains are
- * processed. After the processing this list will be checked and if
- * necessary the processing will be restarted. Processing of these chains
- * can be only interrupted through interrupts.
- */
- Chain_Control *volatile insert_chain;
-
- /**
- * @brief Indicates that the timer server is active or not.
- *
- * The server is active after the delay on a system watchdog. The activity
- * period of the server ends when no more watchdogs managed by the server
- * fire. The system watchdogs must not be manipulated when the server is
- * active.
- */
- bool volatile active;
};
/**
diff --git a/cpukit/rtems/src/timerserver.c b/cpukit/rtems/src/timerserver.c
index 15cbdfd..db38f48 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 embedded brains GmbH.
+ * Copyright (c) 2009-2015 embedded brains GmbH.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -26,200 +26,128 @@
#include "config.h"
#endif
+#include <rtems.h>
#include <rtems/rtems/timerimpl.h>
#include <rtems/rtems/tasksimpl.h>
-#include <rtems/score/isrlevel.h>
-#include <rtems/score/threadimpl.h>
#include <rtems/score/todimpl.h>
static Timer_server_Control _Timer_server_Default;
-static void _Timer_server_Stop_interval_system_watchdog(
- Timer_server_Control *ts
+static void _Timer_server_Cancel_method(
+ Timer_server_Control *ts,
+ Timer_Control *timer
)
{
- _Watchdog_Remove_ticks( &ts->Interval_watchdogs.System_watchdog );
+ 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 void _Timer_server_Reset_interval_system_watchdog(
- Timer_server_Control *ts
-)
+static Watchdog_Interval _Timer_server_Get_ticks( void )
{
- ISR_Level level;
-
- _Timer_server_Stop_interval_system_watchdog( ts );
-
- _ISR_Disable( level );
- if ( !_Watchdog_Is_empty( &ts->Interval_watchdogs.Header ) ) {
- Watchdog_Interval delta_interval =
- _Watchdog_First( &ts->Interval_watchdogs.Header )->delta_interval;
- _ISR_Enable( level );
-
- /*
- * The unit is TICKS here.
- */
- _Watchdog_Insert_ticks(
- &ts->Interval_watchdogs.System_watchdog,
- delta_interval
- );
- } else {
- _ISR_Enable( level );
- }
+ return _Watchdog_Ticks_since_boot;
}
-static void _Timer_server_Stop_tod_system_watchdog(
- Timer_server_Control *ts
-)
+static Watchdog_Interval _Timer_server_Get_seconds( void )
{
- _Watchdog_Remove_seconds( &ts->TOD_watchdogs.System_watchdog );
+ return _TOD_Seconds_since_epoch();
}
-static void _Timer_server_Reset_tod_system_watchdog(
- Timer_server_Control *ts
+static void _Timer_server_Update_system_watchdog(
+ Timer_server_Watchdogs *watchdogs,
+ Watchdog_Header *system_header
)
{
- ISR_Level level;
+ ISR_lock_Context lock_context;
- _Timer_server_Stop_tod_system_watchdog( ts );
+ _Watchdog_Acquire( &watchdogs->Header, &lock_context );
- _ISR_Disable( level );
- if ( !_Watchdog_Is_empty( &ts->TOD_watchdogs.Header ) ) {
- Watchdog_Interval delta_interval =
- _Watchdog_First( &ts->TOD_watchdogs.Header )->delta_interval;
- _ISR_Enable( level );
+ if ( watchdogs->system_watchdog_helper == NULL ) {
+ Thread_Control *executing;
+ uint32_t my_generation;
- /*
- * The unit is SECONDS here.
- */
- _Watchdog_Insert_seconds(
- &ts->TOD_watchdogs.System_watchdog,
- delta_interval
- );
- } else {
- _ISR_Enable( level );
- }
-}
+ executing = _Thread_Executing;
+ watchdogs->system_watchdog_helper = executing;
-static void _Timer_server_Insert_timer(
- Timer_server_Control *ts,
- Timer_Control *timer
-)
-{
- if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) {
- _Watchdog_Insert( &ts->Interval_watchdogs.Header, &timer->Ticker );
- } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) {
- _Watchdog_Insert( &ts->TOD_watchdogs.Header, &timer->Ticker );
+ 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_and_make_snapshot(
- Timer_server_Control *ts,
- Timer_Control *timer
+static void _Timer_server_Insert_timer(
+ Timer_server_Watchdogs *watchdogs,
+ Timer_Control *timer,
+ Watchdog_Header *system_header,
+ Watchdog_Interval (*get_ticks)( void )
)
{
- Watchdog_Control *first_watchdog;
- Watchdog_Interval delta_interval;
- Watchdog_Interval last_snapshot;
- Watchdog_Interval snapshot;
+ ISR_lock_Context lock_context;
+ Watchdog_Interval now;
Watchdog_Interval delta;
- ISR_Level level;
- /*
- * We have to update the time snapshots here, because otherwise we may have
- * problems with the integer range of the delta values. The time delta DT
- * from the last snapshot to now may be arbitrarily long. The last snapshot
- * is the reference point for the delta chain. Thus if we do not update the
- * reference point we have to add DT to the initial delta of the watchdog
- * being inserted. This could result in an integer overflow.
- */
+ _Watchdog_Acquire( &watchdogs->Header, &lock_context );
- _Thread_Disable_dispatch();
+ now = (*get_ticks)();
+ delta = now - watchdogs->last_snapshot;
+ watchdogs->last_snapshot = now;
+ watchdogs->current_snapshot = now;
- if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) {
- /*
- * We have to advance the last known ticks value of the server and update
- * the watchdog chain accordingly.
- */
- _ISR_Disable( level );
- snapshot = _Watchdog_Ticks_since_boot;
- last_snapshot = ts->Interval_watchdogs.last_snapshot;
- if ( !_Watchdog_Is_empty( &ts->Interval_watchdogs.Header ) ) {
- first_watchdog = _Watchdog_First( &ts->Interval_watchdogs.Header );
-
- /*
- * We assume adequate unsigned arithmetic here.
- */
- delta = snapshot - last_snapshot;
-
- delta_interval = first_watchdog->delta_interval;
- if (delta_interval > delta) {
- delta_interval -= delta;
- } else {
- delta_interval = 0;
- }
- first_watchdog->delta_interval = delta_interval;
- }
- ts->Interval_watchdogs.last_snapshot = snapshot;
- _ISR_Enable( level );
+ if ( watchdogs->system_watchdog_delta > delta ) {
+ watchdogs->system_watchdog_delta -= delta;
+ } else {
+ watchdogs->system_watchdog_delta = 0;
+ }
- _Watchdog_Insert( &ts->Interval_watchdogs.Header, &timer->Ticker );
+ if ( !_Watchdog_Is_empty( &watchdogs->Header ) ) {
+ Watchdog_Control *first = _Watchdog_First( &watchdogs->Header );
- if ( !ts->active ) {
- _Timer_server_Reset_interval_system_watchdog( ts );
- }
- } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) {
- /*
- * We have to advance the last known seconds value of the server and update
- * the watchdog chain accordingly.
- */
- _ISR_Disable( level );
- snapshot = (Watchdog_Interval) _TOD_Seconds_since_epoch();
- last_snapshot = ts->TOD_watchdogs.last_snapshot;
- if ( !_Watchdog_Is_empty( &ts->TOD_watchdogs.Header ) ) {
- first_watchdog = _Watchdog_First( &ts->TOD_watchdogs.Header );
- delta_interval = first_watchdog->delta_interval;
- if ( snapshot > last_snapshot ) {
- /*
- * We advanced in time.
- */
- delta = snapshot - last_snapshot;
- if (delta_interval > delta) {
- delta_interval -= delta;
- } else {
- delta_interval = 0;
- }
- } else {
- /*
- * Someone put us in the past.
- */
- delta = last_snapshot - snapshot;
- delta_interval += delta;
- }
- first_watchdog->delta_interval = delta_interval;
+ if ( first->delta_interval > delta ) {
+ first->delta_interval -= delta;
+ } else {
+ first->delta_interval = 0;
}
- ts->TOD_watchdogs.last_snapshot = snapshot;
- _ISR_Enable( level );
+ }
- _Watchdog_Insert( &ts->TOD_watchdogs.Header, &timer->Ticker );
+ _Watchdog_Insert_locked(
+ &watchdogs->Header,
+ &timer->Ticker,
+ &lock_context
+ );
- if ( !ts->active ) {
- _Timer_server_Reset_tod_system_watchdog( ts );
- }
- }
+ ++watchdogs->generation;
- _Thread_Enable_dispatch();
-}
+ _Watchdog_Release( &watchdogs->Header, &lock_context );
-static void _Timer_server_Cancel_method(
- Timer_server_Control *ts,
- Timer_Control *timer
-)
-{
- 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 );
- }
+ _Timer_server_Update_system_watchdog( watchdogs, system_header );
}
static void _Timer_server_Schedule_operation_method(
@@ -227,143 +155,71 @@ static void _Timer_server_Schedule_operation_method(
Timer_Control *timer
)
{
- if ( ts->insert_chain == NULL ) {
- _Timer_server_Insert_timer_and_make_snapshot( ts, timer );
- } else {
- /*
- * We interrupted a critical section of the timer server. The timer
- * server is not preemptible, so we must be in interrupt context here. No
- * thread dispatch will happen until the timer server finishes its
- * critical section. We have to use the protected chain methods because
- * we may be interrupted by a higher priority interrupt.
- */
- _Chain_Append( ts->insert_chain, &timer->Object.Node );
+ 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
+ );
}
}
-static void _Timer_server_Process_interval_watchdogs(
+static void _Timer_server_Update_current_snapshot(
Timer_server_Watchdogs *watchdogs,
- Chain_Control *fire_chain
+ Watchdog_Interval (*get_ticks)( void )
)
{
- Watchdog_Interval snapshot = _Watchdog_Ticks_since_boot;
+ ISR_lock_Context lock_context;
- /*
- * We assume adequate unsigned arithmetic here.
- */
- Watchdog_Interval delta = snapshot - watchdogs->last_snapshot;
-
- watchdogs->last_snapshot = snapshot;
-
- _Watchdog_Adjust_to_chain( &watchdogs->Header, delta, fire_chain );
+ _Watchdog_Acquire( &watchdogs->Header, &lock_context );
+ watchdogs->current_snapshot = (*get_ticks)();
+ watchdogs->system_watchdog_delta = 0;
+ _Watchdog_Release( &watchdogs->Header, &lock_context );
}
-static void _Timer_server_Process_tod_watchdogs(
+static void _Timer_server_Tickle(
Timer_server_Watchdogs *watchdogs,
- Chain_Control *fire_chain
+ Watchdog_Header *system_header,
+ Watchdog_Interval (*get_ticks)( void ),
+ bool ticks
)
{
- Watchdog_Interval snapshot = (Watchdog_Interval) _TOD_Seconds_since_epoch();
- Watchdog_Interval last_snapshot = watchdogs->last_snapshot;
- Watchdog_Interval delta;
-
- /*
- * 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 watchdogs->Header to indicate this.
- */
- if ( snapshot > last_snapshot ) {
- /*
- * This path is for normal forward movement and cases where the
- * TOD has been set forward.
- */
- delta = snapshot - last_snapshot;
- _Watchdog_Adjust_to_chain( &watchdogs->Header, delta, fire_chain );
-
- } else if ( snapshot < last_snapshot ) {
- /*
- * The current TOD is before the last TOD which indicates that
- * TOD has been set backwards.
- */
- delta = last_snapshot - snapshot;
- _Watchdog_Adjust_backward( &watchdogs->Header, delta );
- }
-
- watchdogs->last_snapshot = snapshot;
-}
-
-static void _Timer_server_Process_insertions( Timer_server_Control *ts )
-{
- while ( true ) {
- Timer_Control *timer = (Timer_Control *) _Chain_Get( ts->insert_chain );
+ ISR_lock_Context lock_context;
+ Watchdog_Interval now;
+ Watchdog_Interval last;
- if ( timer == NULL ) {
- break;
- }
-
- _Timer_server_Insert_timer( ts, timer );
- }
-}
-
-static void _Timer_server_Get_watchdogs_that_fire_now(
- Timer_server_Control *ts,
- Chain_Control *insert_chain,
- Chain_Control *fire_chain
-)
-{
- /*
- * Afterwards all timer inserts are directed to this chain and the interval
- * and TOD chains will be no more modified by other parties.
- */
- ts->insert_chain = insert_chain;
+ _Watchdog_Acquire( &watchdogs->Header, &lock_context );
- while ( true ) {
- ISR_Level level;
+ now = watchdogs->current_snapshot;
+ last = watchdogs->last_snapshot;
+ watchdogs->last_snapshot = now;
- /*
- * Remove all the watchdogs that need to fire so we can invoke them.
- */
- _Timer_server_Process_interval_watchdogs(
- &ts->Interval_watchdogs,
- fire_chain
+ if ( ticks || now >= last ) {
+ _Watchdog_Adjust_forward_locked(
+ &watchdogs->Header,
+ now - last,
+ &lock_context
+ );
+ } else {
+ _Watchdog_Adjust_backward_locked(
+ &watchdogs->Header,
+ last - now
);
- _Timer_server_Process_tod_watchdogs( &ts->TOD_watchdogs, fire_chain );
-
- /*
- * The insertions have to take place here, because they reference the
- * current time. The previous process methods take a snapshot of the
- * current time. In case someone inserts a watchdog with an initial value
- * of zero it will be processed in the next iteration of the timer server
- * body loop.
- */
- _Timer_server_Process_insertions( ts );
-
- _ISR_Disable( level );
- if ( _Chain_Is_empty( insert_chain ) ) {
- ts->insert_chain = NULL;
- _ISR_Enable( level );
-
- break;
- } else {
- _ISR_Enable( level );
- }
}
-}
-/* FIXME: This locking approach for SMP is improvable! */
+ ++watchdogs->generation;
-static void _Timer_server_SMP_lock_aquire( void )
-{
-#if defined( RTEMS_SMP )
- _Thread_Disable_dispatch();
-#endif
-}
+ _Watchdog_Release( &watchdogs->Header, &lock_context );
-static void _Timer_server_SMP_lock_release( void )
-{
-#if defined( RTEMS_SMP )
- _Thread_Enable_dispatch();
-#endif
+ _Timer_server_Update_system_watchdog( watchdogs, system_header );
}
/**
@@ -380,81 +236,73 @@ static rtems_task _Timer_server_Body(
)
{
Timer_server_Control *ts = (Timer_server_Control *) arg;
- Chain_Control insert_chain;
- Chain_Control fire_chain;
- _Chain_Initialize_empty( &insert_chain );
- _Chain_Initialize_empty( &fire_chain );
+ while ( true ) {
+ rtems_event_set events;
- _Timer_server_SMP_lock_aquire();
+ _Timer_server_Tickle(
+ &ts->Interval_watchdogs,
+ &_Watchdog_Ticks_header,
+ _Timer_server_Get_ticks,
+ true
+ );
- while ( true ) {
- _Timer_server_Get_watchdogs_that_fire_now( ts, &insert_chain, &fire_chain );
-
- if ( !_Chain_Is_empty( &fire_chain ) ) {
- /*
- * Fire the watchdogs.
- */
- while ( true ) {
- Watchdog_Control *watchdog;
- ISR_Level level;
-
- /*
- * It is essential that interrupts are disable here since an interrupt
- * service routine may remove a watchdog from the chain.
- */
- _ISR_Disable( level );
- watchdog = (Watchdog_Control *) _Chain_Get_unprotected( &fire_chain );
- if ( watchdog != NULL ) {
- watchdog->state = WATCHDOG_INACTIVE;
- _ISR_Enable( level );
- } else {
- _ISR_Enable( level );
-
- break;
- }
+ _Timer_server_Tickle(
+ &ts->TOD_watchdogs,
+ &_Watchdog_Seconds_header,
+ _Timer_server_Get_seconds,
+ false
+ );
- _Timer_server_SMP_lock_release();
+ (void) rtems_event_system_receive(
+ RTEMS_EVENT_SYSTEM_TIMER_SERVER,
+ RTEMS_EVENT_ALL | RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT,
+ &events
+ );
+ }
+}
- /*
- * The timer server may block here and wait for resources or time.
- * The system watchdogs are inactive and will remain inactive since
- * the active flag of the timer server is true.
- */
- (*watchdog->routine)( watchdog->id, watchdog->user_data );
+static void _Timer_server_Wakeup(
+ Objects_Id id,
+ void *arg
+)
+{
+ Timer_server_Control *ts = arg;
- _Timer_server_SMP_lock_aquire();
- }
- } else {
- ts->active = false;
+ _Timer_server_Update_current_snapshot(
+ &ts->Interval_watchdogs,
+ _Timer_server_Get_ticks
+ );
- /*
- * Block until there is something to do.
- */
-#if !defined( RTEMS_SMP )
- _Thread_Disable_dispatch();
-#endif
- _Thread_Set_state( ts->thread, STATES_DELAYING );
- _Timer_server_Reset_interval_system_watchdog( ts );
- _Timer_server_Reset_tod_system_watchdog( ts );
-#if !defined( RTEMS_SMP )
- _Thread_Enable_dispatch();
-#endif
+ _Timer_server_Update_current_snapshot(
+ &ts->TOD_watchdogs,
+ _Timer_server_Get_seconds
+ );
- _Timer_server_SMP_lock_release();
- _Timer_server_SMP_lock_aquire();
+ (void) rtems_event_system_send( id, RTEMS_EVENT_SYSTEM_TIMER_SERVER );
+}
- ts->active = true;
+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;
- /*
- * Maybe an interrupt did reset the system timers, so we have to stop
- * them here. Since we are active now, there will be no more resets
- * until we are inactive again.
- */
- _Timer_server_Stop_interval_system_watchdog( ts );
- _Timer_server_Stop_tod_system_watchdog( ts );
- }
- }
+ now = (*get_ticks)();
+ watchdogs->last_snapshot = now;
+ watchdogs->current_snapshot = now;
+
+ _Watchdog_Header_initialize( &watchdogs->Header );
+ _Watchdog_Initialize(
+ &watchdogs->System_watchdog,
+ _Timer_server_Wakeup,
+ id,
+ ts
+ );
}
/**
@@ -542,36 +390,18 @@ rtems_status_code rtems_timer_initiate_server(
* Timer Server so we do not have to have a critical section.
*/
- /*
- * We work with the TCB pointer, not the ID, so we need to convert
- * to a TCB pointer from here out.
- */
- ts->thread = (Thread_Control *)_Objects_Get_local_object(
- &_RTEMS_tasks_Information,
- _Objects_Get_index(id)
+ _Timer_server_Initialize_watchdogs(
+ ts,
+ id,
+ &ts->Interval_watchdogs,
+ _Timer_server_Get_ticks
);
- /*
- * Initialize the timer lists that the server will manage.
- */
- _Watchdog_Header_initialize( &ts->Interval_watchdogs.Header );
- _Watchdog_Header_initialize( &ts->TOD_watchdogs.Header );
-
- /*
- * Initialize the timers that will be used to control when the
- * Timer Server wakes up and services the task-based timers.
- */
- _Watchdog_Initialize(
- &ts->Interval_watchdogs.System_watchdog,
- _Thread_Delay_ended,
- 0,
- ts->thread
- );
- _Watchdog_Initialize(
- &ts->TOD_watchdogs.System_watchdog,
- _Thread_Delay_ended,
- 0,
- ts->thread
+ _Timer_server_Initialize_watchdogs(
+ ts,
+ id,
+ &ts->TOD_watchdogs,
+ _Timer_server_Get_seconds
);
/*
@@ -581,12 +411,6 @@ rtems_status_code rtems_timer_initiate_server(
ts->cancel = _Timer_server_Cancel_method;
ts->schedule_operation = _Timer_server_Schedule_operation_method;
- ts->Interval_watchdogs.last_snapshot = _Watchdog_Ticks_since_boot;
- ts->TOD_watchdogs.last_snapshot = (Watchdog_Interval) _TOD_Seconds_since_epoch();
-
- ts->insert_chain = NULL;
- ts->active = false;
-
/*
* The default timer server is now available.
*/
diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am
index af7da2a..3eb2caa 100644
--- a/cpukit/score/Makefile.am
+++ b/cpukit/score/Makefile.am
@@ -324,7 +324,7 @@ 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/watchdogadjusttochain.c src/watchdoginsert.c src/watchdogremove.c
+ src/watchdoginsert.c src/watchdogremove.c
libscore_a_SOURCES += src/watchdogtickssinceboot.c
## USEREXT_C_FILES
diff --git a/cpukit/score/include/rtems/score/watchdogimpl.h b/cpukit/score/include/rtems/score/watchdogimpl.h
index dfe50e6..6804bf2 100644
--- a/cpukit/score/include/rtems/score/watchdogimpl.h
+++ b/cpukit/score/include/rtems/score/watchdogimpl.h
@@ -165,6 +165,22 @@ void _Watchdog_Adjust_backward(
);
/**
+ * @brief Adjusts the watchdogs in backward direction in a locked context.
+ *
+ * The caller must be the owner of the watchdog lock and will be the owner
+ * after the call.
+ *
+ * @param[in] header The watchdog header.
+ * @param[in] units The units of ticks to adjust.
+ *
+ * @see _Watchdog_Adjust_forward().
+ */
+void _Watchdog_Adjust_backward_locked(
+ Watchdog_Header *header,
+ Watchdog_Interval units
+);
+
+/**
* @brief Adjusts the header watchdog chain in the forward direction for units
* ticks.
*
@@ -179,24 +195,22 @@ void _Watchdog_Adjust_forward(
);
/**
- * @brief Adjusts the @a header watchdog chain in the forward
- * @a direction for @a units_arg ticks.
+ * @brief Adjusts the watchdogs in forward direction in a locked context.
*
- * This routine adjusts the @a header watchdog chain in the forward
- * @a direction for @a units_arg ticks.
+ * The caller must be the owner of the watchdog lock and will be the owner
+ * after the call. This function may release and acquire the watchdog lock
+ * internally.
*
- * @param[in] header is the watchdog chain to adjust
- * @param[in] units_arg 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.
+ * @param[in] header The watchdog header.
+ * @param[in] units The units of ticks to adjust.
+ * @param[in] lock_context The lock context.
*
- * @note This always adjusts forward.
+ * @see _Watchdog_Adjust_forward().
*/
-void _Watchdog_Adjust_to_chain(
+void _Watchdog_Adjust_forward_locked(
Watchdog_Header *header,
- Watchdog_Interval units_arg,
- Chain_Control *to_fire
-
+ Watchdog_Interval units,
+ ISR_lock_Context *lock_context
);
/**
@@ -216,6 +230,25 @@ void _Watchdog_Insert (
);
/**
+ * @brief Inserts the watchdog in a locked context.
+ *
+ * The caller must be the owner of the watchdog lock and will be the owner
+ * after the call. This function may release and acquire the watchdog lock
+ * internally.
+ *
+ * @param[in] header The watchdog header.
+ * @param[in] the_watchdog The watchdog.
+ * @param[in] lock_context The lock context.
+ *
+ * @see _Watchdog_Insert().
+ */
+void _Watchdog_Insert_locked(
+ Watchdog_Header *header,
+ Watchdog_Control *the_watchdog,
+ ISR_lock_Context *lock_context
+);
+
+/**
* @brief This routine is invoked at appropriate intervals to update
* the @a header watchdog chain.
*
diff --git a/cpukit/score/src/watchdogadjust.c b/cpukit/score/src/watchdogadjust.c
index 04fc1a5..32b5f79 100644
--- a/cpukit/score/src/watchdogadjust.c
+++ b/cpukit/score/src/watchdogadjust.c
@@ -19,26 +19,18 @@
#endif
#include <rtems/score/watchdogimpl.h>
-#include <rtems/score/chainimpl.h>
-#include <rtems/score/isrlevel.h>
-void _Watchdog_Adjust_backward(
+void _Watchdog_Adjust_backward_locked(
Watchdog_Header *header,
Watchdog_Interval units
)
{
- ISR_lock_Context lock_context;
-
- _Watchdog_Acquire( header, &lock_context );
-
if ( !_Watchdog_Is_empty( header ) ) {
_Watchdog_First( header )->delta_interval += units;
}
-
- _Watchdog_Release( header, &lock_context );
}
-void _Watchdog_Adjust_forward(
+void _Watchdog_Adjust_backward(
Watchdog_Header *header,
Watchdog_Interval units
)
@@ -46,7 +38,16 @@ void _Watchdog_Adjust_forward(
ISR_lock_Context lock_context;
_Watchdog_Acquire( header, &lock_context );
+ _Watchdog_Adjust_backward_locked( header, units );
+ _Watchdog_Release( header, &lock_context );
+}
+void _Watchdog_Adjust_forward_locked(
+ Watchdog_Header *header,
+ Watchdog_Interval units,
+ ISR_lock_Context *lock_context
+)
+{
while ( !_Watchdog_Is_empty( header ) && units > 0 ) {
Watchdog_Control *first = _Watchdog_First( header );
@@ -57,13 +58,23 @@ void _Watchdog_Adjust_forward(
units -= first->delta_interval;
first->delta_interval = 1;
- _Watchdog_Release( header, &lock_context );
+ _Watchdog_Release( header, lock_context );
_Watchdog_Tickle( header );
- _Watchdog_Acquire( header, &lock_context );
+ _Watchdog_Acquire( header, lock_context );
}
}
+}
+void _Watchdog_Adjust_forward(
+ Watchdog_Header *header,
+ Watchdog_Interval units
+)
+{
+ ISR_lock_Context lock_context;
+
+ _Watchdog_Acquire( header, &lock_context );
+ _Watchdog_Adjust_forward_locked( header, units, &lock_context );
_Watchdog_Release( header, &lock_context );
}
diff --git a/cpukit/score/src/watchdogadjusttochain.c b/cpukit/score/src/watchdogadjusttochain.c
deleted file mode 100644
index b3063e4..0000000
--- a/cpukit/score/src/watchdogadjusttochain.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * @file
- *
- * @brief Watchdog Adjust to Chain
- * @ingroup ScoreWatchdog
- */
-
-/*
- * COPYRIGHT (c) 1989-2009.
- * 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.org/license/LICENSE.
- */
-
-#if HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <rtems/score/watchdogimpl.h>
-#include <rtems/score/isrlevel.h>
-
-void _Watchdog_Adjust_to_chain(
- Watchdog_Header *header,
- Watchdog_Interval units_arg,
- Chain_Control *to_fire
-
-)
-{
- Watchdog_Interval units = units_arg;
- ISR_lock_Context lock_context;
- Watchdog_Control *first;
-
- _Watchdog_Acquire( header, &lock_context );
-
- while ( 1 ) {
- if ( _Watchdog_Is_empty( header ) ) {
- break;
- }
- first = _Watchdog_First( header );
-
- /*
- * If it is longer than "units" until the first element on the chain
- * fires, then bump it and quit.
- */
- if ( units < first->delta_interval ) {
- first->delta_interval -= units;
- break;
- }
-
- /*
- * The first set happens in less than units, so take all of them
- * off the chain and adjust units to reflect this.
- */
- units -= first->delta_interval;
- first->delta_interval = 0;
-
- while ( 1 ) {
- _Chain_Extract_unprotected( &first->Node );
- _Chain_Append_unprotected( to_fire, &first->Node );
-
- _Watchdog_Flash( header, &lock_context );
-
- if ( _Watchdog_Is_empty( header ) )
- break;
- first = _Watchdog_First( header );
- if ( first->delta_interval != 0 )
- break;
- }
- }
-
- _Watchdog_Release( header, &lock_context );
-}
-
diff --git a/cpukit/score/src/watchdoginsert.c b/cpukit/score/src/watchdoginsert.c
index 6d2df82..6b81c7b 100644
--- a/cpukit/score/src/watchdoginsert.c
+++ b/cpukit/score/src/watchdoginsert.c
@@ -47,15 +47,12 @@ static void _Watchdog_Insert_fixup(
}
}
-void _Watchdog_Insert(
+void _Watchdog_Insert_locked(
Watchdog_Header *header,
- Watchdog_Control *the_watchdog
+ Watchdog_Control *the_watchdog,
+ ISR_lock_Context *lock_context
)
{
- ISR_lock_Context lock_context;
-
- _Watchdog_Acquire( header, &lock_context );
-
if ( the_watchdog->state == WATCHDOG_INACTIVE ) {
Watchdog_Iterator iterator;
Chain_Node *current;
@@ -86,7 +83,7 @@ void _Watchdog_Insert(
iterator.delta_interval = delta - delta_next;
iterator.current = next;
- _Watchdog_Flash( header, &lock_context );
+ _Watchdog_Flash( header, lock_context );
if ( the_watchdog->state != WATCHDOG_BEING_INSERTED ) {
goto abort_insert;
@@ -105,6 +102,16 @@ abort_insert:
_Chain_Extract_unprotected( &iterator.Node );
}
+}
+void _Watchdog_Insert(
+ Watchdog_Header *header,
+ Watchdog_Control *the_watchdog
+)
+{
+ ISR_lock_Context lock_context;
+
+ _Watchdog_Acquire( header, &lock_context );
+ _Watchdog_Insert_locked( header, the_watchdog, &lock_context );
_Watchdog_Release( header, &lock_context );
}
diff --git a/testsuites/sptests/spintrcritical17/init.c b/testsuites/sptests/spintrcritical17/init.c
index 9dde48a..238493e 100644
--- a/testsuites/sptests/spintrcritical17/init.c
+++ b/testsuites/sptests/spintrcritical17/init.c
@@ -1,10 +1,11 @@
/*
- * Copyright (c) 2009
- * embedded brains GmbH
- * Obere Lagerstr. 30
- * D-82178 Puchheim
- * Germany
- * <rtems at embedded-brains.de>
+ * Copyright (c) 2009-2014 embedded brains GmbH.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems at embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -22,141 +23,91 @@
const char rtems_test_name[] = "SPINTRCRITICAL 17";
-/* forward declarations to avoid warnings */
-rtems_task Init(rtems_task_argument argument);
-
-#define TIMER_COUNT 4
-
-#define TIMER_TRIGGER 0
-#define TIMER_RESET 1
-#define TIMER_NEVER_INTERVAL 2
-#define TIMER_NEVER_TOD 3
-
-static rtems_id timer [TIMER_COUNT];
+typedef struct {
+ rtems_id timer1;
+ rtems_id timer2;
+ bool done;
+} test_context;
-static rtems_time_of_day tod;
-
-static volatile bool case_hit;
-
-static void never_callback(rtems_id timer, void *arg)
-{
- rtems_test_assert(false);
-}
+static test_context ctx_instance;
-static void reset_tod_timer(void)
+static void never(rtems_id timer_id, void *arg)
{
- rtems_status_code sc = RTEMS_SUCCESSFUL;
-
- sc = rtems_timer_server_fire_when(
- timer [TIMER_NEVER_TOD],
- &tod,
- never_callback,
- NULL
- );
- directive_failed_with_level(sc, "rtems_timer_server_fire_after", -1);
+ rtems_test_assert(0);
}
-static void reset_callback(rtems_id timer_id, void *arg)
+static void fire(rtems_id timer_id, void *arg)
{
- rtems_status_code sc = RTEMS_SUCCESSFUL;
-
- sc = rtems_timer_reset(timer [TIMER_RESET]);
- directive_failed_with_level(sc, "rtems_timer_reset", -1);
-
- sc = rtems_timer_reset(timer [TIMER_NEVER_INTERVAL]);
- directive_failed_with_level(sc, "rtems_timer_reset", -1);
-
- reset_tod_timer();
-
- if (!case_hit) {
- case_hit = _Timer_server->insert_chain != NULL;
+ /* The arg is NULL */
+ test_context *ctx = &ctx_instance;
+ rtems_status_code sc;
+
+ if (!ctx->done) {
+ ctx->done =
+ _Timer_server->Interval_watchdogs.system_watchdog_helper != NULL;
+
+ if (ctx->done) {
+ sc = rtems_timer_server_fire_after(ctx->timer2, 100, never, NULL);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+ }
}
}
-static void trigger_callback(rtems_id timer_id, void *arg)
+static bool test_body(void *arg)
{
- rtems_status_code sc = RTEMS_SUCCESSFUL;
+ test_context *ctx = arg;
+ rtems_status_code sc;
- if (case_hit) {
- TEST_END();
+ sc = rtems_timer_reset(ctx->timer1);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
- rtems_test_exit(0);
- } else if (interrupt_critical_section_test_support_delay()) {
- puts("test case not hit, give up");
-
- rtems_test_exit(0);
- }
-
- sc = rtems_timer_reset(timer [TIMER_TRIGGER]);
- directive_failed(sc, "rtems_timer_reset");
+ return ctx->done;
}
-rtems_task Init( rtems_task_argument ignored )
+static void Init(rtems_task_argument ignored)
{
- rtems_status_code sc = RTEMS_SUCCESSFUL;
- size_t i = 0;
+ test_context *ctx = &ctx_instance;
+ rtems_status_code sc;
TEST_BEGIN();
- build_time(&tod, 4, 12, 2009, 9, 34, 11, 0);
- sc = rtems_clock_set(&tod);
- directive_failed(sc, "rtems_clock_set");
-
- ++tod.year;
+ sc = rtems_timer_create(
+ rtems_build_name('T', 'I', 'M', '1'),
+ &ctx->timer1
+ );
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
- for (i = 0; i < TIMER_COUNT; ++i) {
- sc = rtems_timer_create(
- rtems_build_name('T', 'I', 'M', '0' + i),
- &timer [i]
- );
- directive_failed(sc, "rtems_timer_create");
- }
+ sc = rtems_timer_create(
+ rtems_build_name('T', 'I', 'M', '2'),
+ &ctx->timer2
+ );
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_timer_initiate_server(
RTEMS_MINIMUM_PRIORITY,
RTEMS_MINIMUM_STACK_SIZE,
RTEMS_DEFAULT_ATTRIBUTES
);
- directive_failed(sc, "rtems_timer_initiate_server");
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
- sc = rtems_timer_server_fire_after(
- timer [TIMER_NEVER_INTERVAL],
- 2,
- never_callback,
- NULL
- );
- directive_failed(sc, "rtems_timer_server_fire_after");
-
- reset_tod_timer();
-
- sc = rtems_timer_fire_after(
- timer [TIMER_RESET],
- 1,
- reset_callback,
- NULL
- );
- directive_failed(sc, "rtems_timer_fire_after");
-
- sc = rtems_timer_server_fire_after(
- timer [TIMER_TRIGGER],
- 1,
- trigger_callback,
- NULL
- );
- directive_failed(sc, "rtems_timer_server_fire_after");
+ sc = rtems_timer_server_fire_after(ctx->timer1, 1000, never, NULL);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
- interrupt_critical_section_test_support_initialize(NULL);
+ interrupt_critical_section_test(test_body, ctx, fire);
+ rtems_test_assert(ctx->done);
- rtems_task_delete(RTEMS_SELF);
+ TEST_END();
+ rtems_test_exit(0);
}
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
-#define CONFIGURE_MICROSECONDS_PER_TICK 2000
+#define CONFIGURE_MICROSECONDS_PER_TICK 1000
#define CONFIGURE_MAXIMUM_TASKS 2
-#define CONFIGURE_MAXIMUM_TIMERS 4
+#define CONFIGURE_MAXIMUM_TIMERS 3
+#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
diff --git a/testsuites/sptests/spintrcritical17/spintrcritical17.doc b/testsuites/sptests/spintrcritical17/spintrcritical17.doc
index 3be8e60..809a966 100644
--- a/testsuites/sptests/spintrcritical17/spintrcritical17.doc
+++ b/testsuites/sptests/spintrcritical17/spintrcritical17.doc
@@ -1,4 +1,4 @@
-# Copyright (c) 2009 embedded brains GmbH.
+# Copyright (c) 2009-2015 embedded brains GmbH.
#
# The license and distribution terms for this file may be
# found in the file LICENSE in this distribution or at
@@ -11,9 +11,7 @@ test set name: spintrcritical17
directives:
- _Timer_server_Get_watchdogs_that_fire_now
- _Timer_server_Schedule_operation_method
- _Timer_server_Process_insertions
+ _Timer_server_Update_system_watchdog
concepts:
--
1.8.4.5
More information about the devel
mailing list