summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Sherrill <joel@rtems.org>2019-11-12 09:33:41 -0600
committerJoel Sherrill <joel@rtems.org>2019-12-11 15:22:33 -0600
commit08bd7d36cee1b041d54ee9dbace86a1b810938af (patch)
tree18de7bd20167d7430c82810d375534c56dfedb91
parentpipe: Use condition variables (diff)
downloadrtems-08bd7d36cee1b041d54ee9dbace86a1b810938af.tar.bz2
Add TOD Hooks to allow BSP to take action when TOD is set
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.
-rw-r--r--cpukit/Makefile.am4
-rw-r--r--cpukit/include/rtems/score/timecounter.h10
-rw-r--r--cpukit/include/rtems/score/todimpl.h107
-rw-r--r--cpukit/posix/src/clocksettime.c16
-rw-r--r--cpukit/rtems/src/clockset.c9
-rw-r--r--cpukit/score/src/coretodhookdata.c45
-rw-r--r--cpukit/score/src/coretodhookregister.c61
-rw-r--r--cpukit/score/src/coretodhookrun.c72
-rw-r--r--cpukit/score/src/coretodhookunregister.c60
-rw-r--r--cpukit/score/src/coretodset.c11
-rw-r--r--testsuites/sptests/Makefile.am9
-rw-r--r--testsuites/sptests/configure.ac1
-rw-r--r--testsuites/sptests/spclock_todhook01/init.c330
-rw-r--r--testsuites/sptests/spclock_todhook01/spclock_todhook01.doc35
-rw-r--r--testsuites/sptests/spclock_todhook01/spclock_todhook01.scn2
15 files changed, 764 insertions, 8 deletions
diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 71daca821a..0b0bede2ad 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 78f5dfa53b..b71ccd3948 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 0d4faac6b2..5287c976f5 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 a0fdd9109f..bfae46feee 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 d77268211b..a885fe1169 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 0000000000..6e7bcff494
--- /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 0000000000..69996a2b06
--- /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 0000000000..ae9cf66dfc
--- /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 0000000000..ce978e8e81
--- /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 b021a58dc6..94ecd0b322 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 09751b6d58..f127c2b2e8 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 467d2417f5..d8816d80f0 100644
--- a/testsuites/sptests/configure.ac
+++ b/testsuites/sptests/configure.ac
@@ -116,6 +116,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 0000000000..26f0ff9b48
--- /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 0000000000..0be564edb6
--- /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 0000000000..b54c10e317
--- /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 ***