[PATCH v3] Add TOD Hooks to allow BSP to take action when TOD is set

Joel Sherrill joel at rtems.org
Mon Dec 9 15:32:55 UTC 2019


Two use cases were envisioned for this.

1) a BSP or application which desires to update a real-time clock
   when the RTEMS TOD is set.

2) a paravirtualized BSP can use this to propagate setting the time
   in an RTEMS application to the hosting environment. This enables
   the entire set of applications in the virtualized environments
   to have a single consistent TOD.
---
 cpukit/Makefile.am                                 |   4 +
 cpukit/include/rtems/score/timecounter.h           |  10 +
 cpukit/include/rtems/score/todimpl.h               | 107 ++++++-
 cpukit/posix/src/clocksettime.c                    |  16 +-
 cpukit/rtems/src/clockset.c                        |   9 +-
 cpukit/score/src/coretodhookdata.c                 |  45 +++
 cpukit/score/src/coretodhookregister.c             |  61 ++++
 cpukit/score/src/coretodhookrun.c                  |  72 +++++
 cpukit/score/src/coretodhookunregister.c           |  60 ++++
 cpukit/score/src/coretodset.c                      |  11 +-
 testsuites/sptests/Makefile.am                     |   9 +
 testsuites/sptests/configure.ac                    |   1 +
 testsuites/sptests/spclock_todhook01/init.c        | 330 +++++++++++++++++++++
 .../spclock_todhook01/spclock_todhook01.doc        |  35 +++
 .../spclock_todhook01/spclock_todhook01.scn        |   2 +
 15 files changed, 764 insertions(+), 8 deletions(-)
 create mode 100644 cpukit/score/src/coretodhookdata.c
 create mode 100644 cpukit/score/src/coretodhookregister.c
 create mode 100644 cpukit/score/src/coretodhookrun.c
 create mode 100644 cpukit/score/src/coretodhookunregister.c
 create mode 100644 testsuites/sptests/spclock_todhook01/init.c
 create mode 100644 testsuites/sptests/spclock_todhook01/spclock_todhook01.doc
 create mode 100644 testsuites/sptests/spclock_todhook01/spclock_todhook01.scn

diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 71daca8..0b0bede 100644
--- a/cpukit/Makefile.am
+++ b/cpukit/Makefile.am
@@ -982,6 +982,10 @@ librtemscpu_a_SOURCES += score/src/coretodset.c
 librtemscpu_a_SOURCES += score/src/coretodtickspersec.c
 librtemscpu_a_SOURCES += score/src/coretodadjust.c
 librtemscpu_a_SOURCES += score/src/watchdoginsert.c
+librtemscpu_a_SOURCES += score/src/coretodhookdata.c
+librtemscpu_a_SOURCES += score/src/coretodhookregister.c
+librtemscpu_a_SOURCES += score/src/coretodhookrun.c
+librtemscpu_a_SOURCES += score/src/coretodhookunregister.c
 librtemscpu_a_SOURCES += score/src/watchdogremove.c
 librtemscpu_a_SOURCES += score/src/watchdogtick.c
 librtemscpu_a_SOURCES += score/src/watchdogtickssinceboot.c
diff --git a/cpukit/include/rtems/score/timecounter.h b/cpukit/include/rtems/score/timecounter.h
index 78f5dfa..b71ccd3 100644
--- a/cpukit/include/rtems/score/timecounter.h
+++ b/cpukit/include/rtems/score/timecounter.h
@@ -202,6 +202,16 @@ ISR_LOCK_DECLARE( extern, _Timecounter_Lock )
   _ISR_lock_ISR_disable_and_acquire( &_Timecounter_Lock, lock_context )
 
 /**
+ * @brief Releases the timecounter lock.
+ *
+ * @param lock_context The lock context.
+ *
+ * See _Timecounter_Tick_simple().
+ */
+#define _Timecounter_Release(lock_context) \
+   _ISR_lock_Release_and_ISR_enable(&_Timecounter_Lock, lock_context)
+
+/**
  * @brief Performs a simple timecounter tick.
  *
  * This is a special purpose tick function for simple timecounter to support
diff --git a/cpukit/include/rtems/score/todimpl.h b/cpukit/include/rtems/score/todimpl.h
index 0d4faac..5287c97 100644
--- a/cpukit/include/rtems/score/todimpl.h
+++ b/cpukit/include/rtems/score/todimpl.h
@@ -141,6 +141,9 @@ typedef struct {
   bool is_set;
 } TOD_Control;
 
+/**
+ * @brief TOD Management information
+ */
 extern TOD_Control _TOD;
 
 /**
@@ -174,6 +177,16 @@ static inline void _TOD_Acquire( ISR_lock_Context *lock_context )
 }
 
 /**
+ * @brief Releases the lock context for the timecounter.
+ *
+ * @param lock_context The lock to release.
+ */
+static inline void _TOD_Release( ISR_lock_Context *lock_context )
+{
+  _Timecounter_Release( lock_context );
+}
+
+/**
  * @brief Sets the time of day.
  *
  * The caller must be the owner of the TOD lock.
@@ -183,8 +196,11 @@ static inline void _TOD_Acquire( ISR_lock_Context *lock_context )
  * @param lock_context The ISR lock context used for the corresponding
  *   _TOD_Acquire().  The caller must be the owner of the TOD lock.  This
  *   function will release the TOD lock.
+ *
+ * @retval true on success
+ * @retval false on failure
  */
-void _TOD_Set(
+bool _TOD_Set(
   const struct timespec *tod,
   ISR_lock_Context      *lock_context
 );
@@ -320,6 +336,95 @@ RTEMS_INLINE_ROUTINE bool _TOD_Is_set( void )
 
 /** @} */
 
+/**
+ * @defgroup RTEMSScoreTODHooks Time of Day Handler Action Hooks
+ *
+ * @ingroup RTEMSScoreTOD
+ *
+ * @brief Time of Day Handler Action Hooks
+ *
+ * The following support registering a hook which is invoked
+ * when the TOD is set. These can be used by a paravirtualized
+ * BSP to mirror time changes to the hosting environment or a
+ * regular BSP to program a real-time clock when the RTEMS TOD
+ * is set.
+ *
+ * @{
+ */
+
+/**
+ *  @brief Possible actions where a registered hook could be invoked
+ */
+typedef enum {
+  /**
+   *  @brief Constant to indicate the TOD is being set.
+   */
+  TOD_ACTION_SET_CLOCK
+} TOD_Action;
+
+/**
+ * @brief Structure to manage each TOD action hook
+ */
+typedef struct TOD_Hook {
+  /** This is the chain node portion of an object. */
+  Chain_Node Node;
+
+  /** This is the TOD action hook that is invoked. */
+  bool (*handler)(TOD_Action, const struct timespec *);
+} TOD_Hook;
+
+/**
+ * @brief Set of registered methods for TOD Actions
+ */
+extern Chain_Control _TOD_Hooks;
+
+/**
+ * @brief Add a TOD Action Hook
+ *
+ * This method is used to add a hook to the TOD action set.
+ *
+ * @brief hook is the action hook to register.
+ *
+ * @retval true if the hook is added. 
+ * @retval false if the hook cannot be added. 
+ */
+void _TOD_Hook_Register(
+  TOD_Hook *hook
+);
+
+/**
+ * @brief Remove a TOD Action Hook
+ *
+ * This method is used to remove a hook from the TOD action set.
+ *
+ * @brief hook is the action hook to unregister.
+ *
+ * @retval true if the hook is unregister. 
+ * @retval false if the hook cannot be unregister. 
+ */
+void _TOD_Hook_Unregister(
+  TOD_Hook *hook
+);
+
+/**
+ * @brief Run the TOD Action Hooks
+ *
+ * This method is used to invoke the set of TOD action hooks.
+ *
+ * @brief action is the action which triggered this run.
+ * @brief tod is the current tod
+ *
+ * @retval true if the hooks can be run. 
+ * @retval false if the hook cannot be run. 
+ */
+bool _TOD_Hook_Run(
+  TOD_Action             action,
+  const struct timespec *tod
+);
+
+
+/** @} */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/cpukit/posix/src/clocksettime.c b/cpukit/posix/src/clocksettime.c
index a0fdd91..bfae46f 100644
--- a/cpukit/posix/src/clocksettime.c
+++ b/cpukit/posix/src/clocksettime.c
@@ -32,6 +32,8 @@ int clock_settime(
   const struct timespec *tp
 )
 {
+  bool  retval;
+
   if ( !tp )
     rtems_set_errno_and_return_minus_one( EINVAL );
 
@@ -43,19 +45,25 @@ int clock_settime(
 
     _TOD_Lock();
     _TOD_Acquire( &lock_context );
-    _TOD_Set( tp, &lock_context );
+      retval = _TOD_Set( tp, &lock_context );
     _TOD_Unlock();
+    if ( retval == false ) {
+      rtems_set_errno_and_return_minus_one( EPERM );
+    }
   }
 #ifdef _POSIX_CPUTIME
-  else if ( clock_id == CLOCK_PROCESS_CPUTIME_ID )
+  else if ( clock_id == CLOCK_PROCESS_CPUTIME_ID ) {
     rtems_set_errno_and_return_minus_one( ENOSYS );
+  }
 #endif
 #ifdef _POSIX_THREAD_CPUTIME
-  else if ( clock_id == CLOCK_THREAD_CPUTIME_ID )
+  else if ( clock_id == CLOCK_THREAD_CPUTIME_ID ) {
     rtems_set_errno_and_return_minus_one( ENOSYS );
+  }
 #endif
-  else
+  else {
     rtems_set_errno_and_return_minus_one( EINVAL );
+  }
 
   return 0;
 }
diff --git a/cpukit/rtems/src/clockset.c b/cpukit/rtems/src/clockset.c
index d772682..a885fe1 100644
--- a/cpukit/rtems/src/clockset.c
+++ b/cpukit/rtems/src/clockset.c
@@ -26,6 +26,8 @@ rtems_status_code rtems_clock_set(
   const rtems_time_of_day *tod
 )
 {
+  bool retval;
+
   if ( !tod )
     return RTEMS_INVALID_ADDRESS;
 
@@ -39,10 +41,13 @@ rtems_status_code rtems_clock_set(
 
     _TOD_Lock();
     _TOD_Acquire( &lock_context );
-    _TOD_Set( &tod_as_timespec, &lock_context );
+    retval = _TOD_Set( &tod_as_timespec, &lock_context );
     _TOD_Unlock();
 
-    return RTEMS_SUCCESSFUL;
+    if ( retval == true ) {
+      return RTEMS_SUCCESSFUL;
+    }
+    return RTEMS_IO_ERROR;
   }
 
   return RTEMS_INVALID_CLOCK;
diff --git a/cpukit/score/src/coretodhookdata.c b/cpukit/score/src/coretodhookdata.c
new file mode 100644
index 0000000..6e7bcff
--- /dev/null
+++ b/cpukit/score/src/coretodhookdata.c
@@ -0,0 +1,45 @@
+/**
+ * @file
+ *
+ * @brief TOD Hook Set
+ *
+ * @ingroup RTEMSScoreTODHooks
+ */
+
+/*
+ *  SPDX-License-Identifier: BSD-2-Clause
+ *
+ *  COPYRIGHT (c) 2019.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/score/todimpl.h>
+#include <rtems/score/chainimpl.h>
+ 
+Chain_Control _TOD_Hooks = CHAIN_INITIALIZER_EMPTY(_TOD_Hooks);
+
diff --git a/cpukit/score/src/coretodhookregister.c b/cpukit/score/src/coretodhookregister.c
new file mode 100644
index 0000000..69996a2
--- /dev/null
+++ b/cpukit/score/src/coretodhookregister.c
@@ -0,0 +1,61 @@
+/**
+ * @file
+ *
+ * @brief Register Hook to be in TOD Hook Set
+ *
+ * @ingroup RTEMSScoreTODHooks
+ */
+
+/*
+ *  SPDX-License-Identifier: BSD-2-Clause
+ *
+ *  COPYRIGHT (c) 2019.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/score/todimpl.h>
+#include <rtems/score/chainimpl.h>
+ 
+void _TOD_Hook_Register(
+  TOD_Hook *hook
+)
+{
+  /*
+   * At this time, this method does NOT have a Classic or POSIX API
+   * that exports it. Any use of this method will be a direct call.
+   * It should only be called while NOT holding the TOD lock. 
+   */
+  _Assert( !_TOD_Is_owner() );
+
+  _Assert( hook != NULL );
+
+  _TOD_Lock();
+  _Chain_Append_unprotected( &_TOD_Hooks, &hook->Node );
+  _TOD_Unlock();
+}
+
diff --git a/cpukit/score/src/coretodhookrun.c b/cpukit/score/src/coretodhookrun.c
new file mode 100644
index 0000000..ae9cf66
--- /dev/null
+++ b/cpukit/score/src/coretodhookrun.c
@@ -0,0 +1,72 @@
+/**
+ * @file
+ *
+ * @brief Run TOD Hook Set
+ *
+ * @ingroup RTEMSScoreTODHooks
+ */
+
+/*
+ *  SPDX-License-Identifier: BSD-2-Clause
+ *
+ *  COPYRIGHT (c) 2019.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/score/todimpl.h>
+#include <rtems/score/assert.h>
+#include <rtems/score/chainimpl.h>
+
+bool _TOD_Hook_Run(
+  TOD_Action             action,
+  const struct timespec *tod
+)
+{
+  Chain_Node        *the_node;
+  bool               retval = true;
+
+  /*
+   * This is assumed to be called only from _TOD_Set() which is supposed
+   * to be called only while holding the TOD lock. 
+   */
+  _Assert( _TOD_Is_owner() );
+
+  for ( the_node = _Chain_First( &_TOD_Hooks );
+        !_Chain_Is_tail( &_TOD_Hooks, the_node ) ;
+        the_node = the_node->next ) {
+    TOD_Hook *the_hook = (TOD_Hook *) the_node;
+ 
+    retval = (the_hook->handler)( action, tod );
+    if ( retval == false ) {
+      break;
+    }
+  }
+
+  return retval;
+}
+
diff --git a/cpukit/score/src/coretodhookunregister.c b/cpukit/score/src/coretodhookunregister.c
new file mode 100644
index 0000000..ce978e8
--- /dev/null
+++ b/cpukit/score/src/coretodhookunregister.c
@@ -0,0 +1,60 @@
+/**
+ * @file
+ *
+ * @brief Remove Hook from TOD Hook Set
+ *
+ * @ingroup RTEMSScoreTODHooks
+ */
+
+/*
+ *  SPDX-License-Identifier: BSD-2-Clause
+ *
+ *  COPYRIGHT (c) 2019.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/score/todimpl.h>
+#include <rtems/score/chainimpl.h>
+ 
+void _TOD_Hook_Unregister(
+  TOD_Hook *hook
+)
+{
+  /*
+   * At this time, this method does NOT have a Classic or POSIX API
+   * that exports it. Any use of this method will be a direct call.
+   * It should only be called while NOT holding the TOD lock. 
+   */
+  _Assert( !_TOD_Is_owner() );
+
+  _Assert( hook != NULL );
+
+  _TOD_Lock();
+  _Chain_Extract_unprotected( &hook->Node );
+  _TOD_Unlock();
+}
diff --git a/cpukit/score/src/coretodset.c b/cpukit/score/src/coretodset.c
index b021a58..94ecd0b 100644
--- a/cpukit/score/src/coretodset.c
+++ b/cpukit/score/src/coretodset.c
@@ -22,7 +22,7 @@
 #include <rtems/score/assert.h>
 #include <rtems/score/watchdogimpl.h>
 
-void _TOD_Set(
+bool _TOD_Set(
   const struct timespec *tod,
   ISR_lock_Context      *lock_context
 )
@@ -31,9 +31,16 @@ void _TOD_Set(
   uint64_t        tod_as_ticks;
   uint32_t        cpu_max;
   uint32_t        cpu_index;
+  bool            retval;
 
   _Assert( _TOD_Is_owner() );
 
+  retval = _TOD_Hook_Run( TOD_ACTION_SET_CLOCK, tod );
+  if ( retval == false ) {
+    _TOD_Release( lock_context );
+    return false;
+  }
+
   timespec2bintime( tod, &tod_as_bintime );
   _Timecounter_Set_clock( &tod_as_bintime, lock_context );
 
@@ -67,4 +74,6 @@ void _TOD_Set(
   }
 
   _TOD.is_set = true;
+
+  return true;
 }
diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am
index 09751b6..f127c2b 100644
--- a/testsuites/sptests/Makefile.am
+++ b/testsuites/sptests/Makefile.am
@@ -707,6 +707,15 @@ spclock_err02_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_spclock_err02) \
 	$(support_includes)
 endif
 
+if TEST_spclock_todhook01
+sp_tests += spclock_todhook01
+sp_screens += spclock_todhook01/spclock_todhook01.scn
+sp_docs += spclock_todhook01/spclock_todhook01.doc
+spclock_todhook01_SOURCES = spclock_todhook01/init.c
+spclock_todhook01_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_spclock_todhook01) \
+	$(support_includes)
+endif
+
 if TEST_spconfig01
 sp_tests += spconfig01
 sp_screens += spconfig01/spconfig01.scn
diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac
index 3222196..2ad0c61 100644
--- a/testsuites/sptests/configure.ac
+++ b/testsuites/sptests/configure.ac
@@ -117,6 +117,7 @@ RTEMS_TEST_CHECK([spcbssched03])
 RTEMS_TEST_CHECK([spchain])
 RTEMS_TEST_CHECK([spclock_err01])
 RTEMS_TEST_CHECK([spclock_err02])
+RTEMS_TEST_CHECK([spclock_todhook01])
 RTEMS_TEST_CHECK([spconfig01])
 RTEMS_TEST_CHECK([spconfig02])
 RTEMS_TEST_CHECK([spconsole01])
diff --git a/testsuites/sptests/spclock_todhook01/init.c b/testsuites/sptests/spclock_todhook01/init.c
new file mode 100644
index 0000000..26f0ff9
--- /dev/null
+++ b/testsuites/sptests/spclock_todhook01/init.c
@@ -0,0 +1,330 @@
+/**
+ * @file
+ *
+ * @brief Test TOD Set Hook
+ *
+ * @ingroup sptests
+ */
+
+/*
+ *  SPDX-License-Identifier: BSD-2-Clause
+ *
+ *  COPYRIGHT (c) 2019.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <rtems.h>
+#include <rtems/score/todimpl.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+#include "tmacros.h"
+
+/* #define TEST_DEBUG */
+
+const char rtems_test_name[] = "SPCLOCK TOD HOOK 1";
+
+typedef struct test_case {
+  bool       do_settime; 
+  bool       use_posix; 
+  bool       do_hook1; 
+  bool       do_hook2; 
+  struct tm  tm;
+} testcase_t;
+
+testcase_t Cases[] = {
+  /* should not trigger hooks when time not set */
+  { false, false, false, false, { 0, 0, 9, 31, 11, 88 } },
+  { false, false, true,  true,  { 0, 0, 9, 24, 5,  95 }  },
+  /* should trigger hook when time is set with Classic API rtems_clock_set */
+  { true,  false, false, false, { 0, 0, 9, 24, 5,   95 }  },
+  { true,  false, false, false, { 0, 0, 9, 31, 11,  88 }  },
+  { true,  false, true,  false, { 0, 0, 9, 31, 11,  88 }  },
+  { true,  false, true,  true,  { 0, 0, 9, 24, 5,  105 }  },
+  /* should trigger hook when time is set with POSIX API clock_settime */
+  { true,  true,  false, false, { 0, 0, 9, 24, 5,   95 }  },
+  { true,  true,  false, false, { 0, 9, 6, 14, 2,  114 }  },
+  { true,  true,  true,  false, { 0, 0, 9, 31, 11,  88 }  },
+  { true,  true,  true,  true,  { 0, 0, 9, 24, 5,  105 }  },
+};
+
+#define NUM_CASES (sizeof(Cases)/sizeof(testcase_t))
+
+static struct timespec tod_set;
+
+static bool hook1_executed;
+static bool hook2_executed;
+
+static bool tod_hook1(
+  TOD_Action             action,
+  const struct timespec *tod
+)
+{
+  rtems_test_assert( action == TOD_ACTION_SET_CLOCK );
+
+  rtems_test_assert( tod->tv_sec == tod_set.tv_sec );
+  rtems_test_assert( tod->tv_nsec == tod_set.tv_nsec );
+
+  hook1_executed = true;
+
+  return true;
+}
+
+static bool tod_hook2(
+  TOD_Action             action,
+  const struct timespec *tod
+)
+{
+  rtems_test_assert( action == TOD_ACTION_SET_CLOCK );
+
+  rtems_test_assert( tod->tv_sec == tod_set.tv_sec );
+  rtems_test_assert( tod->tv_nsec == tod_set.tv_nsec );
+
+  hook2_executed = true;
+
+  return true;
+}
+
+/*
+ * Execute one positive test case.
+ *
+ * Assume no hooks registered at begining. Unregister if needed at the end.
+ */
+static void do_positive_case(int i)
+{
+  testcase_t  *testcase = &Cases[i];
+  TOD_Hook     hook1;
+  TOD_Hook     hook2;
+
+  #ifdef TEST_DEBUG
+    printf(
+      "%d: do_settime=%d use_posix=%d do_hook1=%d do_hook2=%d\n",
+      i,
+      testcase->do_settime,
+      testcase->use_posix,
+      testcase->do_hook1,
+      testcase->do_hook2
+    );
+  #endif
+
+  _Chain_Initialize_node( &hook1.Node );
+  hook1.handler = tod_hook1;
+
+  _Chain_Initialize_node( &hook2.Node );
+  hook2.handler = tod_hook2;
+
+  hook1_executed = false;
+  hook2_executed = false;
+
+  /*
+   * Register the TOD Hooks
+   */
+  if ( testcase->do_hook1 == true ) {
+    _TOD_Hook_Register( &hook1 );
+  }
+
+  if ( testcase->do_hook2 == true ) {
+    _TOD_Hook_Register( &hook2 );
+  }
+
+  /*
+   * Now set the time and if registered, let the handlers fire
+   */
+  if ( testcase->do_settime == true ) {
+    rtems_time_of_day   time;
+    rtems_status_code   status;
+    struct tm          *tm = &testcase->tm;
+
+    tod_set.tv_sec = mktime( tm );
+    tod_set.tv_nsec = 0;
+
+    if ( testcase->use_posix == false ) {
+      build_time(
+        &time,
+        tm->tm_mon + 1,
+        tm->tm_mday,
+        tm->tm_year + 1900,
+        tm->tm_hour,
+        tm->tm_min,
+        0,
+        0
+      );
+      status = rtems_clock_set( &time );
+      directive_failed( status, "rtems_clock_set" );
+    } else {
+      int rc;
+
+      rc = clock_settime( CLOCK_REALTIME, &tod_set );
+      rtems_test_assert( rc == 0 ); 
+    }
+  }
+
+  /*
+   * Unregister the TOD hooks 
+   */
+  if ( testcase->do_hook1 == true ) {
+    _TOD_Hook_Unregister( &hook1 );
+  }
+
+  if ( testcase->do_hook2 == true ) {
+    _TOD_Hook_Unregister( &hook2 );
+  }
+
+  #ifdef TEST_DEBUG
+    printf(
+      "    hook1_executed=%d hook2_executed=%d\n",
+      hook1_executed,
+      hook2_executed
+    );
+  #endif
+
+  /*
+   * Check expected results
+   */
+  if ( testcase->do_hook1 == true ) {
+    rtems_test_assert( testcase->do_settime == hook1_executed );
+  } else {
+    rtems_test_assert( hook1_executed == false );
+  }
+
+  if ( testcase->do_hook2 == true ) {
+    rtems_test_assert( testcase->do_settime == hook2_executed );
+  } else {
+    rtems_test_assert( hook2_executed == false );
+  }
+}
+
+static bool hook_error_executed;
+
+static bool tod_hook_error(
+  TOD_Action             action,
+  const struct timespec *tod
+)
+{
+  rtems_test_assert( action == TOD_ACTION_SET_CLOCK );
+
+  rtems_test_assert( tod->tv_sec == tod_set.tv_sec );
+  rtems_test_assert( tod->tv_nsec == tod_set.tv_nsec );
+
+  hook_error_executed = true;
+
+  return false;
+}
+/*
+ * Execute one negative test case.
+ *
+ * Assume no hooks registered at begining. Unregister if needed at the end.
+ */
+static void do_negative_case(bool use_posix)
+{
+  TOD_Hook            hook_error;
+  rtems_time_of_day   time;
+  rtems_status_code   status;
+  struct tm          *tm = &Cases[0].tm;
+
+
+  _Chain_Initialize_node( &hook_error.Node );
+  hook_error.handler = tod_hook_error;
+
+  hook_error_executed = false;
+
+  /*
+   * Register the TOD Hooks
+   */
+  _TOD_Hook_Register( &hook_error );
+
+  /*
+   * Now set the time and if registered, let the handlers fire
+   */
+  tod_set.tv_sec = mktime( tm );
+  tod_set.tv_nsec = 0;
+
+  if ( use_posix == false ) {
+    build_time(
+      &time,
+      tm->tm_mon + 1,
+      tm->tm_mday,
+      tm->tm_year + 1900,
+      tm->tm_hour,
+      tm->tm_min,
+      0,
+      0
+    );
+    status = rtems_clock_set( &time );
+    rtems_test_assert( status == RTEMS_IO_ERROR );
+  } else {
+    int rc;
+
+    rc = clock_settime( CLOCK_REALTIME, &tod_set );
+    rtems_test_assert( rc == -1 ); 
+    rtems_test_assert( errno == EPERM ); 
+  }
+
+  /*
+   * Unregister the TOD hooks 
+   */
+  _TOD_Hook_Unregister( &hook_error );
+
+  /*
+   * Check expected results
+   */
+  rtems_test_assert( hook_error_executed == true );
+}
+
+
+static rtems_task Init(rtems_task_argument ignored)
+{
+  // rtems_status_code status;
+  int               i;
+
+  TEST_BEGIN();
+
+  // test positive cases
+  for (i=0 ; i < NUM_CASES ; i++) {
+    do_positive_case( i );
+  }
+
+  // test error cases
+  do_negative_case(false);
+  do_negative_case(true);
+
+  TEST_END();
+
+  rtems_test_exit(0);
+}
+
+/* configuration information */
+#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+
+#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+#define CONFIGURE_MAXIMUM_TASKS 1
+
+#define CONFIGURE_INIT
+#include <rtems/confdefs.h>
+
diff --git a/testsuites/sptests/spclock_todhook01/spclock_todhook01.doc b/testsuites/sptests/spclock_todhook01/spclock_todhook01.doc
new file mode 100644
index 0000000..0be564e
--- /dev/null
+++ b/testsuites/sptests/spclock_todhook01/spclock_todhook01.doc
@@ -0,0 +1,35 @@
+#  COPYRIGHT (c) 1989-2014.
+#  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.com/license/LICENSE.
+#
+
+
+This file describes the directives and concepts tested by this test set.
+
+test set name:  spclock_todhook01
+
+directives:
+  _TOD_Hook_Register
+  _TOD_Hook_Unregister
+  rtems_clock_set 
+  clock_settime 
+  
+
+concepts:
+
+- Verifies that TOD Hooks can be registered
+
+- Verifies that TOD Hooks can be unregistered
+
+- Verifies that an empty TOD Hooks set is properly processed when the TOD is set
+
+- Verifies that TOD Hooks are executed when the TOD is set
+
+- Verifies that a TOD Hook returning an error is properly reported by
+  rtems_clock_set
+
+- Verifies that a TOD Hook returning an error is properly reported by
+  clock_settime
diff --git a/testsuites/sptests/spclock_todhook01/spclock_todhook01.scn b/testsuites/sptests/spclock_todhook01/spclock_todhook01.scn
new file mode 100644
index 0000000..b54c10e
--- /dev/null
+++ b/testsuites/sptests/spclock_todhook01/spclock_todhook01.scn
@@ -0,0 +1,2 @@
+*** BEGIN OF TEST SPCLOCK TOD HOOK 1 ***
+*** END OF TEST SPCLOCK TOD HOOK 1 ***
-- 
1.8.3.1



More information about the devel mailing list