[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