mirror of
https://github.com/azure-rtos/threadx
synced 2025-01-30 08:02:57 +08:00
391 lines
9.8 KiB
C
391 lines
9.8 KiB
C
/* This test checks out the delayed suspension clear from tx_thread_resume. */
|
|
|
|
#include <stdio.h>
|
|
#include "tx_api.h"
|
|
#include "tx_thread.h"
|
|
#include "tx_timer.h"
|
|
|
|
|
|
#define DEMO_STACK_SIZE TEST_STACK_SIZE_PRINTF
|
|
|
|
|
|
/* Define the ThreadX object control blocks... */
|
|
|
|
static TX_THREAD thread_0;
|
|
static TX_THREAD thread_1;
|
|
static TX_SEMAPHORE semaphore_0;
|
|
|
|
|
|
/* Define thread prototypes. */
|
|
|
|
static void thread_0_entry(ULONG thread_input);
|
|
static void thread_1_entry(ULONG thread_input);
|
|
|
|
|
|
/* Prototype for test control return. */
|
|
void test_control_return(UINT status);
|
|
|
|
|
|
/* Define the ISR dispatch routine. */
|
|
|
|
#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
|
|
|
|
|
|
/* Define the ISR dispatch. */
|
|
|
|
extern VOID (*test_isr_dispatch)(void);
|
|
static void thread_2_entry(ULONG thread_input);
|
|
|
|
static UINT delayed_suspend_set;
|
|
|
|
static ULONG thread_2_counter;
|
|
static ULONG thread_2_counter_capture;
|
|
|
|
static ULONG min_loop_count;
|
|
static ULONG max_loop_count;
|
|
static ULONG loop_count;
|
|
static volatile ULONG count;
|
|
static volatile ULONG destination = 0;
|
|
static ULONG start_time;
|
|
static ULONG lower_bound;
|
|
static ULONG upper_bound;
|
|
static ULONG current_itterations;
|
|
#ifdef DEBUG_1
|
|
static ULONG last_loop_count;
|
|
#endif
|
|
static TX_THREAD thread_2;
|
|
static TX_SEMAPHORE semaphore_1;
|
|
|
|
static ULONG array_delay[ARRAY_SIZE];
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
static void test_isr(void)
|
|
{
|
|
ULONG i;
|
|
|
|
/* Determine if we are in calibration mode. */
|
|
if (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_itterations < lower_bound) || (current_itterations > upper_bound))
|
|
current_itterations = 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++;
|
|
|
|
/* Check to see if the interrupt occurred in the middle of the suspension. */
|
|
if ((thread_2.tx_thread_suspending) && (delayed_suspend_set == 0))
|
|
{
|
|
|
|
/* Yes, we have taken the interrupt in the middle of a thread suspension. */
|
|
|
|
/* Indicate we have got the condition. */
|
|
delayed_suspend_set = 1;
|
|
|
|
/* Capture the current thread 2 counter. */
|
|
thread_2_counter_capture = thread_2_counter;
|
|
|
|
/* Now attempt to set the delayed suspension. */
|
|
tx_thread_suspend(&thread_2);
|
|
|
|
/* Check for the delayed suspension flag being set. */
|
|
if (thread_2.tx_thread_delayed_suspend != 1)
|
|
{
|
|
|
|
/* Error! Setup the counters to indicate an error. */
|
|
thread_2_counter = 0xEEEEEEEE;
|
|
thread_2_counter_capture = 0xFFFFFFFF;
|
|
}
|
|
|
|
/* Now, abort the suspension for thread 2... the thread should switch to a pure suspended state. */
|
|
tx_thread_wait_abort(&thread_2);
|
|
|
|
/* Check for the proper state. */
|
|
if (thread_2.tx_thread_state != TX_SUSPENDED)
|
|
{
|
|
|
|
/* Error! Setup the counters to indicate an error. */
|
|
thread_2_counter = 0xEEEEEEEE;
|
|
thread_2_counter_capture = 0xFFFFFFFF;
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
/* Define what the initial system looks like. */
|
|
|
|
#ifdef CTEST
|
|
void test_application_define(void *first_unused_memory)
|
|
#else
|
|
void threadx_thread_delayed_suspension_application_define(void *first_unused_memory)
|
|
#endif
|
|
{
|
|
|
|
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. */
|
|
|
|
/* Create the main thread. */
|
|
tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
|
|
pointer, DEMO_STACK_SIZE,
|
|
2, 2, TX_NO_TIME_SLICE, TX_AUTO_START);
|
|
pointer = pointer + DEMO_STACK_SIZE;
|
|
|
|
/* Create threads 1 and 2. */
|
|
tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1,
|
|
pointer, DEMO_STACK_SIZE,
|
|
2, 2, TX_NO_TIME_SLICE, TX_AUTO_START);
|
|
pointer = pointer + DEMO_STACK_SIZE;
|
|
|
|
/* Create the semaphore. */
|
|
tx_semaphore_create(&semaphore_0, "semaphore 0", 0);
|
|
|
|
#ifndef TX_NOT_INTERRUPTABLE
|
|
|
|
tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2,
|
|
pointer, DEMO_STACK_SIZE,
|
|
1, 1, TX_NO_TIME_SLICE, TX_DONT_START);
|
|
pointer = pointer + DEMO_STACK_SIZE;
|
|
|
|
tx_semaphore_create(&semaphore_1, "semaphore 1", 0);
|
|
|
|
thread_2_counter = 0;
|
|
thread_2_counter_capture = 0;
|
|
min_loop_count = 0xFFFFFFFF;
|
|
max_loop_count = 0;
|
|
loop_count = 0xFFFFFFFF;
|
|
#ifdef DEBUG_1
|
|
last_loop_count = 0;
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
/* Define the test threads. */
|
|
|
|
static void thread_0_entry(ULONG thread_input)
|
|
{
|
|
|
|
UINT status;
|
|
|
|
|
|
/* Inform user. */
|
|
printf("Running Thread Delayed Suspension Clearing Test..................... ");
|
|
|
|
/* Relinquish to the other thread. */
|
|
tx_thread_relinquish();
|
|
|
|
/* At this point thread 1 has suspended on the semaphore. */
|
|
|
|
/* Suspend the already suspended thread. */
|
|
tx_thread_suspend(&thread_1);
|
|
|
|
/* Set the semaphore, which should make it go into a suspend state. */
|
|
tx_semaphore_put(&semaphore_0);
|
|
|
|
/* Resume the other thread so it runs again. */
|
|
tx_thread_resume(&thread_1);
|
|
|
|
/* Relinquish so it can run again. */
|
|
tx_thread_relinquish();
|
|
|
|
/* Suspend the already suspended thread. */
|
|
tx_thread_suspend(&thread_1);
|
|
|
|
/* Now, clear the delayed suspension. */
|
|
status = tx_thread_resume(&thread_1);
|
|
|
|
if (status != TX_SUSPEND_LIFTED)
|
|
{
|
|
|
|
/* Delayed suspension error. */
|
|
printf("ERROR #1\n");
|
|
test_control_return(1);
|
|
}
|
|
|
|
#ifndef TX_NOT_INTERRUPTABLE
|
|
|
|
/* Setup the test ISR. */
|
|
test_isr_dispatch = test_isr;
|
|
|
|
/* Resume the test thread. */
|
|
tx_thread_resume(&thread_2);
|
|
|
|
/* Wait until we see the delayed suspension set flag. */
|
|
while(delayed_suspend_set == 0)
|
|
{
|
|
|
|
/* Abort the suspension for thread 2. */
|
|
tx_thread_wait_abort(&thread_2);
|
|
|
|
/* Just relinquish. */
|
|
tx_thread_relinquish();
|
|
}
|
|
|
|
/* Relinquish one more time to make sure thread 2 could run if it is ready. */
|
|
tx_thread_relinquish();
|
|
|
|
/* At this point, check for an error. */
|
|
if (thread_2_counter != thread_2_counter_capture)
|
|
{
|
|
|
|
/* Delayed suspension error... thread kept running! */
|
|
printf("ERROR #2\n");
|
|
test_control_return(1);
|
|
}
|
|
#endif
|
|
|
|
/* Successful test. */
|
|
printf("SUCCESS!\n");
|
|
test_control_return(0);
|
|
}
|
|
|
|
|
|
static void thread_1_entry(ULONG thread_input)
|
|
{
|
|
|
|
UINT status;
|
|
|
|
/* This thread simply gets the semaphore... */
|
|
while(1)
|
|
{
|
|
|
|
/* Get semaphore. */
|
|
status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER);
|
|
|
|
/* Check completion status. */
|
|
if (status != TX_SUCCESS)
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
#ifndef TX_NOT_INTERRUPTABLE
|
|
|
|
|
|
static void thread_2_entry(ULONG thread_input)
|
|
{
|
|
|
|
ULONG i;
|
|
|
|
/* Callibrate the loop count from thread sleep. */
|
|
for (i = 0; i < 10; i++)
|
|
{
|
|
|
|
/* Sleep to get a fresh time. */
|
|
tx_thread_sleep(1);
|
|
|
|
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);
|
|
}
|
|
|
|
/* 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;
|
|
|
|
current_itterations = lower_bound;
|
|
|
|
/* This thread simply suspends over and over... */
|
|
while(1)
|
|
{
|
|
|
|
/* Sleep to get a fresh starting time. */
|
|
tx_thread_sleep(1);
|
|
|
|
loop_count = 0;
|
|
start_time = _tx_timer_system_clock;
|
|
do
|
|
{
|
|
/* Call delay function. */
|
|
delay_function();
|
|
loop_count++;
|
|
} while (loop_count < current_itterations);
|
|
|
|
/* Suspend this thread. */
|
|
tx_semaphore_get(&semaphore_1, TX_WAIT_FOREVER);
|
|
|
|
/* Adjust the current itterations. */
|
|
current_itterations++;
|
|
if (current_itterations > upper_bound)
|
|
{
|
|
if (lower_bound > min_loop_count)
|
|
lower_bound--;
|
|
if (upper_bound < max_loop_count)
|
|
upper_bound++;
|
|
current_itterations = lower_bound;
|
|
}
|
|
|
|
/* Increment the thread counter. */
|
|
thread_2_counter++;
|
|
}
|
|
}
|
|
|
|
#endif
|