Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions common/src/tx_thread_create.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/

// Some portions generated by Copilot (Opus 5).


/**************************************************************************/
/**************************************************************************/
Expand Down Expand Up @@ -93,18 +95,26 @@ UCHAR *temp_ptr;
ALIGN_TYPE new_stack_start;
ALIGN_TYPE updated_stack_start;
#endif
#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING) && !defined(TX_DISABLE_STACK_FILLING)
ULONG stack_fill_value;
#endif

#ifndef TX_DISABLE_STACK_FILLING
#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING)

/* Initialize the stack fill value to a 8-bit random value. */
thread_ptr -> tx_thread_stack_fill_value = ((ULONG) TX_RAND()) & 0xFFUL;
stack_fill_value = ((ULONG) TX_RAND()) & 0xFFUL;

/* Duplicate the random value in each of the 4 bytes of the stack fill value. */
thread_ptr -> tx_thread_stack_fill_value = thread_ptr -> tx_thread_stack_fill_value |
(thread_ptr -> tx_thread_stack_fill_value << 8) |
(thread_ptr -> tx_thread_stack_fill_value << 16) |
(thread_ptr -> tx_thread_stack_fill_value << 24);
stack_fill_value = stack_fill_value |
(stack_fill_value << 8) |
(stack_fill_value << 16) |
(stack_fill_value << 24);

/* Store the fill value in the control block so that the stack fill below picks it up
through the TX_STACK_FILL macro. The control block is cleared further down in this
function, so the value is stored again once that has been done. */
thread_ptr -> tx_thread_stack_fill_value = stack_fill_value;
#endif

/* Set the thread stack to a pattern prior to creating the initial
Expand Down Expand Up @@ -150,6 +160,14 @@ ALIGN_TYPE updated_stack_start;
/* Initialize thread control block to all zeros. */
TX_MEMSET(thread_ptr, 0, (sizeof(TX_THREAD)));

#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING) && !defined(TX_DISABLE_STACK_FILLING)

/* Clearing the control block reset the stack fill value, so store the value that was
actually used to fill the stack again. Otherwise the stack checking and stack analyze
routines would look for a pattern that is not the one present in the stack. */
thread_ptr -> tx_thread_stack_fill_value = stack_fill_value;
#endif

/* Place the supplied parameters into the thread's control block. */
thread_ptr -> tx_thread_name = name_ptr;
thread_ptr -> tx_thread_entry = entry_function;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ UCHAR *temp_ptr;
ALIGN_TYPE new_stack_start;
ALIGN_TYPE updated_stack_start;
#endif
#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING) && !defined(TX_DISABLE_STACK_FILLING)
ULONG stack_fill_value;
#endif
TXM_MODULE_THREAD_ENTRY_INFO *thread_entry_info;
VOID *stack_end;
ULONG i;
Expand Down Expand Up @@ -263,13 +266,18 @@ ULONG i;
#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING)

/* Initialize the stack fill value to a 8-bit random value. */
thread_ptr -> tx_thread_stack_fill_value = ((ULONG) TX_RAND()) & 0xFFUL;
stack_fill_value = ((ULONG) TX_RAND()) & 0xFFUL;

/* Duplicate the random value in each of the 4 bytes of the stack fill value. */
thread_ptr -> tx_thread_stack_fill_value = thread_ptr -> tx_thread_stack_fill_value |
(thread_ptr -> tx_thread_stack_fill_value << 8) |
(thread_ptr -> tx_thread_stack_fill_value << 16) |
(thread_ptr -> tx_thread_stack_fill_value << 24);
stack_fill_value = stack_fill_value |
(stack_fill_value << 8) |
(stack_fill_value << 16) |
(stack_fill_value << 24);

/* Store the fill value in the control block so that the stack fill below picks it up
through the TX_STACK_FILL macro. The control block is cleared further down in this
function, so the value is stored again once that has been done. */
thread_ptr -> tx_thread_stack_fill_value = stack_fill_value;
#endif

/* Set the thread stack to a pattern prior to creating the initial
Expand Down Expand Up @@ -311,6 +319,14 @@ ULONG i;
/* Initialize thread control block to all zeros. */
TX_MEMSET(thread_ptr, 0, sizeof(TX_THREAD));

#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING) && !defined(TX_DISABLE_STACK_FILLING)

/* Clearing the control block reset the stack fill value, so store the value that was
actually used to fill the stack again. Otherwise the stack checking and stack analyze
routines would look for a pattern that is not the one present in the stack. */
thread_ptr -> tx_thread_stack_fill_value = stack_fill_value;
#endif

/* Note that TX_ENABLE_STACK_CHECKING is not supported for module threads. A user mode
module thread owns two stacks and the scheduler swaps tx_thread_stack_start,
tx_thread_stack_end and tx_thread_stack_size over to the kernel stack whenever the
Expand Down
28 changes: 23 additions & 5 deletions common_smp/src/tx_thread_create.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/

// Some portions generated by Copilot (Opus 5).


/**************************************************************************/
/**************************************************************************/
Expand Down Expand Up @@ -93,19 +95,27 @@ UCHAR *temp_ptr;
ALIGN_TYPE new_stack_start;
ALIGN_TYPE updated_stack_start;
#endif
#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING) && !defined(TX_DISABLE_STACK_FILLING)
ULONG stack_fill_value;
#endif


#ifndef TX_DISABLE_STACK_FILLING
#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING)

/* Initialize the stack fill value to a 8-bit random value. */
thread_ptr -> tx_thread_stack_fill_value = ((ULONG) TX_RAND()) & 0xFFUL;
stack_fill_value = ((ULONG) TX_RAND()) & 0xFFUL;

/* Duplicate the random value in each of the 4 bytes of the stack fill value. */
thread_ptr -> tx_thread_stack_fill_value = thread_ptr -> tx_thread_stack_fill_value |
(thread_ptr -> tx_thread_stack_fill_value << 8) |
(thread_ptr -> tx_thread_stack_fill_value << 16) |
(thread_ptr -> tx_thread_stack_fill_value << 24);
stack_fill_value = stack_fill_value |
(stack_fill_value << 8) |
(stack_fill_value << 16) |
(stack_fill_value << 24);

/* Store the fill value in the control block so that the stack fill below picks it up
through the TX_STACK_FILL macro. The control block is cleared further down in this
function, so the value is stored again once that has been done. */
thread_ptr -> tx_thread_stack_fill_value = stack_fill_value;
#endif

/* Set the thread stack to a pattern prior to creating the initial
Expand Down Expand Up @@ -143,6 +153,14 @@ ALIGN_TYPE updated_stack_start;
/* Initialize thread control block to all zeros. */
TX_MEMSET(thread_ptr, 0, sizeof(TX_THREAD));

#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING) && !defined(TX_DISABLE_STACK_FILLING)

/* Clearing the control block reset the stack fill value, so store the value that was
actually used to fill the stack again. Otherwise the stack checking and stack analyze
routines would look for a pattern that is not the one present in the stack. */
thread_ptr -> tx_thread_stack_fill_value = stack_fill_value;
#endif

/* Place the supplied parameters into the thread's control block. */
thread_ptr -> tx_thread_name = name_ptr;
thread_ptr -> tx_thread_entry = entry_function;
Expand Down
1 change: 1 addition & 0 deletions test/smp/cmake/regression/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ set(regression_test_cases
${SOURCE_DIR}/threadx_thread_sleep_for_100ticks_test.c
${SOURCE_DIR}/threadx_thread_sleep_terminate_test.c
${SOURCE_DIR}/threadx_thread_stack_checking_test.c
${SOURCE_DIR}/threadx_thread_stack_fill_value_test.c
${SOURCE_DIR}/threadx_thread_terminate_delete_test.c
${SOURCE_DIR}/threadx_thread_exit_callback_transition_test.c
${SOURCE_DIR}/threadx_smp_thread_exit_callback_remote_test.c
Expand Down
2 changes: 2 additions & 0 deletions test/smp/regression/testcontrol.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ void threadx_thread_create_preemption_threshold_application_define(void *);
void threadx_thread_information_application_define(void *);
void threadx_thread_reset_application_define(void *);
void threadx_thread_stack_checking_application_define(void *);
void threadx_thread_stack_fill_value_application_define(void *);

void threadx_time_get_set_application_define(void *);

Expand Down Expand Up @@ -401,6 +402,7 @@ TEST_ENTRY test_control_tests[] =
threadx_thread_information_application_define,
threadx_thread_reset_application_define,
threadx_thread_stack_checking_application_define,
threadx_thread_stack_fill_value_application_define,

threadx_time_get_set_application_define,

Expand Down
190 changes: 190 additions & 0 deletions test/smp/regression/threadx_thread_stack_fill_value_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/***************************************************************************/
/* 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 */
/***************************************************************************/

// Some portions generated by Copilot (Opus 5).

/* This test checks that the stack fill value recorded in a thread control block is the
value that was actually written into that thread's stack. The two used to disagree
when TX_ENABLE_RANDOM_NUMBER_STACK_FILLING was enabled, because the control block was
cleared after the random value had been chosen and the stack had been filled with it,
which left the stack checking and stack analyze routines looking for a pattern that is
not the one present in the stack. */

#include <stdio.h>
#include "tx_api.h"


/* Number of probe threads created. A random fill value can legitimately come out as zero,
which hides the defect for that one thread, so several threads are created and at least
one of them is required to have produced a non-zero pattern. */

#define TEST_PROBE_THREADS 16


static unsigned long thread_0_counter = 0;
static TX_THREAD thread_0;

static TX_THREAD probe_thread;
static ULONG probe_stack[TX_MINIMUM_STACK / sizeof(ULONG)];


/* Define task prototypes. */

static void thread_0_entry(ULONG task_input);


/* Prototype for test control return. */

void test_control_return(UINT status);


/* Define what the initial system looks like. */

#ifdef CTEST
void test_application_define(void *first_unused_memory)
#else
void threadx_thread_stack_fill_value_application_define(void *first_unused_memory)
#endif
{

UINT status;
CHAR *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, 0,
pointer, TEST_STACK_SIZE_PRINTF,
16, 16, TX_NO_TIME_SLICE, TX_AUTO_START);

/* Check for status. */
if (status != TX_SUCCESS)
{

printf("Running Thread Stack Fill Value Test................................ ERROR #1\n");
test_control_return(1);
}
}


/* Define the test threads. */

static void thread_0_entry(ULONG thread_input)
{

UINT status;
UINT i;
ULONG stack_pattern;
UINT non_zero_seen = TX_FALSE;


/* Increment thread 0 counter. */
thread_0_counter++;

/* Inform user of success getting to this test. */
printf("Running Thread Stack Fill Value Test................................ ");

for (i = 0; i < TEST_PROBE_THREADS; i++)
{

/* Create a thread that is never started, so that its stack still holds nothing but
the fill pattern and the initial stack frame built at the top of the stack. */
status = tx_thread_create(&probe_thread, "probe thread", thread_0_entry, 0,
probe_stack, sizeof(probe_stack),
17, 17, TX_NO_TIME_SLICE, TX_DONT_START);

/* Check for status. */
if (status != TX_SUCCESS)
{

printf("ERROR #2\n");
test_control_return(1);
}

/* Pick up the pattern the create service wrote into the unused part of the stack. */
stack_pattern = *(((ULONG *) probe_thread.tx_thread_stack_start) + 4);

#ifndef TX_DISABLE_STACK_FILLING
#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING)

/* The control block must hold the value that was written into the stack. */
if (probe_thread.tx_thread_stack_fill_value != stack_pattern)
{

printf("ERROR #3\n");
test_control_return(1);
}

/* The random value is duplicated into all four bytes of the fill value. */
if ((stack_pattern & 0xFFUL) !=
((stack_pattern >> 24) & 0xFFUL))
{

printf("ERROR #4\n");
test_control_return(1);
}

if (stack_pattern != ((ULONG) 0))
{

non_zero_seen = TX_TRUE;
}
#else

/* Without random filling, the pattern is the fixed one. */
if (stack_pattern != ((ULONG) 0xEFEFEFEFUL))
{

printf("ERROR #5\n");
test_control_return(1);
}

non_zero_seen = TX_TRUE;
#endif
#else

/* Stack filling is disabled, so there is nothing to compare. */
non_zero_seen = TX_TRUE;
#endif

/* Terminate and delete the probe thread so that the next pass starts from a clean
slate. A thread created with TX_DONT_START is suspended rather than completed,
so it must be terminated before it can be deleted. */
status = tx_thread_terminate(&probe_thread);

if (status == TX_SUCCESS)
{

status = tx_thread_delete(&probe_thread);
}

/* Check for status. */
if (status != TX_SUCCESS)
{

printf("ERROR #6\n");
test_control_return(1);
}
}

/* A run in which every fill value came out as zero would prove nothing. */
if (non_zero_seen != TX_TRUE)
{

printf("ERROR #7\n");
test_control_return(1);
}

/* Success! */
printf("SUCCESS!\n");
test_control_return(0);
}
1 change: 1 addition & 0 deletions test/tx/cmake/regression/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ set(regression_test_cases
${SOURCE_DIR}/threadx_thread_sleep_for_100ticks_test.c
${SOURCE_DIR}/threadx_thread_sleep_terminate_test.c
${SOURCE_DIR}/threadx_thread_stack_checking_test.c
${SOURCE_DIR}/threadx_thread_stack_fill_value_test.c
${SOURCE_DIR}/threadx_thread_terminate_delete_test.c
${SOURCE_DIR}/threadx_thread_exit_callback_transition_test.c
${SOURCE_DIR}/threadx_thread_time_slice_change_test.c
Expand Down
Loading
Loading