/*************************************************************************** * Copyright (c) 2026 Eclipse ThreadX contributors * * This program and the accompanying materials are made available under the * terms of the MIT License which is available at * https://opensource.org/licenses/MIT. * * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5). * The AI-generated portions may be considered public domain (CC0-1.0) * and not subject to the project's licence. The human contributor has * reviewed and verified that the code is correct. * * SPDX-License-Identifier: MIT and CC0-1.0 **************************************************************************/ /* This test takes the timer thread's loop round to its exit. The timer thread's body is one loop over a condition that under TX_MISRA_ENABLE is a call rather than the literal one the other six configurations compile, so that the constant is not written into the controlling expression. The function behind it takes nothing and returns true, so the loop's exit arm never executes and, in the six configurations without the macro, does not exist at all. That function is the only thing in the construct that is not a constant, and the timer thread's loop is its only user anywhere in the kernel. The test defines it itself; the kernel is built shared and the call goes through the procedure linkage table, so the definition here is the one the loop reaches. What this costs is the timer thread. The loop is the whole body of the timer thread's entry function, so an exit ends the thread, and from that point the system has no thread to process timer expirations, thread timeouts or time slices. The test therefore does it deliberately and last: it proves the timer is working first, arms the shim, waits for the thread to end, and reports. Nothing after the arming depends on a tick. Read the coverage this contributes with that in mind. It is coverage of a kernel whose MISRA loop condition is the test's rather than the library's, and of a system the test has just taken the timer thread out of. The shim's own body is covered by every other test, which call it through this same loop thousands of times. */ #include #include "tx_api.h" #define TX_SOURCE_CODE #include "tx_thread.h" #include "tx_timer.h" #define TEST_PRIORITY 16 /* The timer must expire enough times before the shim is armed for the test to have shown that the thread is doing its work. */ #define EXPIRATIONS_BEFORE_ARMING 3 /* How long to wait for the thread to end, in ticks. One is enough; this is a bound so that a shim the kernel never reaches fails the test rather than hanging it. */ #define ARMED_TICK_BUDGET 200 static unsigned long thread_0_counter = 0; static TX_THREAD thread_0; static TX_TIMER timer_0; static volatile ULONG timer_0_counter = 0; #if defined(TX_MISRA_ENABLE) && !defined(TX_TIMER_PROCESS_IN_ISR) && !defined(TX_NO_TIMER) #define TEST_DRIVES_THE_LOOP /* While this is set the shim below reports that the loop should end. */ static volatile UINT shim_armed = TX_FALSE; /* How many times it has done so, which is how many times the exit arm has been taken. */ static volatile ULONG shim_exits = 0; /* The MISRA loop condition, defined here so that it is this one the timer thread's loop calls. The library's returns true; this one returns false once it is armed. */ UINT _tx_misra_always_true(void) { if (shim_armed == TX_TRUE) { shim_exits++; return(TX_FALSE); } return(TX_TRUE); } #endif /* Define thread prototypes. */ static void thread_0_entry(ULONG thread_input); /* Prototype for test control return. */ void test_control_return(UINT status); /* Count the expirations, so the test can show the timer thread was running before it ends it. */ static void timer_0_entry(ULONG timer_input) { timer_0_counter++; } static void thread_0_entry(ULONG thread_input) { UINT status; ULONG deadline; /* Increment thread 0 counter. */ thread_0_counter++; /* Inform user of success getting to this test. */ printf("Running Timer MISRA Loop Test..................................... "); status = tx_timer_activate(&timer_0); if (status != TX_SUCCESS) { printf("ERROR #2\n"); test_control_return(1); } /* The timer thread has to be doing its work before the test ends it, otherwise an exit proves nothing about the loop it exited from. */ deadline = _tx_timer_system_clock + ((ULONG) ARMED_TICK_BUDGET); while (timer_0_counter < ((ULONG) EXPIRATIONS_BEFORE_ARMING)) { if (_tx_timer_system_clock > deadline) { printf("ERROR #3\n"); test_control_return(1); } } #ifdef TEST_DRIVES_THE_LOOP /* From here on nothing may depend on a tick. */ shim_armed = TX_TRUE; /* The thread ends the next time the tick resumes it and the loop retests its condition. */ deadline = _tx_timer_system_clock + ((ULONG) ARMED_TICK_BUDGET); while (_tx_timer_thread.tx_thread_state != TX_COMPLETED) { if (_tx_timer_system_clock > deadline) { /* The tick is still running -- the clock is what this waits on -- so a thread that has not ended means the loop reached the library's condition rather than this test's. */ shim_armed = TX_FALSE; printf("ERROR #4\n"); test_control_return(1); } } shim_armed = TX_FALSE; /* The loop tested its condition once more and took the arm that leaves it. */ if (shim_exits != ((ULONG) 1)) { printf("ERROR #5\n"); test_control_return(1); } #endif status = tx_timer_deactivate(&timer_0); if (status != TX_SUCCESS) { printf("ERROR #6\n"); test_control_return(1); } /* Success! */ printf("SUCCESS!\n"); test_control_return(0); } /* Define what the initial system looks like. */ #ifdef CTEST void test_application_define(void *first_unused_memory) #else void threadx_timer_misra_loop_application_define(void *first_unused_memory) #endif { UINT status; CHAR *pointer; /* Put first available memory address into a character pointer. */ pointer = (CHAR *) first_unused_memory; status = tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, pointer, TEST_STACK_SIZE_PRINTF, TEST_PRIORITY, TEST_PRIORITY, TX_NO_TIME_SLICE, TX_AUTO_START); pointer = pointer + TEST_STACK_SIZE_PRINTF; /* Check for status. */ if (status != TX_SUCCESS) { printf("Running Timer MISRA Loop Test..................................... ERROR #1\n"); test_control_return(1); } /* A tick's worth of work every tick, so the timer thread is resumed repeatedly and the loop retests its condition each time. */ status = tx_timer_create(&timer_0, "timer 0", timer_0_entry, 0, 1, 1, TX_NO_ACTIVATE); /* Check for status. */ if (status != TX_SUCCESS) { printf("Running Timer MISRA Loop Test..................................... ERROR #1\n"); test_control_return(1); } }