summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 ***