summaryrefslogtreecommitdiff
path: root/test/smp/regression/threadx_thread_misaligned_stack_test.c
blob: fa72aab5a1f6913b0645d7d4aebb1adfafb6ffb3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/***************************************************************************
 * 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 creates a thread whose stack does not begin on a ULONG boundary.
   It is the SMP counterpart of the ThreadX suite's test of the same name.

   tx_thread_create rounds the starting address up to the next ULONG and then
   takes a ULONG off the size, so that the rounding cannot push the end of the
   stack past the memory the caller supplied:

       if (new_stack_start != updated_stack_start)
       {
           stack_size =  stack_size - (sizeof(ULONG));
       }

   Every other test in the suite hands tx_thread_create an aligned stack, so
   that subtraction was never executed -- the only uncovered line in
   tx_thread_create.c across all five build configurations. A misaligned stack
   is legitimate: the API takes a VOID * and the alignment fix-up exists
   precisely to accept one.

   The line is compiled only under TX_ENABLE_STACK_CHECKING, so it is absent
   from three of the five configurations' reports rather than uncovered in
   them.

   The thread is then run to completion rather than merely created, because the
   point of the adjustment is that the resulting stack is still usable and still
   inside the caller's buffer.  */

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


void  test_control_return(UINT status);


static TX_THREAD       thread_0;
static TX_THREAD       thread_1;

/* Thread 1's stack is carved out of this by hand so that its start can be put
   deliberately off a ULONG boundary. The extra ULONG is what the misaligned
   start is offset into, so that the stack still ends inside the array after
   tx_thread_create has rounded the start up.  */

static UCHAR           misaligned_area[TEST_STACK_SIZE_PRINTF + sizeof(ULONG)];

static ULONG           thread_1_counter =  0;


static void    thread_0_entry(ULONG thread_input);
static void    thread_1_entry(ULONG thread_input);


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

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

UINT    status;
CHAR    *pointer;
CHAR    *misaligned_stack;


    /* Setup a pointer.  */
    pointer =  (CHAR *) first_unused_memory;

    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);
    pointer =  pointer + TEST_STACK_SIZE_PRINTF;

    if (status != TX_SUCCESS)
    {

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

    /* Push the start one byte past a ULONG boundary. The array itself is
       aligned, so adding one is enough to guarantee the fix-up runs whatever
       the alignment of the array turned out to be.  */
    misaligned_stack =  ((CHAR *) misaligned_area) + 1;

    status =  tx_thread_create(&thread_1, "thread 1", thread_1_entry, 0,
            misaligned_stack, TEST_STACK_SIZE_PRINTF,
            15, 15, TX_NO_TIME_SLICE, TX_AUTO_START);

    if (status != TX_SUCCESS)
    {

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


static void    thread_0_entry(ULONG thread_input)
{

    /* On this port the two threads start on separate cores, so this one does
       not have to wait for a relinquish to run. It sleeps well past the single
       tick thread 1 sleeps for, so the checks below are made against a thread
       that has actually finished either way.  */
    tx_thread_sleep(5);

    /* Both increments must have happened: one before thread 1 slept and one
       after it woke, which is the half that needed the stack to survive a
       context switch.  */
    if (thread_1_counter != ((ULONG) 2))
    {

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

    /* The thread that ran on the misaligned stack must have run to completion,
       which is what says the adjusted stack was usable.  */
    if (thread_1.tx_thread_state != TX_COMPLETED)
    {

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

    printf("Running Thread Misaligned Stack Test................................ SUCCESS!\n");
    test_control_return(0);
}


static void    thread_1_entry(ULONG thread_input)
{

    /* Use the stack either side of a context switch rather than returning
       straight away.  */
    thread_1_counter++;

    tx_thread_sleep(1);

    thread_1_counter++;
}