From 7eb4fc8d4331d3c1423c9d0b573141e70022cf11 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 9 Dec 2021 16:19:41 +0100 Subject: validation: Test timecounter The test source code is generated from specification items by the "./spec2modules.py" script contained in the git://git.rtems.org/rtems-central.git Git repository. Please read the "How-To" section in the "Software Requirements Engineering" chapter of the RTEMS Software Engineering manual to get more information about the process. Update #3716. --- testsuites/validation/tc-timecounter-get-smp.c | 741 +++++++++++++ testsuites/validation/tc-timecounter-get.c | 575 ++++++++++ testsuites/validation/tc-timecounter-install.c | 1134 ++++++++++++++++++++ .../validation/ts-validation-timecounter-0.c | 77 ++ .../validation/ts-validation-timecounter-1.c | 75 ++ .../validation/ts-validation-timecounter-smp-0.c | 77 ++ 6 files changed, 2679 insertions(+) create mode 100644 testsuites/validation/tc-timecounter-get-smp.c create mode 100644 testsuites/validation/tc-timecounter-get.c create mode 100644 testsuites/validation/tc-timecounter-install.c create mode 100644 testsuites/validation/ts-validation-timecounter-0.c create mode 100644 testsuites/validation/ts-validation-timecounter-1.c create mode 100644 testsuites/validation/ts-validation-timecounter-smp-0.c (limited to 'testsuites/validation') diff --git a/testsuites/validation/tc-timecounter-get-smp.c b/testsuites/validation/tc-timecounter-get-smp.c new file mode 100644 index 0000000000..520d532c7b --- /dev/null +++ b/testsuites/validation/tc-timecounter-get-smp.c @@ -0,0 +1,741 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTestCaseScoreTimecounterValGetSmp + */ + +/* + * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) + * + * 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. + */ + +/* + * This file is part of the RTEMS quality process and was automatically + * generated. If you find something that needs to be fixed or + * worded better please post a report or patch to an RTEMS mailing list + * or raise a bug report: + * + * https://www.rtems.org/bugs.html + * + * For information on updating and regenerating please refer to the How-To + * section in the Software Requirements Engineering chapter of the + * RTEMS Software Engineering manual. The manual is provided as a part of + * a release. For development sources please refer to the online + * documentation at: + * + * https://docs.rtems.org + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "tx-support.h" + +#include + +/** + * @defgroup RTEMSTestCaseScoreTimecounterValGetSmp \ + * spec:/score/timecounter/val/get-smp + * + * @ingroup RTEMSTestSuiteTestsuitesValidationTimecounterSmp0 + * + * @brief Tests directives to get a time value. + * + * This test case performs the following actions: + * + * - Install timecounter of different quality levels and frequencies. + * + * - Call the rtems_clock_get_realtime() directive and let it observe a + * generation number of zero as well as a generation number change. + * + * - Call the rtems_clock_get_realtime_bintime() directive and let it observe + * a generation number of zero as well as a generation number change. + * + * - Call the rtems_clock_get_realtime_timeval() directive and let it observe + * a generation number of zero as well as a generation number change. + * + * - Call the rtems_clock_get_monotonic() directive and let it observe a + * generation number of zero as well as a generation number change. + * + * - Call the rtems_clock_get_monotonic_bintime() directive and let it + * observe a generation number of zero as well as a generation number + * change. + * + * - Call the rtems_clock_get_monotonic_sbintime() directive and let it + * observe a generation number of zero as well as a generation number + * change. + * + * - Call the rtems_clock_get_monotonic_timeval() directive and let it + * observe a generation number of zero as well as a generation number + * change. + * + * - Delete the synchronous worker task. Reinitialize the barrier and + * barrier states. Start the zero worker task. + * + * - Call the rtems_clock_get_realtime_coarse() directive and try to let it + * observe a generation number of zero. + * + * - Call the rtems_clock_get_realtime_coarse_bintime() directive and try to + * let it observe a generation number of zero. + * + * - Call the rtems_clock_get_realtime_coarse_timeval() directive and try to + * let it observe a generation number of zero. + * + * - Call the rtems_clock_get_monotonic_coarse() directive and try to let it + * observe a generation number of zero. + * + * - Call the rtems_clock_get_monotonic_coarse_bintime() directive and try to + * let it observe a generation number of zero. + * + * - Call the rtems_clock_get_monotonic_coarse_timeval() directive and try to + * let it observe a generation number of zero. + * + * - Call the rtems_clock_get_boot_time() directive and try to let it observe + * a generation number of zero. + * + * - Call the rtems_clock_get_boot_time_bintime() directive and try to let it + * observe a generation number of zero. + * + * - Call the rtems_clock_get_boot_time_timeval() directive and try to let it + * observe a generation number of zero. + * + * - Delete the zero worker task. Reinitialize the barrier and barrier + * states. Start the change worker task. + * + * - Call the rtems_clock_get_realtime_coarse() directive and try to let it + * observe a changing generation number. + * + * - Call the rtems_clock_get_realtime_coarse_bintime() directive and try to + * let it observe a changing generation number. + * + * - Call the rtems_clock_get_realtime_coarse_timeval() directive and try to + * let it observe a changing generation number. + * + * - Call the rtems_clock_get_monotonic_coarse() directive and try to let it + * observe a changing generation number. + * + * - Call the rtems_clock_get_monotonic_coarse_bintime() directive and try to + * let it observe a changing generation number. + * + * - Call the rtems_clock_get_monotonic_coarse_timeval() directive and try to + * let it observe a changing generation number. + * + * - Call the rtems_clock_get_boot_time() directive and try to let it observe + * a changing generation number. + * + * - Call the rtems_clock_get_boot_time_bintime() directive and try to let it + * observe a changing generation number. + * + * - Call the rtems_clock_get_boot_time_timeval() directive and try to let it + * observe a changing generation number. + * + * - Delete the change worker task. + * + * @{ + */ + +typedef struct { + struct timecounter base; + Atomic_Ulong counter; + Atomic_Uint *generation_0; + Atomic_Uint *generation_1; + SMP_barrier_Control barrier; + SMP_barrier_State barrier_state[ 2 ]; +} Timecounter; + +static Timecounter test_timecounter; + +static uint32_t GetTimecount( struct timecounter *base ) +{ + Timecounter *tc; + + tc = (Timecounter *) base; + + return (uint32_t) _Atomic_Fetch_add_ulong( + &tc->counter, + 1, + ATOMIC_ORDER_RELAXED + ); +} + +static uint32_t GetTimecountBarrier( struct timecounter *base ) +{ + Timecounter *tc; + + tc = (Timecounter *) base; + + /* C0, C1, C2 */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 ); + + /* D0, D1, D2 */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 ); + + return GetTimecount( &tc->base ); +} + +static uint32_t GetCounter( const Timecounter *tc ) +{ + return (uint32_t) _Atomic_Load_ulong( + &tc->counter, + ATOMIC_ORDER_RELAXED + ); +} + +static void SetCounter( Timecounter *tc, uint32_t counter ) +{ + _Atomic_Store_ulong( + &tc->counter, + counter, + ATOMIC_ORDER_RELAXED + ); +} + +static void CallTimecounterTick( void ) +{ + Per_CPU_Control *cpu_self; + + cpu_self = _Thread_Dispatch_disable(); + rtems_timecounter_tick(); + _Thread_Dispatch_enable( cpu_self ); +} + +static void SetGeneration( Timecounter *tc, unsigned int generation ) +{ + _Atomic_Store_uint( tc->generation_0, generation, ATOMIC_ORDER_RELAXED ); + _Atomic_Store_uint( tc->generation_1, generation, ATOMIC_ORDER_RELAXED ); +} + +static void PrepareSynchronousWork( Timecounter *tc ) +{ + /* A */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 ); + + SetCounter( tc, 0 ); + + /* B */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 ); +} + +static void CleanupSynchronousWork( Timecounter *tc ) +{ + /* E */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 ); + + T_eq_u32( GetCounter( tc ), 3 ); +} + +static void SynchronousWorker( rtems_task_argument arg ) +{ + Timecounter *tc; + + tc = (Timecounter *) arg; + + while ( true ) { + /* A */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 ); + + SetGeneration( tc, 0 ); + + /* B */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 ); + + /* C0 */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 ); + + SetGeneration( tc, 1 ); + + /* D0 */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 ); + + /* C1 */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 ); + + SetGeneration( tc, 2 ); + + /* D1 */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 ); + + /* C2 */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 ); + + /* D2 */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 ); + + /* E */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 ); + } +} + +static void PrepareZeroWork( Timecounter *tc ) +{ + /* F */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 ); + + SetCounter( tc, 0 ); + + /* G */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 ); +} + +static void CleanupZeroWork( Timecounter *tc ) +{ + /* H */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 ); + + T_eq_u32( GetCounter( tc ), 0 ); +} + +static void ZeroWorker( rtems_task_argument arg ) +{ + Timecounter *tc; + + tc = (Timecounter *) arg; + + while ( true ) { + /* F */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 ); + + SetGeneration( tc, 0 ); + + /* G */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 ); + + rtems_counter_delay_nanoseconds( 10000000 ); + SetGeneration( tc, 1 ); + + /* H */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 ); + } +} + +static void PrepareChangeWork( Timecounter *tc ) +{ + /* F */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 ); + + SetCounter( tc, 0 ); + + /* G */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 ); +} + +static void CleanupChangeWork( Timecounter *tc ) +{ + /* H */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 0 ], 2 ); + + T_eq_u32( GetCounter( tc ), 0 ); +} + +static void ChangeWorker( rtems_task_argument arg ) +{ + Timecounter *tc; + + tc = (Timecounter *) arg; + + while ( true ) { + unsigned int i; + + /* F */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 ); + + /* G */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 ); + + for ( i = 1; i < 1000; ++i ) { + SetGeneration( tc, i ); + } + + /* H */ + _SMP_barrier_Wait( &tc->barrier, &tc->barrier_state[ 1 ], 2 ); + } +} + +/* This definition must be identical to the one in kern_tc.c */ +struct timehands { + struct timecounter *th_counter; + int64_t th_adjustment; + uint64_t th_scale; + uint32_t th_large_delta; + uint32_t th_offset_count; + struct bintime th_offset; + struct bintime th_bintime; + struct timeval th_microtime; + struct timespec th_nanotime; + struct bintime th_boottime; + Atomic_Uint th_generation; + struct timehands *th_next; +}; + +static void NtpUpdateSecond( int64_t *adjustment, time_t *newsec ) +{ + Timecounter *tc; + struct timehands *th; + + tc = &test_timecounter; + th = RTEMS_CONTAINER_OF( adjustment, struct timehands, th_adjustment ); + T_assert_eq_ptr( th, th->th_next->th_next ); + tc->generation_0 = &th->th_generation; + tc->generation_1 = &th->th_next->th_generation; +} + +/** + * @brief Install timecounter of different quality levels and frequencies. + */ +static void ScoreTimecounterValGetSmp_Action_0( void ) +{ + Timecounter *tc; + rtems_id worker_id; + struct bintime bt; + sbintime_t sbt; + struct timespec ts; + struct timeval tv; + unsigned int i; + + tc = &test_timecounter; + tc->base.tc_get_timecount = GetTimecount; + tc->base.tc_counter_mask = 0xffffffff; + tc->base.tc_frequency = 0x10000000; + tc->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install( &tc->base ); + + SetCounter( tc, tc->base.tc_frequency ); + _Timecounter_Set_NTP_update_second( NtpUpdateSecond ); + CallTimecounterTick(); + _Timecounter_Set_NTP_update_second( NULL ); + + T_assert_not_null( tc->generation_0 ); + T_assert_not_null( tc->generation_1 ); + + _SMP_barrier_Control_initialize( &tc->barrier ); + _SMP_barrier_State_initialize( &tc->barrier_state[ 0 ] ); + _SMP_barrier_State_initialize( &tc->barrier_state[ 1 ] ); + + worker_id = CreateTask( "WORK", PRIO_NORMAL ); + SetScheduler( worker_id, SCHEDULER_B_ID, PRIO_NORMAL ); + StartTask( worker_id, SynchronousWorker, tc ); + + tc->base.tc_get_timecount = GetTimecountBarrier; + + /* + * Call the rtems_clock_get_realtime() directive and let it observe a + * generation number of zero as well as a generation number change. + */ + PrepareSynchronousWork( tc ); + rtems_clock_get_realtime( &ts ); + T_eq_i64( ts.tv_sec, 567993616 ); + T_eq_long( ts.tv_nsec, 7 ); + CleanupSynchronousWork( tc ); + + /* + * Call the rtems_clock_get_realtime_bintime() directive and let it observe a + * generation number of zero as well as a generation number change. + */ + PrepareSynchronousWork( tc ); + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567993616 ); + T_eq_u64( bt.frac, 137438953472 ); + CleanupSynchronousWork( tc ); + + /* + * Call the rtems_clock_get_realtime_timeval() directive and let it observe a + * generation number of zero as well as a generation number change. + */ + PrepareSynchronousWork( tc ); + rtems_clock_get_realtime_timeval( &tv ); + T_eq_i64( tv.tv_sec, 567993616 ); + T_eq_long( tv.tv_usec, 0 ); + CleanupSynchronousWork( tc ); + + /* + * Call the rtems_clock_get_monotonic() directive and let it observe a + * generation number of zero as well as a generation number change. + */ + PrepareSynchronousWork( tc ); + rtems_clock_get_monotonic( &ts ); + T_eq_i64( ts.tv_sec, 17 ); + T_eq_long( ts.tv_nsec, 7 ); + CleanupSynchronousWork( tc ); + + /* + * Call the rtems_clock_get_monotonic_bintime() directive and let it observe + * a generation number of zero as well as a generation number change. + */ + PrepareSynchronousWork( tc ); + rtems_clock_get_monotonic_bintime( &bt ); + T_eq_i64( bt.sec, 17 ); + T_eq_u64( bt.frac, 137438953472 ); + CleanupSynchronousWork( tc ); + + /* + * Call the rtems_clock_get_monotonic_sbintime() directive and let it observe + * a generation number of zero as well as a generation number change. + */ + PrepareSynchronousWork( tc ); + sbt = rtems_clock_get_monotonic_sbintime(); + T_eq_i64( sbt, 73014444064 ); + CleanupSynchronousWork( tc ); + + /* + * Call the rtems_clock_get_monotonic_timeval() directive and let it observe + * a generation number of zero as well as a generation number change. + */ + PrepareSynchronousWork( tc ); + rtems_clock_get_monotonic_timeval( &tv ); + T_eq_i64( tv.tv_sec, 17 ); + T_eq_long( tv.tv_usec, 0 ); + CleanupSynchronousWork( tc ); + + /* + * Delete the synchronous worker task. Reinitialize the barrier and barrier + * states. Start the zero worker task. + */ + tc->base.tc_get_timecount = GetTimecount; + DeleteTask( worker_id ); + + _SMP_barrier_Control_initialize( &tc->barrier ); + _SMP_barrier_State_initialize( &tc->barrier_state[ 0 ] ); + _SMP_barrier_State_initialize( &tc->barrier_state[ 1 ] ); + + worker_id = CreateTask( "WORK", PRIO_NORMAL ); + SetScheduler( worker_id, SCHEDULER_B_ID, PRIO_NORMAL ); + StartTask( worker_id, ZeroWorker, tc ); + + /* + * Call the rtems_clock_get_realtime_coarse() directive and try to let it + * observe a generation number of zero. + */ + PrepareZeroWork( tc ); + rtems_clock_get_realtime_coarse( &ts ); + CleanupZeroWork( tc ); + + /* + * Call the rtems_clock_get_realtime_coarse_bintime() directive and try to + * let it observe a generation number of zero. + */ + PrepareZeroWork( tc ); + rtems_clock_get_realtime_coarse_bintime( &bt ); + CleanupZeroWork( tc ); + + /* + * Call the rtems_clock_get_realtime_coarse_timeval() directive and try to + * let it observe a generation number of zero. + */ + PrepareZeroWork( tc ); + rtems_clock_get_realtime_coarse_timeval( &tv ); + CleanupZeroWork( tc ); + + /* + * Call the rtems_clock_get_monotonic_coarse() directive and try to let it + * observe a generation number of zero. + */ + PrepareZeroWork( tc ); + rtems_clock_get_monotonic_coarse( &ts ); + CleanupZeroWork( tc ); + + /* + * Call the rtems_clock_get_monotonic_coarse_bintime() directive and try to + * let it observe a generation number of zero. + */ + PrepareZeroWork( tc ); + rtems_clock_get_monotonic_coarse_bintime( &bt ); + CleanupZeroWork( tc ); + + /* + * Call the rtems_clock_get_monotonic_coarse_timeval() directive and try to + * let it observe a generation number of zero. + */ + PrepareZeroWork( tc ); + rtems_clock_get_monotonic_coarse_timeval( &tv ); + CleanupZeroWork( tc ); + + /* + * Call the rtems_clock_get_boot_time() directive and try to let it observe a + * generation number of zero. + */ + PrepareZeroWork( tc ); + rtems_clock_get_boot_time( &ts ); + CleanupZeroWork( tc ); + + /* + * Call the rtems_clock_get_boot_time_bintime() directive and try to let it + * observe a generation number of zero. + */ + PrepareZeroWork( tc ); + rtems_clock_get_boot_time_bintime( &bt ); + CleanupZeroWork( tc ); + + /* + * Call the rtems_clock_get_boot_time_timeval() directive and try to let it + * observe a generation number of zero. + */ + PrepareZeroWork( tc ); + rtems_clock_get_boot_time_timeval( &tv ); + CleanupZeroWork( tc ); + + /* + * Delete the zero worker task. Reinitialize the barrier and barrier states. + * Start the change worker task. + */ + DeleteTask( worker_id ); + + _SMP_barrier_Control_initialize( &tc->barrier ); + _SMP_barrier_State_initialize( &tc->barrier_state[ 0 ] ); + _SMP_barrier_State_initialize( &tc->barrier_state[ 1 ] ); + + worker_id = CreateTask( "WORK", PRIO_NORMAL ); + SetScheduler( worker_id, SCHEDULER_B_ID, PRIO_NORMAL ); + StartTask( worker_id, ChangeWorker, tc ); + + /* + * Call the rtems_clock_get_realtime_coarse() directive and try to let it + * observe a changing generation number. + */ + PrepareChangeWork( tc ); + + for ( i = 0; i < 100; ++i ) { + rtems_clock_get_realtime_coarse( &ts ); + } + + CleanupChangeWork( tc ); + + /* + * Call the rtems_clock_get_realtime_coarse_bintime() directive and try to + * let it observe a changing generation number. + */ + PrepareChangeWork( tc ); + + for ( i = 0; i < 100; ++i ) { + rtems_clock_get_realtime_coarse_bintime( &bt ); + } + + CleanupChangeWork( tc ); + + /* + * Call the rtems_clock_get_realtime_coarse_timeval() directive and try to + * let it observe a changing generation number. + */ + PrepareChangeWork( tc ); + + for ( i = 0; i < 100; ++i ) { + rtems_clock_get_realtime_coarse_timeval( &tv ); + } + + CleanupChangeWork( tc ); + + /* + * Call the rtems_clock_get_monotonic_coarse() directive and try to let it + * observe a changing generation number. + */ + PrepareChangeWork( tc ); + + for ( i = 0; i < 100; ++i ) { + rtems_clock_get_monotonic_coarse( &ts ); + } + + CleanupChangeWork( tc ); + + /* + * Call the rtems_clock_get_monotonic_coarse_bintime() directive and try to + * let it observe a changing generation number. + */ + PrepareChangeWork( tc ); + + for ( i = 0; i < 100; ++i ) { + rtems_clock_get_monotonic_coarse_bintime( &bt ); + } + + CleanupChangeWork( tc ); + + /* + * Call the rtems_clock_get_monotonic_coarse_timeval() directive and try to + * let it observe a changing generation number. + */ + PrepareChangeWork( tc ); + + for ( i = 0; i < 100; ++i ) { + rtems_clock_get_monotonic_coarse_timeval( &tv ); + } + + CleanupChangeWork( tc ); + + /* + * Call the rtems_clock_get_boot_time() directive and try to let it observe a + * changing generation number. + */ + PrepareChangeWork( tc ); + + for ( i = 0; i < 100; ++i ) { + rtems_clock_get_boot_time( &ts ); + } + + CleanupChangeWork( tc ); + + /* + * Call the rtems_clock_get_boot_time_bintime() directive and try to let it + * observe a changing generation number. + */ + PrepareChangeWork( tc ); + + for ( i = 0; i < 100; ++i ) { + rtems_clock_get_boot_time_bintime( &bt ); + } + + CleanupChangeWork( tc ); + + /* + * Call the rtems_clock_get_boot_time_timeval() directive and try to let it + * observe a changing generation number. + */ + PrepareChangeWork( tc ); + + for ( i = 0; i < 100; ++i ) { + rtems_clock_get_boot_time_timeval( &tv ); + } + + CleanupChangeWork( tc ); + + /* + * Delete the change worker task. + */ + DeleteTask( worker_id ); +} + +/** + * @fn void T_case_body_ScoreTimecounterValGetSmp( void ) + */ +T_TEST_CASE( ScoreTimecounterValGetSmp ) +{ + ScoreTimecounterValGetSmp_Action_0(); +} + +/** @} */ diff --git a/testsuites/validation/tc-timecounter-get.c b/testsuites/validation/tc-timecounter-get.c new file mode 100644 index 0000000000..7ab746ab86 --- /dev/null +++ b/testsuites/validation/tc-timecounter-get.c @@ -0,0 +1,575 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTestCaseScoreTimecounterValGet + */ + +/* + * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) + * + * 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. + */ + +/* + * This file is part of the RTEMS quality process and was automatically + * generated. If you find something that needs to be fixed or + * worded better please post a report or patch to an RTEMS mailing list + * or raise a bug report: + * + * https://www.rtems.org/bugs.html + * + * For information on updating and regenerating please refer to the How-To + * section in the Software Requirements Engineering chapter of the + * RTEMS Software Engineering manual. The manual is provided as a part of + * a release. For development sources please refer to the online + * documentation at: + * + * https://docs.rtems.org + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "tx-support.h" + +#include + +/** + * @defgroup RTEMSTestCaseScoreTimecounterValGet \ + * spec:/score/timecounter/val/get + * + * @ingroup RTEMSTestSuiteTestsuitesValidationTimecounter1 + * + * @brief Tests directives to get a time value. + * + * This test case performs the following actions: + * + * - Install a timecounter which can be used to perform interrut tests for the + * get time directives. + * + * - Try to interrupt the rtems_clock_get_realtime() directive to provoke a + * change in the timehand generation number. + * + * - Try to interrupt the rtems_clock_get_realtime_bintime() directive to + * provoke a change in the timehand generation number. + * + * - Try to interrupt the rtems_clock_get_realtime_timeval() directive to + * provoke a change in the timehand generation number. + * + * - Try to interrupt the rtems_clock_get_monotonic() directive to provoke a + * change in the timehand generation number. + * + * - Try to interrupt the rtems_clock_get_monotonic_bintime() directive to + * provoke a change in the timehand generation number. + * + * - Try to interrupt the rtems_clock_get_monotonic_sbintime() directive to + * provoke a change in the timehand generation number. + * + * - Try to interrupt the rtems_clock_get_monotonic_timeval() directive to + * provoke a change in the timehand generation number. + * + * - Prepare for the coarse get time directives. + * + * - Try to interrupt the rtems_clock_get_realtime_coarse() directive to + * provoke a change in the timehand generation number. + * + * - Try to interrupt the rtems_clock_get_realtime_coarse_bintime() directive + * to provoke a change in the timehand generation number. + * + * - Try to interrupt the rtems_clock_get_realtime_coarse_timeval() directive + * to provoke a change in the timehand generation number. + * + * - Try to interrupt the rtems_clock_get_monotonic_coarse() directive to + * provoke a change in the timehand generation number. + * + * - Try to interrupt the rtems_clock_get_monotonic_coarse_bintime() + * directive to provoke a change in the timehand generation number. + * + * - Try to interrupt the rtems_clock_get_monotonic_coarse_timeval() + * directive to provoke a change in the timehand generation number. + * + * - Try to interrupt the rtems_clock_get_boot_time() directive to provoke a + * change in the timehand generation number. + * + * - Try to interrupt the rtems_clock_get_boot_time_bintime() directive to + * provoke a change in the timehand generation number. + * + * - Try to interrupt the rtems_clock_get_boot_time_timeval() directive to + * provoke a change in the timehand generation number. + * + * @{ + */ + +typedef enum { + STATE_EARLY, + STATE_GET_TIMECOUNT_BEFORE, + STATE_GET_TIMECOUNT_BUSY, + STATE_GET_TIMECOUNT_DONE, + STATE_GET_TIMECOUNT_AFTER +} State; + +typedef struct { + struct timecounter base; + State state; + uint_fast32_t busy; + struct bintime tod; +} Timecounter; + +static Timecounter test_timecounter; + +static uint32_t GetTimecount( struct timecounter *base ) +{ + Timecounter *tc; + + tc = (Timecounter *) base; + + if ( + tc->state == STATE_GET_TIMECOUNT_BEFORE && + !rtems_interrupt_is_in_progress() + ) { + tc->state = STATE_GET_TIMECOUNT_BUSY; + T_busy( tc->busy ); + tc->state = STATE_GET_TIMECOUNT_DONE; + } + + return rtems_counter_read(); +} + +static void InterruptPrepare( void *arg ) +{ + Timecounter *tc; + + tc = (Timecounter *) arg; + tc->state = STATE_EARLY; +} + +static void ActionRealtime( void *arg ) +{ + Timecounter *tc; + struct timespec ts; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + rtems_clock_get_realtime( &ts ); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void ActionRealtimeBintime( void *arg ) +{ + Timecounter *tc; + struct bintime bt; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + rtems_clock_get_realtime_bintime( &bt ); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void ActionRealtimeTimeval( void *arg ) +{ + Timecounter *tc; + struct timeval tv; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + rtems_clock_get_realtime_timeval( &tv ); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void ActionMonotonic( void *arg ) +{ + Timecounter *tc; + struct timespec ts; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + rtems_clock_get_monotonic( &ts ); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void ActionMonotonicBintime( void *arg ) +{ + Timecounter *tc; + struct bintime bt; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + rtems_clock_get_monotonic_bintime( &bt ); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void ActionMonotonicSbintime( void *arg ) +{ + Timecounter *tc; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + (void) rtems_clock_get_monotonic_sbintime(); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void ActionMonotonicTimeval( void *arg ) +{ + Timecounter *tc; + struct timeval tv; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + rtems_clock_get_monotonic_timeval( &tv ); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void ActionCoarseRealtime( void *arg ) +{ + Timecounter *tc; + struct timespec ts; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + rtems_clock_get_realtime_coarse( &ts ); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void ActionCoarseRealtimeBintime( void *arg ) +{ + Timecounter *tc; + struct bintime bt; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + rtems_clock_get_realtime_coarse_bintime( &bt ); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void ActionCoarseRealtimeTimeval( void *arg ) +{ + Timecounter *tc; + struct timeval tv; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + rtems_clock_get_realtime_coarse_timeval( &tv ); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void ActionCoarseMonotonic( void *arg ) +{ + Timecounter *tc; + struct timespec ts; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + rtems_clock_get_monotonic_coarse( &ts ); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void ActionCoarseMonotonicBintime( void *arg ) +{ + Timecounter *tc; + struct bintime bt; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + rtems_clock_get_monotonic_coarse_bintime( &bt ); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void ActionCoarseMonotonicTimeval( void *arg ) +{ + Timecounter *tc; + struct timeval tv; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + rtems_clock_get_monotonic_coarse_timeval( &tv ); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void ActionBootTime( void *arg ) +{ + Timecounter *tc; + struct timespec ts; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + rtems_clock_get_boot_time( &ts ); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void ActionBootTimeBintime( void *arg ) +{ + Timecounter *tc; + struct bintime bt; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + rtems_clock_get_boot_time_bintime( &bt ); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void ActionBootTimeTimeval( void *arg ) +{ + Timecounter *tc; + struct timeval tv; + + tc = (Timecounter *) arg; + tc->state = STATE_GET_TIMECOUNT_BEFORE; + rtems_clock_get_boot_time_timeval( &tv ); + tc->state = STATE_GET_TIMECOUNT_AFTER; +} + +static void CallTimcounterWindupTwice( const Timecounter *tc ) +{ + ISR_lock_Context lock_context; + + /* + * Make sure that tc_windup() was called at least twice to increment the + * generation number for * both timehands. + */ + + _Timecounter_Acquire( &lock_context ); + _Timecounter_Set_clock( &tc->tod, &lock_context ); + + _Timecounter_Acquire( &lock_context ); + _Timecounter_Set_clock( &tc->tod, &lock_context ); +} + +static T_interrupt_test_state Interrupt( void *arg ) +{ + Timecounter *tc; + State state; + + tc = (Timecounter *) arg; + state = tc->state; + + if ( state == STATE_EARLY || state == STATE_GET_TIMECOUNT_BEFORE ) { + return T_INTERRUPT_TEST_EARLY; + } + + if ( state == STATE_GET_TIMECOUNT_BUSY ) { + CallTimcounterWindupTwice( tc ); + + return T_INTERRUPT_TEST_DONE; + } + + return T_INTERRUPT_TEST_LATE; +} + +static T_interrupt_test_state InterruptCoarse( void *arg ) +{ + Timecounter *tc; + State state; + + tc = (Timecounter *) arg; + state = tc->state; + + if ( state == STATE_EARLY ) { + return T_INTERRUPT_TEST_EARLY; + } + + if ( state == STATE_GET_TIMECOUNT_BEFORE ) { + CallTimcounterWindupTwice( tc ); + + return T_INTERRUPT_TEST_DONE; + } + + return T_INTERRUPT_TEST_LATE; +} + +static bool InterruptTest( + const T_interrupt_test_config *config, + void *arg, + uint32_t iterations +) +{ + uint32_t i; + bool ok; + + ok = false; + + for ( i = 0; i < iterations; ++i ) { + T_interrupt_test_state test_state; + + test_state = T_interrupt_test( config, arg ); + ok = ok || test_state == T_INTERRUPT_TEST_DONE; + } + + return ok; +} + +/** + * @brief Install a timecounter which can be used to perform interrut tests for + * the get time directives. + */ +static void ScoreTimecounterValGet_Action_0( void ) +{ + T_interrupt_test_config config = { + .prepare = InterruptPrepare, + .interrupt = Interrupt, + .max_iteration_count = 10000 + }; + Timecounter *tc; + + tc = &test_timecounter; + tc->base.tc_get_timecount = GetTimecount; + tc->base.tc_counter_mask = 0xffffffff; + tc->base.tc_frequency = rtems_counter_frequency(); + tc->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER + 1; + tc->busy = T_get_one_clock_tick_busy() / 10; + rtems_clock_get_realtime_bintime( &tc->tod ); + rtems_timecounter_install( &tc->base ); + + /* + * Try to interrupt the rtems_clock_get_realtime() directive to provoke a + * change in the timehand generation number. + */ + config.action = ActionRealtime; + T_true( InterruptTest( &config, tc, 1 ) ); + + /* + * Try to interrupt the rtems_clock_get_realtime_bintime() directive to + * provoke a change in the timehand generation number. + */ + config.action = ActionRealtimeBintime; + T_true( InterruptTest( &config, tc, 1 ) ); + + /* + * Try to interrupt the rtems_clock_get_realtime_timeval() directive to + * provoke a change in the timehand generation number. + */ + config.action = ActionRealtimeTimeval; + T_true( InterruptTest( &config, tc, 1 ) ); + + /* + * Try to interrupt the rtems_clock_get_monotonic() directive to provoke a + * change in the timehand generation number. + */ + config.action = ActionMonotonic; + T_true( InterruptTest( &config, tc, 1 ) ); + + /* + * Try to interrupt the rtems_clock_get_monotonic_bintime() directive to + * provoke a change in the timehand generation number. + */ + config.action = ActionMonotonicBintime; + T_true( InterruptTest( &config, tc, 1 ) ); + + /* + * Try to interrupt the rtems_clock_get_monotonic_sbintime() directive to + * provoke a change in the timehand generation number. + */ + config.action = ActionMonotonicSbintime; + T_true( InterruptTest( &config, tc, 1 ) ); + + /* + * Try to interrupt the rtems_clock_get_monotonic_timeval() directive to + * provoke a change in the timehand generation number. + */ + config.action = ActionMonotonicTimeval; + T_true( InterruptTest( &config, tc, 1 ) ); + + /* + * Prepare for the coarse get time directives. + */ + config.interrupt = InterruptCoarse; + + /* + * Try to interrupt the rtems_clock_get_realtime_coarse() directive to + * provoke a change in the timehand generation number. + */ + config.action = ActionCoarseRealtime; + T_true( InterruptTest( &config, tc, 10 ) ); + + /* + * Try to interrupt the rtems_clock_get_realtime_coarse_bintime() directive + * to provoke a change in the timehand generation number. + */ + config.action = ActionCoarseRealtimeBintime; + T_true( InterruptTest( &config, tc, 10 ) ); + + /* + * Try to interrupt the rtems_clock_get_realtime_coarse_timeval() directive + * to provoke a change in the timehand generation number. + */ + config.action = ActionCoarseRealtimeTimeval; + T_true( InterruptTest( &config, tc, 10 ) ); + + /* + * Try to interrupt the rtems_clock_get_monotonic_coarse() directive to + * provoke a change in the timehand generation number. + */ + config.action = ActionCoarseMonotonic; + T_true( InterruptTest( &config, tc, 10 ) ); + + /* + * Try to interrupt the rtems_clock_get_monotonic_coarse_bintime() directive + * to provoke a change in the timehand generation number. + */ + config.action = ActionCoarseMonotonicBintime; + T_true( InterruptTest( &config, tc, 10 ) ); + + /* + * Try to interrupt the rtems_clock_get_monotonic_coarse_timeval() directive + * to provoke a change in the timehand generation number. + */ + config.action = ActionCoarseMonotonicTimeval; + T_true( InterruptTest( &config, tc, 10 ) ); + + /* + * Try to interrupt the rtems_clock_get_boot_time() directive to provoke a + * change in the timehand generation number. + */ + config.action = ActionBootTime; + T_true( InterruptTest( &config, tc, 10 ) ); + + /* + * Try to interrupt the rtems_clock_get_boot_time_bintime() directive to + * provoke a change in the timehand generation number. + */ + config.action = ActionBootTimeBintime; + T_true( InterruptTest( &config, tc, 10 ) ); + + /* + * Try to interrupt the rtems_clock_get_boot_time_timeval() directive to + * provoke a change in the timehand generation number. + */ + config.action = ActionBootTimeTimeval; + T_true( InterruptTest( &config, tc, 10 ) ); +} + +/** + * @fn void T_case_body_ScoreTimecounterValGet( void ) + */ +T_TEST_CASE( ScoreTimecounterValGet ) +{ + ScoreTimecounterValGet_Action_0(); +} + +/** @} */ diff --git a/testsuites/validation/tc-timecounter-install.c b/testsuites/validation/tc-timecounter-install.c new file mode 100644 index 0000000000..3189f37a23 --- /dev/null +++ b/testsuites/validation/tc-timecounter-install.c @@ -0,0 +1,1134 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTestCaseScoreTimecounterValInstall + */ + +/* + * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) + * + * 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. + */ + +/* + * This file is part of the RTEMS quality process and was automatically + * generated. If you find something that needs to be fixed or + * worded better please post a report or patch to an RTEMS mailing list + * or raise a bug report: + * + * https://www.rtems.org/bugs.html + * + * For information on updating and regenerating please refer to the How-To + * section in the Software Requirements Engineering chapter of the + * RTEMS Software Engineering manual. The manual is provided as a part of + * a release. For development sources please refer to the online + * documentation at: + * + * https://docs.rtems.org + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "tx-support.h" + +#include + +/** + * @defgroup RTEMSTestCaseScoreTimecounterValInstall \ + * spec:/score/timecounter/val/install + * + * @ingroup RTEMSTestSuiteTestsuitesValidationTimecounter0 + * + * @brief Tests timecounter installation related functions and directives of + * the Clock Manager. + * + * This test case performs the following actions: + * + * - Call the simple timecounter tick service with a zero delta and offset. + * This will lead to an overflow to zero of the timehand generation. It + * shall not change the initial clock values. + * + * - Call the directives to get the initial value of CLOCK_REALTIME and the + * initial boot time. + * + * - Check the initial CLOCK_REALTIME in seconds and nanoseconds format. + * + * - Check that CLOCK_REALTIME is frozen in seconds and nanoseconds format. + * + * - Check the initial CLOCK_REALTIME in coarse resolution in seconds and + * nanoseconds format. + * + * - Check that CLOCK_REALTIME is frozen in coarse resolution in seconds and + * nanoseconds format. + * + * - Check the initial CLOCK_REALTIME in binary time format. + * + * - Check that CLOCK_REALTIME is frozen in binary time format. + * + * - Check the initial CLOCK_REALTIME in coarse resolution in binary time + * format. + * + * - Check that CLOCK_REALTIME is frozen in coarse resolution in binary time + * format. + * + * - Check the initial CLOCK_REALTIME in seconds and microseconds format. + * + * - Check that CLOCK_REALTIME is frozen in seconds and microseconds format. + * + * - Check the initial CLOCK_REALTIME in coarse resolution in seconds and + * microseconds format. + * + * - Check that CLOCK_REALTIME is frozen in coarse resolution in seconds and + * microseconds format. + * + * - Check the initial boot time in seconds and nanoseconds format. + * + * - Check the initial boot time in binary time format. + * + * - Check the initial boot time in seconds and microseconds format. + * + * - Call the directives to get the initial value of CLOCK_MONOTONIC and the + * initial boot time. + * + * - Check the initial CLOCK_MONOTONIC in seconds and nanoseconds format. + * + * - Check that CLOCK_MONOTONIC is frozen in seconds and nanoseconds format. + * + * - Check the initial CLOCK_MONOTONIC in coarse resolution in seconds and + * nanoseconds format. + * + * - Check that CLOCK_MONOTONIC is frozen in coarse resolution in seconds and + * nanoseconds format. + * + * - Check the initial CLOCK_MONOTONIC in binary time format. + * + * - Check that CLOCK_MONOTONIC is frozen in binary time format. + * + * - Check the initial CLOCK_MONOTONIC in coarse resolution in binary time + * format. + * + * - Check that CLOCK_MONOTONIC is frozen in coarse resolution in binary time + * format. + * + * - Check the initial CLOCK_MONOTONIC in signed binary time format. + * + * - Check that CLOCK_MONOTONIC is frozen in signed binary time format. + * + * - Check the initial CLOCK_MONOTONIC in seconds and microseconds format. + * + * - Check that CLOCK_MONOTONIC is frozen in seconds and microseconds format. + * + * - Check the initial CLOCK_MONOTONIC in coarse resolution in seconds and + * microseconds format. + * + * - Check that CLOCK_MONOTONIC is frozen in coarse resolution in seconds and + * microseconds format. + * + * - Install timecounter of different quality levels and frequencies. + * + * - Install a timecounter with a high quality level and normal frequency. + * Check that it was installed. + * + * - Install a timecounter with a high quality level and low frequency. Check + * that it was not installed. + * + * - Install a timecounter with a high quality level and high frequency. + * Check that it was installed. + * + * - Install a timecounter with a low quality level. Check that it was not + * installed. + * + * - Call the directives to get the time in the highest resolution available to + * the system. + * + * - Check that the timecounter was used by rtems_clock_get_realtime(). + * + * - Check that the timecounter was used by + * rtems_clock_get_realtime_bintime(). + * + * - Check that the timecounter was used by + * rtems_clock_get_realtime_timeval(). + * + * - Check that the timecounter was used by rtems_clock_get_monotonic(). + * + * - Check that the timecounter was used by + * rtems_clock_get_monotonic_bintime(). + * + * - Check that the timecounter was used by + * rtems_clock_get_monotonic_sbintime(). + * + * - Check that the timecounter was used by + * rtems_clock_get_monotonic_timeval(). + * + * - Call the directives to get the time in a coarse resolution. + * + * - Check that the timecounter was not used by + * rtems_clock_get_realtime_coarse(). + * + * - Check that the timecounter was not used by + * rtems_clock_get_realtime_coarse_bintime(). + * + * - Check that the timecounter was not used by + * rtems_clock_get_realtime_coarse_timeval(). + * + * - Check that the timecounter was not used by + * rtems_clock_get_monotonic_coarse(). + * + * - Check that the timecounter was not used by + * rtems_clock_get_monotonic_coarse_bintime(). + * + * - Check that the timecounter was not used by + * rtems_clock_get_monotonic_coarse_timeval(). + * + * - Check that the timecounter was not used by rtems_clock_get_boot_time(). + * + * - Check that the timecounter was not used by + * rtems_clock_get_boot_time_bintime(). + * + * - Check that the timecounter was not used by + * rtems_clock_get_boot_time_timeval(). + * + * - Call the directives to get the time in the highest resolution available to + * the system. + * + * - Prepare the timecounter to get a large time difference. Check that + * rtems_clock_get_realtime() returns the correct time. + * + * - Prepare the timecounter to get a large time difference. Check that + * rtems_clock_get_realtime_bintime() returns the correct time. + * + * - Prepare the timecounter to get a large time difference. Check that + * rtems_clock_get_realtime_timeval() returns the correct time. + * + * - Prepare the timecounter to get a large time difference. Check that + * rtems_clock_get_monotonic() returns the correct time. + * + * - Prepare the timecounter to get a large time difference. Check that + * rtems_clock_get_monotonic_bintime() returns the correct time. + * + * - Prepare the timecounter to get a large time difference. Check that + * rtems_clock_get_monotonic_sbintime() returns the correct time. + * + * - Prepare the timecounter to get a large time difference. Check that + * rtems_clock_get_monotonic_timeval() returns the correct time. + * + * - Update the oldest timehand after a large time interval. + * + * - Call the simple timecounter tick service with non-zero delta and offset + * parameter values so that exactly one second passed. + * + * - Check that exactly one second passed due to the simple clock tick + * service. + * + * - Install a very high quality timecounter with a low frequency to test the + * NTP support. + * + * - Let the seconds value of CLOCK_REALTIME not change. Check that the NTP + * update second handler is not called. + * + * - Let the seconds value of CLOCK_REALTIME change by one. Check that the + * NTP update second handler is called exactly once. + * + * - Let the seconds value of CLOCK_REALTIME change by 200. Check that the + * NTP update second handler is called exactly 200 times. + * + * - Let the seconds value of CLOCK_REALTIME change by 201. Check that the + * NTP update second handler is called exactly twice. + * + * - Let the seconds value of CLOCK_REALTIME change by one. Check that the + * NTP update second handler is incremented the CLOCK_REALTIME by one + * second. + * + * - Let the seconds value of CLOCK_REALTIME change by one. Check that the + * NTP update second handler is decremented the CLOCK_REALTIME by one + * second. + * + * - Let the seconds value of CLOCK_REALTIME change by one. Check that the + * NTP update second handler increased the timecounter frequency. + * + * - Let the seconds value of CLOCK_REALTIME change by one. Check that the + * NTP update second handler decreased the timecounter frequency. + * + * @{ + */ + +typedef struct { + struct timecounter base; + Atomic_Ulong counter; +} Timecounter; + +static Timecounter high_quality_low_frequency; + +static Timecounter high_quality_normal_frequency; + +static Timecounter high_quality_high_frequency; + +static Timecounter low_quality; + +static Timecounter very_high_quality; + +static uint32_t ntp_counter; + +static uint32_t GetTimecount( struct timecounter *base ) +{ + Timecounter *tc; + + tc = (Timecounter *) base; + + return (uint32_t) _Atomic_Fetch_add_ulong( + &tc->counter, + 1, + ATOMIC_ORDER_RELAXED + ); +} + +static uint32_t GetCounter( const Timecounter *tc ) +{ + return (uint32_t) _Atomic_Load_ulong( + &tc->counter, + ATOMIC_ORDER_RELAXED + ); +} + +static void SetCounter( Timecounter *tc, uint32_t counter ) +{ + _Atomic_Store_ulong( + &tc->counter, + counter, + ATOMIC_ORDER_RELAXED + ); +} + +static void NtpUpdateCounter( int64_t *adjustment, time_t *newsec ) +{ + (void) newsec; + T_eq_i64( *adjustment, 0 ); + ++ntp_counter; +} + +static void NtpUpdateSecondIncrement( int64_t *adjustment, time_t *newsec ) +{ + (void) adjustment; + ++(*newsec); +} + +static void NtpUpdateSecondDecrement( int64_t *adjustment, time_t *newsec ) +{ + (void) adjustment; + --(*newsec); +} + +static void NtpUpdateAdjustmentFaster( int64_t *adjustment, time_t *newsec ) +{ + *adjustment = ( (int64_t) 5000 ) << 32; + (void) newsec; +} + +static void NtpUpdateAdjustmentSlower( int64_t *adjustment, time_t *newsec ) +{ + *adjustment = -( (int64_t) 5000 ) << 32; + (void) newsec; +} + +static void CallTimecounterTick( void ) +{ + Per_CPU_Control *cpu_self; + + cpu_self = _Thread_Dispatch_disable(); + rtems_timecounter_tick(); + _Thread_Dispatch_enable( cpu_self ); +} + +/** + * @brief Call the simple timecounter tick service with a zero delta and + * offset. This will lead to an overflow to zero of the timehand generation. + * It shall not change the initial clock values. + */ +static void ScoreTimecounterValInstall_Action_0( void ) +{ + ISR_lock_Context lock_context; + + _Timecounter_Acquire( &lock_context ); + _Timecounter_Tick_simple( 0, 0, &lock_context ); +} + +/** + * @brief Call the directives to get the initial value of CLOCK_REALTIME and + * the initial boot time. + */ +static void ScoreTimecounterValInstall_Action_1( void ) +{ + struct bintime bt; + struct timespec ts; + struct timeval tv; + + /* + * Check the initial CLOCK_REALTIME in seconds and nanoseconds format. + */ + rtems_clock_get_realtime( &ts ); + T_eq_i64( ts.tv_sec, 567993600 ); + T_eq_u64( ts.tv_nsec, 0 ); + + /* + * Check that CLOCK_REALTIME is frozen in seconds and nanoseconds format. + */ + rtems_clock_get_realtime( &ts ); + T_eq_i64( ts.tv_sec, 567993600 ); + T_eq_u64( ts.tv_nsec, 0 ); + + /* + * Check the initial CLOCK_REALTIME in coarse resolution in seconds and + * nanoseconds format. + */ + rtems_clock_get_realtime_coarse( &ts ); + T_eq_i64( ts.tv_sec, 567993600 ); + T_eq_u64( ts.tv_nsec, 0 ); + + /* + * Check that CLOCK_REALTIME is frozen in coarse resolution in seconds and + * nanoseconds format. + */ + rtems_clock_get_realtime_coarse( &ts ); + T_eq_i64( ts.tv_sec, 567993600 ); + T_eq_u64( ts.tv_nsec, 0 ); + + /* + * Check the initial CLOCK_REALTIME in binary time format. + */ + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567993600 ); + T_eq_u64( bt.frac, 0 ); + + /* + * Check that CLOCK_REALTIME is frozen in binary time format. + */ + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567993600 ); + T_eq_u64( bt.frac, 0 ); + + /* + * Check the initial CLOCK_REALTIME in coarse resolution in binary time + * format. + */ + rtems_clock_get_realtime_coarse_bintime( &bt ); + T_eq_i64( bt.sec, 567993600 ); + T_eq_u64( bt.frac, 0 ); + + /* + * Check that CLOCK_REALTIME is frozen in coarse resolution in binary time + * format. + */ + rtems_clock_get_realtime_coarse_bintime( &bt ); + T_eq_i64( bt.sec, 567993600 ); + T_eq_u64( bt.frac, 0 ); + + /* + * Check the initial CLOCK_REALTIME in seconds and microseconds format. + */ + rtems_clock_get_realtime_timeval( &tv ); + T_eq_i64( tv.tv_sec, 567993600 ); + T_eq_long( tv.tv_usec, 0 ); + + /* + * Check that CLOCK_REALTIME is frozen in seconds and microseconds format. + */ + rtems_clock_get_realtime_timeval( &tv ); + T_eq_i64( tv.tv_sec, 567993600 ); + T_eq_long( tv.tv_usec, 0 ); + + /* + * Check the initial CLOCK_REALTIME in coarse resolution in seconds and + * microseconds format. + */ + rtems_clock_get_realtime_coarse_timeval( &tv ); + T_eq_i64( tv.tv_sec, 567993600 ); + T_eq_long( tv.tv_usec, 0 ); + + /* + * Check that CLOCK_REALTIME is frozen in coarse resolution in seconds and + * microseconds format. + */ + rtems_clock_get_realtime_coarse_timeval( &tv ); + T_eq_i64( tv.tv_sec, 567993600 ); + T_eq_long( tv.tv_usec, 0 ); + + /* + * Check the initial boot time in seconds and nanoseconds format. + */ + rtems_clock_get_boot_time( &ts ); + T_eq_i64( ts.tv_sec, 567993599 ); + T_eq_u64( ts.tv_nsec, 0 ); + + /* + * Check the initial boot time in binary time format. + */ + rtems_clock_get_boot_time_bintime( &bt ); + T_eq_i64( bt.sec, 567993599 ); + T_eq_u64( bt.frac, 0 ); + + /* + * Check the initial boot time in seconds and microseconds format. + */ + rtems_clock_get_boot_time_timeval( &tv ); + T_eq_i64( tv.tv_sec, 567993599 ); + T_eq_long( tv.tv_usec, 0 ); +} + +/** + * @brief Call the directives to get the initial value of CLOCK_MONOTONIC and + * the initial boot time. + */ +static void ScoreTimecounterValInstall_Action_2( void ) +{ + struct bintime bt; + sbintime_t sb; + struct timespec ts; + struct timeval tv; + + /* + * Check the initial CLOCK_MONOTONIC in seconds and nanoseconds format. + */ + rtems_clock_get_monotonic( &ts ); + T_eq_i64( ts.tv_sec, 1 ); + T_eq_u64( ts.tv_nsec, 0 ); + + /* + * Check that CLOCK_MONOTONIC is frozen in seconds and nanoseconds format. + */ + rtems_clock_get_monotonic( &ts ); + T_eq_i64( ts.tv_sec, 1 ); + T_eq_u64( ts.tv_nsec, 0 ); + + /* + * Check the initial CLOCK_MONOTONIC in coarse resolution in seconds and + * nanoseconds format. + */ + rtems_clock_get_monotonic_coarse( &ts ); + T_eq_i64( ts.tv_sec, 1 ); + T_eq_u64( ts.tv_nsec, 0 ); + + /* + * Check that CLOCK_MONOTONIC is frozen in coarse resolution in seconds and + * nanoseconds format. + */ + rtems_clock_get_monotonic_coarse( &ts ); + T_eq_i64( ts.tv_sec, 1 ); + T_eq_u64( ts.tv_nsec, 0 ); + + /* + * Check the initial CLOCK_MONOTONIC in binary time format. + */ + rtems_clock_get_monotonic_bintime( &bt ); + T_eq_i64( bt.sec, 1 ); + T_eq_u64( bt.frac, 0 ); + + /* + * Check that CLOCK_MONOTONIC is frozen in binary time format. + */ + rtems_clock_get_monotonic_bintime( &bt ); + T_eq_i64( bt.sec, 1 ); + T_eq_u64( bt.frac, 0 ); + + /* + * Check the initial CLOCK_MONOTONIC in coarse resolution in binary time + * format. + */ + rtems_clock_get_monotonic_coarse_bintime( &bt ); + T_eq_i64( bt.sec, 1 ); + T_eq_u64( bt.frac, 0 ); + + /* + * Check that CLOCK_MONOTONIC is frozen in coarse resolution in binary time + * format. + */ + rtems_clock_get_monotonic_coarse_bintime( &bt ); + T_eq_i64( bt.sec, 1 ); + T_eq_u64( bt.frac, 0 ); + + /* + * Check the initial CLOCK_MONOTONIC in signed binary time format. + */ + sb = rtems_clock_get_monotonic_sbintime(); + T_eq_i64( sb, SBT_1S ); + + /* + * Check that CLOCK_MONOTONIC is frozen in signed binary time format. + */ + sb = rtems_clock_get_monotonic_sbintime(); + T_eq_i64( sb, SBT_1S ); + + /* + * Check the initial CLOCK_MONOTONIC in seconds and microseconds format. + */ + rtems_clock_get_monotonic_timeval( &tv ); + T_eq_i64( tv.tv_sec, 1 ); + T_eq_long( tv.tv_usec, 0 ); + + /* + * Check that CLOCK_MONOTONIC is frozen in seconds and microseconds format. + */ + rtems_clock_get_monotonic_timeval( &tv ); + T_eq_i64( tv.tv_sec, 1 ); + T_eq_long( tv.tv_usec, 0 ); + + /* + * Check the initial CLOCK_MONOTONIC in coarse resolution in seconds and + * microseconds format. + */ + rtems_clock_get_monotonic_coarse_timeval( &tv ); + T_eq_i64( tv.tv_sec, 1 ); + T_eq_long( tv.tv_usec, 0 ); + + /* + * Check that CLOCK_MONOTONIC is frozen in coarse resolution in seconds and + * microseconds format. + */ + rtems_clock_get_monotonic_coarse_timeval( &tv ); + T_eq_i64( tv.tv_sec, 1 ); + T_eq_long( tv.tv_usec, 0 ); +} + +/** + * @brief Install timecounter of different quality levels and frequencies. + */ +static void ScoreTimecounterValInstall_Action_3( void ) +{ + Timecounter *hqlf; + Timecounter *hqnf; + Timecounter *hqhf; + Timecounter *lq; + sbintime_t sb; + + hqlf = &high_quality_low_frequency; + hqnf = &high_quality_normal_frequency; + hqhf = &high_quality_high_frequency; + lq = &low_quality; + + /* + * Install a timecounter with a high quality level and normal frequency. + * Check that it was installed. + */ + hqnf->base.tc_get_timecount = GetTimecount; + hqnf->base.tc_counter_mask = 0xffffffff; + hqnf->base.tc_frequency = 0x20000000; + hqnf->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER + 1; + rtems_timecounter_install( &hqnf->base ); + + T_eq_u32( GetCounter( hqnf ), 1 ); + + sb = rtems_clock_get_monotonic_sbintime(); + T_eq_u32( GetCounter( hqnf ), 2 ); + T_eq_i64( sb, SBT_1S + 8 ); + + /* + * Install a timecounter with a high quality level and low frequency. Check + * that it was not installed. + */ + hqlf->base.tc_get_timecount = GetTimecount; + hqlf->base.tc_counter_mask = 0xffffffff; + hqlf->base.tc_frequency = 0x10000000; + hqlf->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER + 1; + rtems_timecounter_install( &hqlf->base ); + + T_eq_u32( GetCounter( hqlf ), 0 ); + T_eq_u32( GetCounter( hqnf ), 2 ); + + sb = rtems_clock_get_monotonic_sbintime(); + T_eq_u32( GetCounter( hqlf ), 0 ); + T_eq_u32( GetCounter( hqnf ), 3 ); + T_eq_i64( sb, SBT_1S + 16 ); + + /* + * Install a timecounter with a high quality level and high frequency. Check + * that it was installed. + */ + hqhf->base.tc_get_timecount = GetTimecount; + hqhf->base.tc_counter_mask = 0xffffffff; + hqhf->base.tc_frequency = 0x40000000; + hqhf->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER + 1; + rtems_timecounter_install( &hqhf->base ); + + T_eq_u32( GetCounter( hqlf ), 0 ); + T_eq_u32( GetCounter( hqnf ), 4 ); + T_eq_u32( GetCounter( hqhf ), 1 ); + + sb = rtems_clock_get_monotonic_sbintime(); + T_eq_u32( GetCounter( hqlf ), 0 ); + T_eq_u32( GetCounter( hqnf ), 4 ); + T_eq_u32( GetCounter( hqhf ), 2 ); + T_eq_i64( sb, SBT_1S + 28 ); + + /* + * Install a timecounter with a low quality level. Check that it was not + * installed. + */ + lq->base.tc_get_timecount = GetTimecount; + lq->base.tc_counter_mask = 0xffffffff; + lq->base.tc_frequency = 0x80000000; + lq->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install( &lq->base ); + + T_eq_u32( GetCounter( hqlf ), 0 ); + T_eq_u32( GetCounter( hqnf ), 4 ); + T_eq_u32( GetCounter( hqhf ), 2 ); + T_eq_u32( GetCounter( lq ), 0 ); + + sb = rtems_clock_get_monotonic_sbintime(); + T_eq_u32( GetCounter( hqlf ), 0 ); + T_eq_u32( GetCounter( hqnf ), 4 ); + T_eq_u32( GetCounter( hqhf ), 3 ); + T_eq_u32( GetCounter( lq ), 0 ); + T_eq_i64( sb, SBT_1S + 32 ); +} + +/** + * @brief Call the directives to get the time in the highest resolution + * available to the system. + */ +static void ScoreTimecounterValInstall_Action_4( void ) +{ + Timecounter *tc; + uint32_t counter; + struct bintime bt; + struct timespec ts; + struct timeval tv; + + tc = &high_quality_high_frequency; + counter = GetCounter( tc ); + + /* + * Check that the timecounter was used by rtems_clock_get_realtime(). + */ + rtems_clock_get_realtime( &ts ); + T_eq_u32( GetCounter( tc ), counter + 1 ); + + /* + * Check that the timecounter was used by rtems_clock_get_realtime_bintime(). + */ + rtems_clock_get_realtime_bintime( &bt ); + T_eq_u32( GetCounter( tc ), counter + 2 ); + + /* + * Check that the timecounter was used by rtems_clock_get_realtime_timeval(). + */ + rtems_clock_get_realtime_timeval( &tv ); + T_eq_u32( GetCounter( tc ), counter + 3 ); + + /* + * Check that the timecounter was used by rtems_clock_get_monotonic(). + */ + rtems_clock_get_monotonic( &ts ); + T_eq_u32( GetCounter( tc ), counter + 4 ); + + /* + * Check that the timecounter was used by + * rtems_clock_get_monotonic_bintime(). + */ + rtems_clock_get_monotonic_bintime( &bt ); + T_eq_u32( GetCounter( tc ), counter + 5 ); + + /* + * Check that the timecounter was used by + * rtems_clock_get_monotonic_sbintime(). + */ + (void) rtems_clock_get_monotonic_sbintime(); + T_eq_u32( GetCounter( tc ), counter + 6 ); + + /* + * Check that the timecounter was used by + * rtems_clock_get_monotonic_timeval(). + */ + rtems_clock_get_monotonic_timeval( &tv ); + T_eq_u32( GetCounter( tc ), counter + 7 ); +} + +/** + * @brief Call the directives to get the time in a coarse resolution. + */ +static void ScoreTimecounterValInstall_Action_5( void ) +{ + Timecounter *tc; + uint32_t counter; + struct bintime bt; + struct timespec ts; + struct timeval tv; + + tc = &high_quality_high_frequency; + counter = GetCounter( tc ); + + /* + * Check that the timecounter was not used by + * rtems_clock_get_realtime_coarse(). + */ + rtems_clock_get_realtime_coarse( &ts ); + T_eq_u32( GetCounter( tc ), counter ); + + /* + * Check that the timecounter was not used by + * rtems_clock_get_realtime_coarse_bintime(). + */ + rtems_clock_get_realtime_coarse_bintime( &bt ); + T_eq_u32( GetCounter( tc ), counter ); + + /* + * Check that the timecounter was not used by + * rtems_clock_get_realtime_coarse_timeval(). + */ + rtems_clock_get_realtime_coarse_timeval( &tv ); + T_eq_u32( GetCounter( tc ), counter ); + + /* + * Check that the timecounter was not used by + * rtems_clock_get_monotonic_coarse(). + */ + rtems_clock_get_monotonic_coarse( &ts ); + T_eq_u32( GetCounter( tc ), counter ); + + /* + * Check that the timecounter was not used by + * rtems_clock_get_monotonic_coarse_bintime(). + */ + rtems_clock_get_monotonic_coarse_bintime( &bt ); + T_eq_u32( GetCounter( tc ), counter ); + + /* + * Check that the timecounter was not used by + * rtems_clock_get_monotonic_coarse_timeval(). + */ + rtems_clock_get_monotonic_coarse_timeval( &tv ); + T_eq_u32( GetCounter( tc ), counter ); + + /* + * Check that the timecounter was not used by rtems_clock_get_boot_time(). + */ + rtems_clock_get_boot_time( &ts ); + T_eq_u32( GetCounter( tc ), counter ); + + /* + * Check that the timecounter was not used by + * rtems_clock_get_boot_time_bintime(). + */ + rtems_clock_get_boot_time_bintime( &bt ); + T_eq_u32( GetCounter( tc ), counter ); + + /* + * Check that the timecounter was not used by + * rtems_clock_get_boot_time_timeval(). + */ + rtems_clock_get_boot_time_timeval( &tv ); + T_eq_u32( GetCounter( tc ), counter ); +} + +/** + * @brief Call the directives to get the time in the highest resolution + * available to the system. + */ +static void ScoreTimecounterValInstall_Action_6( void ) +{ + Timecounter *tc; + uint32_t counter; + struct bintime bt; + sbintime_t sb; + struct timespec ts; + struct timeval tv; + + tc = &high_quality_high_frequency; + counter = 3 * tc->base.tc_frequency + 123456789; + + /* + * Prepare the timecounter to get a large time difference. Check that + * rtems_clock_get_realtime() returns the correct time. + */ + SetCounter( tc, counter ); + rtems_clock_get_realtime( &ts ); + T_eq_i64( ts.tv_sec, 567993603 ); + T_eq_u64( ts.tv_nsec, 114978100 ); + + /* + * Prepare the timecounter to get a large time difference. Check that + * rtems_clock_get_realtime_bintime() returns the correct time. + */ + SetCounter( tc, counter ); + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567993603 ); + T_eq_u64( bt.frac, 2120971587975905280 ); + + /* + * Prepare the timecounter to get a large time difference. Check that + * rtems_clock_get_realtime_timeval() returns the correct time. + */ + SetCounter( tc, counter ); + rtems_clock_get_realtime_timeval( &tv ); + T_eq_i64( tv.tv_sec, 567993603 ); + T_eq_long( tv.tv_usec, 114978 ); + + /* + * Prepare the timecounter to get a large time difference. Check that + * rtems_clock_get_monotonic() returns the correct time. + */ + SetCounter( tc, counter ); + rtems_clock_get_monotonic( &ts ); + T_eq_i64( ts.tv_sec, 4 ); + T_eq_u64( ts.tv_nsec, 114978100 ); + + /* + * Prepare the timecounter to get a large time difference. Check that + * rtems_clock_get_monotonic_bintime() returns the correct time. + */ + SetCounter( tc, counter ); + rtems_clock_get_monotonic_bintime( &bt ); + T_eq_i64( bt.sec, 4 ); + T_eq_u64( bt.frac, 2120971587975905280 ); + + /* + * Prepare the timecounter to get a large time difference. Check that + * rtems_clock_get_monotonic_sbintime() returns the correct time. + */ + SetCounter( tc, counter ); + sb = rtems_clock_get_monotonic_sbintime(); + T_eq_i64( sb, 17673696364 ); + + /* + * Prepare the timecounter to get a large time difference. Check that + * rtems_clock_get_monotonic_timeval() returns the correct time. + */ + SetCounter( tc, counter ); + rtems_clock_get_monotonic_timeval( &tv ); + T_eq_i64( tv.tv_sec, 4 ); + T_eq_long( tv.tv_usec, 114978 ); +} + +/** + * @brief Update the oldest timehand after a large time interval. + */ +static void ScoreTimecounterValInstall_Action_7( void ) +{ + Timecounter *tc; + struct bintime bt; + + tc = &high_quality_high_frequency; + + SetCounter( tc, 0 ); + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567993600 ); + T_eq_u64( bt.frac, 103079215104 ); + + SetCounter( tc, 2 * tc->base.tc_frequency ); + CallTimecounterTick(); + + SetCounter( tc, 2 * tc->base.tc_frequency ); + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567993602 ); + T_eq_u64( bt.frac, 103079215104 ); +} + +/** + * @brief Call the simple timecounter tick service with non-zero delta and + * offset parameter values so that exactly one second passed. + */ +static void ScoreTimecounterValInstall_Action_8( void ) +{ + ISR_lock_Context lock_context; + Timecounter *tc; + struct bintime bt; + + tc = &high_quality_high_frequency; + + _Timecounter_Acquire( &lock_context ); + _Timecounter_Tick_simple( + tc->base.tc_frequency / 2, + GetCounter( tc ) - tc->base.tc_frequency / 2, + &lock_context + ); + + /* + * Check that exactly one second passed due to the simple clock tick service. + */ + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567993603 ); + T_eq_u64( bt.frac, 103079215104 ); +} + +/** + * @brief Install a very high quality timecounter with a low frequency to test + * the NTP support. + */ +static void ScoreTimecounterValInstall_Action_9( void ) +{ + Timecounter *tc; + struct bintime bt; + + tc = &very_high_quality; + tc->base.tc_get_timecount = GetTimecount; + tc->base.tc_counter_mask = 0xffffffff; + tc->base.tc_frequency = 0x01000000; + tc->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER + 2; + rtems_timecounter_install( &tc->base ); + + T_eq_u32( GetCounter( tc ), 1 ); + + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567993603 ); + T_eq_u64( bt.frac, 1219770712064 ); + + /* + * Let the seconds value of CLOCK_REALTIME not change. Check that the NTP + * update second handler is not called. + */ + _Timecounter_Set_NTP_update_second( NtpUpdateCounter ); + SetCounter( tc, tc->base.tc_frequency / 2 ); + CallTimecounterTick(); + _Timecounter_Set_NTP_update_second( NULL ); + + T_eq_u32( ntp_counter, 0 ); + + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567993603 ); + T_eq_u64( bt.frac, UINT64_C( 9223373256625487872 ) ); + + /* + * Let the seconds value of CLOCK_REALTIME change by one. Check that the NTP + * update second handler is called exactly once. + */ + _Timecounter_Set_NTP_update_second( NtpUpdateCounter ); + SetCounter( tc, tc->base.tc_frequency ); + CallTimecounterTick(); + _Timecounter_Set_NTP_update_second( NULL ); + + T_eq_u32( ntp_counter, 1 ); + + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567993604 ); + T_eq_u64( bt.frac, 1219770712064 ); + + /* + * Let the seconds value of CLOCK_REALTIME change by 200. Check that the NTP + * update second handler is called exactly 200 times. + */ + _Timecounter_Set_NTP_update_second( NtpUpdateCounter ); + SetCounter( tc, 201 * tc->base.tc_frequency ); + CallTimecounterTick(); + _Timecounter_Set_NTP_update_second( NULL ); + + T_eq_u32( ntp_counter, 201 ); + + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567993804 ); + T_eq_u64( bt.frac, 1219770712064 ); + + /* + * Let the seconds value of CLOCK_REALTIME change by 201. Check that the NTP + * update second handler is called exactly twice. + */ + _Timecounter_Set_NTP_update_second( NtpUpdateCounter ); + SetCounter( tc, 402 * tc->base.tc_frequency ); + CallTimecounterTick(); + _Timecounter_Set_NTP_update_second( NULL ); + + T_eq_u32( ntp_counter, 203 ); + + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567994005 ); + T_eq_u64( bt.frac, 1219770712064 ); + + /* + * Let the seconds value of CLOCK_REALTIME change by one. Check that the NTP + * update second handler is incremented the CLOCK_REALTIME by one second. + */ + _Timecounter_Set_NTP_update_second( NtpUpdateSecondIncrement ); + SetCounter( tc, 403 * tc->base.tc_frequency ); + CallTimecounterTick(); + _Timecounter_Set_NTP_update_second( NULL ); + + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567994007 ); + T_eq_u64( bt.frac, 1219770712064 ); + + /* + * Let the seconds value of CLOCK_REALTIME change by one. Check that the NTP + * update second handler is decremented the CLOCK_REALTIME by one second. + */ + _Timecounter_Set_NTP_update_second( NtpUpdateSecondDecrement ); + SetCounter( tc, 404 * tc->base.tc_frequency ); + CallTimecounterTick(); + _Timecounter_Set_NTP_update_second( NULL ); + + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567994007 ); + T_eq_u64( bt.frac, 1219770712064 ); + + /* + * Let the seconds value of CLOCK_REALTIME change by one. Check that the NTP + * update second handler increased the timecounter frequency. + */ + _Timecounter_Set_NTP_update_second( NtpUpdateAdjustmentFaster ); + SetCounter( tc, 405 * tc->base.tc_frequency ); + CallTimecounterTick(); + _Timecounter_Set_NTP_update_second( NULL ); + + SetCounter( tc, 406 * tc->base.tc_frequency ); + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567994009 ); + T_eq_u64( bt.frac, 92353004044288 ); + + /* + * Let the seconds value of CLOCK_REALTIME change by one. Check that the NTP + * update second handler decreased the timecounter frequency. + */ + _Timecounter_Set_NTP_update_second( NtpUpdateAdjustmentSlower ); + SetCounter( tc, 407 * tc->base.tc_frequency ); + CallTimecounterTick(); + _Timecounter_Set_NTP_update_second( NULL ); + + SetCounter( tc, 408 * tc->base.tc_frequency ); + rtems_clock_get_realtime_bintime( &bt ); + T_eq_i64( bt.sec, 567994011 ); + T_eq_u64( bt.frac, 92353004044288 ); +} + +/** + * @fn void T_case_body_ScoreTimecounterValInstall( void ) + */ +T_TEST_CASE( ScoreTimecounterValInstall ) +{ + ScoreTimecounterValInstall_Action_0(); + ScoreTimecounterValInstall_Action_1(); + ScoreTimecounterValInstall_Action_2(); + ScoreTimecounterValInstall_Action_3(); + ScoreTimecounterValInstall_Action_4(); + ScoreTimecounterValInstall_Action_5(); + ScoreTimecounterValInstall_Action_6(); + ScoreTimecounterValInstall_Action_7(); + ScoreTimecounterValInstall_Action_8(); + ScoreTimecounterValInstall_Action_9(); +} + +/** @} */ diff --git a/testsuites/validation/ts-validation-timecounter-0.c b/testsuites/validation/ts-validation-timecounter-0.c new file mode 100644 index 0000000000..9e4abeeab0 --- /dev/null +++ b/testsuites/validation/ts-validation-timecounter-0.c @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTestSuiteTestsuitesValidationTimecounter0 + */ + +/* + * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) + * + * 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. + */ + +/* + * This file is part of the RTEMS quality process and was automatically + * generated. If you find something that needs to be fixed or + * worded better please post a report or patch to an RTEMS mailing list + * or raise a bug report: + * + * https://www.rtems.org/bugs.html + * + * For information on updating and regenerating please refer to the How-To + * section in the Software Requirements Engineering chapter of the + * RTEMS Software Engineering manual. The manual is provided as a part of + * a release. For development sources please refer to the online + * documentation at: + * + * https://docs.rtems.org + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +/** + * @defgroup RTEMSTestSuiteTestsuitesValidationTimecounter0 \ + * spec:/testsuites/validation-timecounter-0 + * + * @ingroup RTEMSTestSuites + * + * @brief This validation test suite is intended test cases related to the + * installation of timecouters. The Clock Driver is disabled. + * + * @{ + */ + +const char rtems_test_name[] = "ValidationTimecounter0"; + +#define CONFIGURE_MAXIMUM_PROCESSORS 1 + +#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER + +#include "ts-default.h" + +/** @} */ diff --git a/testsuites/validation/ts-validation-timecounter-1.c b/testsuites/validation/ts-validation-timecounter-1.c new file mode 100644 index 0000000000..ec0ff027ee --- /dev/null +++ b/testsuites/validation/ts-validation-timecounter-1.c @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTestSuiteTestsuitesValidationTimecounter1 + */ + +/* + * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) + * + * 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. + */ + +/* + * This file is part of the RTEMS quality process and was automatically + * generated. If you find something that needs to be fixed or + * worded better please post a report or patch to an RTEMS mailing list + * or raise a bug report: + * + * https://www.rtems.org/bugs.html + * + * For information on updating and regenerating please refer to the How-To + * section in the Software Requirements Engineering chapter of the + * RTEMS Software Engineering manual. The manual is provided as a part of + * a release. For development sources please refer to the online + * documentation at: + * + * https://docs.rtems.org + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +/** + * @defgroup RTEMSTestSuiteTestsuitesValidationTimecounter1 \ + * spec:/testsuites/validation-timecounter-1 + * + * @ingroup RTEMSTestSuites + * + * @brief This validation test suite is intended test cases related to the use + * of timecouters. The Clock Driver is enabled. + * + * @{ + */ + +const char rtems_test_name[] = "ValidationTimecounter1"; + +#define CONFIGURE_MAXIMUM_PROCESSORS 4 + +#include "ts-default.h" + +/** @} */ diff --git a/testsuites/validation/ts-validation-timecounter-smp-0.c b/testsuites/validation/ts-validation-timecounter-smp-0.c new file mode 100644 index 0000000000..6ae0311b59 --- /dev/null +++ b/testsuites/validation/ts-validation-timecounter-smp-0.c @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTestSuiteTestsuitesValidationTimecounterSmp0 + */ + +/* + * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) + * + * 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. + */ + +/* + * This file is part of the RTEMS quality process and was automatically + * generated. If you find something that needs to be fixed or + * worded better please post a report or patch to an RTEMS mailing list + * or raise a bug report: + * + * https://www.rtems.org/bugs.html + * + * For information on updating and regenerating please refer to the How-To + * section in the Software Requirements Engineering chapter of the + * RTEMS Software Engineering manual. The manual is provided as a part of + * a release. For development sources please refer to the online + * documentation at: + * + * https://docs.rtems.org + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +/** + * @defgroup RTEMSTestSuiteTestsuitesValidationTimecounterSmp0 \ + * spec:/testsuites/validation-timecounter-smp-0 + * + * @ingroup RTEMSTestSuites + * + * @brief This validation test suite is intended test cases related to the use + * of timecouters. The Clock Driver is disabled. + * + * @{ + */ + +const char rtems_test_name[] = "ValidationTimecounterSmp0"; + +#define CONFIGURE_MAXIMUM_PROCESSORS 4 + +#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER + +#include "ts-default.h" + +/** @} */ -- cgit v1.2.3