/***************************************************************************/ /* Copyright (c) 2024 Microsoft Corporation */ /* 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. */ /* */ /* SPDX-License-Identifier: MIT */ /***************************************************************************/ /* This test is designed to test a simple sleep for 100 ticks. */ #include #include "tx_api.h" #include "tx_thread.h" #include "tx_timer.h" //#define DEBUG /* Define the ISR dispatch. */ extern VOID (*test_isr_dispatch)(void); static TX_THREAD thread_0; static int error = 0; static int isr_count = 0; #ifdef TEST_INTERRUPT_CONDITION #ifndef TX_NOT_INTERRUPTABLE #if defined(TX_WIN32_MEMORY_SIZE) || defined(TX_LINUX_MEMORY_SIZE) /* Use larger array size when running on Win32 test platform because of greater speed. */ #define ARRAY_SIZE 100 #else #define ARRAY_SIZE 10 #endif static UINT isr_test_suspend_interrupt = TX_TRUE; static UINT isr_test_suspend_interrupted_condition = TX_FALSE; static ULONG min_loop_count; static ULONG max_loop_count; static TX_SEMAPHORE test_semaphore; static ULONG loop_count; static volatile ULONG count; static volatile ULONG destination = 0; static ULONG array_delay[ARRAY_SIZE]; static ULONG start_time; static ULONG lower_bound; static ULONG upper_bound; static ULONG current_iterations; #ifdef DEBUG_1 static ULONG last_loop_count; #endif static ULONG delay_function(void) { ULONG accumulator; ULONG i; for (i = 0; i < ARRAY_SIZE; i++) array_delay[i] = i; for (i = 0; i < ARRAY_SIZE-4; i++) { array_delay[i] = (array_delay[i+1] * array_delay[i+2]) * (array_delay[i+3] * array_delay[i+4]); } accumulator = 0; for (i = 0; i < ARRAY_SIZE; i++) accumulator = accumulator + array_delay[i]; return(accumulator); } #endif #endif /* Define thread prototypes. */ static void thread_0_entry(ULONG thread_input); /* Prototype for test control return. */ void test_control_return(UINT status); /* Define the ISR dispatch routine. */ static void test_isr(void) { UINT status; #ifdef TEST_INTERRUPT_CONDITION #ifndef TX_NOT_INTERRUPTABLE ULONG i; /* Determine if we are in calibration mode. */ if ((loop_count) && (loop_count != 0xFFFFFFFF)) { if (loop_count < min_loop_count) min_loop_count = loop_count; if (loop_count > max_loop_count) max_loop_count = loop_count; lower_bound = loop_count - 1; upper_bound = loop_count + 1; if (lower_bound < min_loop_count) lower_bound = min_loop_count; if (upper_bound > max_loop_count) lower_bound = max_loop_count; if ((current_iterations < lower_bound) || (current_iterations > upper_bound)) current_iterations = lower_bound; #ifdef DEBUG_1 /* Last loop count. */ last_loop_count = loop_count; #endif /* Reset the loop count to all ones! */ loop_count = 0xFFFFFFFF; } count++; for (i = 0; i < (count%32); i++) destination++; /* Determine if the ISR is in the mode to wakeup the thread suspending with a timeout. */ if (isr_test_suspend_interrupt) { /* Determine if the thread is suspended on the semaphore... */ if (thread_0.tx_thread_state == TX_SEMAPHORE_SUSP) { /* Determine if the test condition is present... */ if ((_tx_thread_preempt_disable) && (thread_0.tx_thread_timer.tx_timer_internal_list_head == TX_NULL)) { /* Set the flag showing the condition is present. */ isr_test_suspend_interrupted_condition = TX_TRUE; /* All done with the test. */ isr_test_suspend_interrupt = TX_FALSE; } /* Post to the semaphore to wakeup the thread. */ tx_semaphore_put(&test_semaphore); } return; } #endif #endif /* Increment the ISR count. */ isr_count++; /* Call sleep from ISR to check for error! */ status = tx_thread_sleep(100); /* Check status. */ if (status != TX_CALLER_ERROR) { error = 1; } /* End the ISR. */ test_isr_dispatch = TX_NULL; } /* Define what the initial system looks like. */ #ifdef CTEST void test_application_define(void *first_unused_memory) #else void threadx_thread_sleep_for_100ticks_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; /* Put system definition stuff in here, e.g. thread creates and other assorted create information. */ status = tx_thread_create(&thread_0, "thread 0", thread_0_entry, 1, pointer, TEST_STACK_SIZE_PRINTF, 16, 16, 3, TX_AUTO_START); /* Check for status. */ if (status != TX_SUCCESS) { printf("Running Thread Sleep for 100 Ticks Test............................. ERROR #1\n"); test_control_return(1); } #ifdef TEST_INTERRUPT_CONDITION #ifndef TX_NOT_INTERRUPTABLE status = tx_semaphore_create(&test_semaphore, "test semaphore", 0); /* Check for status. */ if (status != TX_SUCCESS) { printf("Running Thread Sleep for 100 Ticks Test............................. ERROR #2\n"); test_control_return(1); } min_loop_count = 0xFFFFFFFF; max_loop_count = 0; loop_count = 0xFFFFFFFF; current_iterations = 0; #ifdef DEBUG_1 last_loop_count = 0x0; #endif #endif #endif } /* Define the test threads. */ static void thread_0_entry(ULONG thread_input) { UINT status; #ifdef TEST_INTERRUPT_CONDITION #ifndef TX_NOT_INTERRUPTABLE ULONG i; volatile ULONG value = 0; #endif #endif /* Inform user. */ printf("Running Thread Sleep for 100 Ticks Test............................. "); /* Call sleep with an expiration of 0 and test error code. */ status = tx_thread_sleep(0); /* Check error code. */ if (status != TX_SUCCESS) { /* Thread Simple Sleep error. */ printf("ERROR #3\n"); test_control_return(1); } #ifdef TEST_INTERRUPT_CONDITION #ifndef TX_NOT_INTERRUPTABLE isr_test_suspend_interrupt = TX_TRUE; isr_test_suspend_interrupted_condition = TX_FALSE; #endif #endif /* Setup the test ISR. */ test_isr_dispatch = test_isr; #ifdef TEST_INTERRUPT_CONDITION #ifndef TX_NOT_INTERRUPTABLE /* Callibrate the loop count from thread sleep. */ for (i = 0; i < 180; i++) { /* Sleep to get a fresh time. */ tx_thread_sleep(1); /* Set the loop count to 0 and start counting.... */ loop_count = 0; start_time = _tx_timer_system_clock; do { /* Call delay function. */ delay_function(); loop_count++; } while (start_time == _tx_timer_system_clock); /* Wait to reset the loop count. */ tx_thread_sleep(1); } #if 1 /* Setup the lower and upper bounds. */ lower_bound = min_loop_count; if (lower_bound > 5) lower_bound = lower_bound - 5; upper_bound = max_loop_count + 5; #else /* Setup the lower and upper bounds. */ lower_bound = min_loop_count; upper_bound = max_loop_count; #endif current_iterations = lower_bound; #ifdef DEBUG i = 0; #endif while (isr_test_suspend_interrupted_condition != TX_TRUE) { /* Sleep to get a frest timer slot. */ tx_thread_sleep(1); /* Loop to delay to next interrupt. */ loop_count = 0; start_time = _tx_timer_system_clock; do { /* Call delay function. */ delay_function(); loop_count++; } while (loop_count < current_iterations); /* Check for a timer interrupt... if so, just skip the semaphore get. */ if (start_time != _tx_timer_system_clock) continue; /* Suspend on the semaphore for 20 ticks... */ tx_semaphore_get(&test_semaphore, 20); /* Adjust the current iterations. */ current_iterations++; if (current_iterations > upper_bound) { if (lower_bound > min_loop_count) lower_bound--; if (upper_bound < max_loop_count) upper_bound++; current_iterations = lower_bound; } /* Set the tick count simply to use value. */ tx_time_set(value); #ifdef DEBUG /* Debug block. */ i++; if ((i % 180) == 0) { printf("*** update ***\n"); if (loop_count == 0xFFFFFFFF) printf("loop count: NA\n"); else printf("loop count: %lu\n", loop_count); printf("current: %lu\n", current_iterations); printf("last loop count: %lu\n", last_loop_count); printf("minimum: %lu\n", min_loop_count); printf("maximum: %lu\n", max_loop_count); printf("lower bound: %lu\n", lower_bound); printf("upper bound: %lu\n", upper_bound); printf("count: %lu\n", i); } #endif } #ifdef DEBUG /* Debug block */ printf("*** final ***\n"); if (loop_count == 0xFFFFFFFF) printf("loop count: NA\n"); else printf("loop count: %lu\n", loop_count); printf("current: %lu\n", current_iterations); printf("last loop count: %lu\n", last_loop_count); printf("minimum: %lu\n", min_loop_count); printf("maximum: %lu\n", max_loop_count); printf("lower bound: %lu\n", lower_bound); printf("upper bound: %lu\n", upper_bound); printf("count: %lu\n", i); #endif /* Clear the tick count. */ tx_time_set(0); /* Sleep for 100 ticks. */ tx_thread_sleep(100); /* Check for error. */ if (tx_time_get() < 100) { /* Thread Simple Sleep error. */ printf("ERROR #4\n"); test_control_return(1); } #endif #endif /* Clear the tick count. */ tx_time_set(0); /* Sleep for 100 ticks. */ status = tx_thread_sleep(100); /* Determine if the sleep was accurate. */ if ((status != TX_SUCCESS) || (tx_time_get() < 100) || (tx_time_get() > 101)) { /* Thread Simple Sleep error. */ printf("ERROR #5\n"); test_control_return(1); } /* Check to make sure the ISR happened and the proper return value was present. */ if ((isr_count == 0) || (error)) { /* Thread Simple Sleep error. */ printf("ERROR #6\n"); test_control_return(1); } else { /* Successful Simple Sleep test. */ printf("SUCCESS!\n"); test_control_return(0); } }