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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
/***************************************************************************/
/* 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 covers pthread_self() being called from a thread that is not a
pthread.
Nothing stops an application mixing tx_thread_create() with the POSIX layer,
and a ThreadX thread created that way has no POSIX control block.
posix_thread2tcb() returns NULL for it, and pthread_self() used to read the
pthread ID through that null pointer, then read the signal fields of a
POSIX_TCB out of a plain TX_THREAD that never had any.
The test calls pthread_self() from both kinds of thread: a real pthread,
which must get the ID pthread_create() handed back, and a plain ThreadX
thread, which must get zero rather than a fault or a value read out of
whatever follows its control block. */
#include <stdio.h>
#include "tx_api.h"
#include "pthread.h"
#define TEST_STACK_BYTES 4096
static ULONG posix_region[192 * 1024 / sizeof(ULONG)];
static pthread_t worker;
static pthread_attr_t worker_attr;
/* A plain ThreadX thread, deliberately not created through pthread_create(). */
static TX_THREAD plain_thread;
static volatile INT worker_done;
static volatile INT plain_done;
static pthread_t worker_reported_id;
static pthread_t plain_reported_id;
extern void test_control_return(UINT status);
static VOID *worker_entry(VOID *input);
static VOID plain_entry(ULONG input);
static VOID checker_entry(ULONG input);
static TX_THREAD checker_thread;
/* Define what the initial system looks like. */
#ifdef CTEST
void test_application_define(void *first_unused_memory)
#else
void posix_pthread_self_application_define(void *first_unused_memory)
#endif
{
struct sched_param param;
VOID *storage_ptr;
CHAR *pointer;
pointer = (CHAR *) first_unused_memory;
storage_ptr = posix_initialize(posix_region);
/* A genuine pthread. */
pthread_attr_init(&worker_attr);
param.sched_priority = 15;
pthread_attr_setschedparam(&worker_attr, ¶m);
pthread_attr_setstackaddr(&worker_attr, storage_ptr);
if (pthread_create(&worker, &worker_attr, worker_entry, NULL) != OK)
{
printf("Running POSIX Pthread Self Test.................................. ERROR #1\n");
test_control_return(1);
}
/* A ThreadX thread that the POSIX layer knows nothing about. */
if (tx_thread_create(&plain_thread, "plain threadx thread", plain_entry, 0,
pointer, TEST_STACK_BYTES,
20, 20, TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS)
{
printf("Running POSIX Pthread Self Test.................................. ERROR #2\n");
test_control_return(1);
}
pointer = pointer + TEST_STACK_BYTES;
/* Runs last and inspects what the other two reported. */
if (tx_thread_create(&checker_thread, "checker", checker_entry, 0,
pointer, TEST_STACK_BYTES,
25, 25, TX_NO_TIME_SLICE, TX_AUTO_START) != TX_SUCCESS)
{
printf("Running POSIX Pthread Self Test.................................. ERROR #3\n");
test_control_return(1);
}
}
static VOID *worker_entry(VOID *input)
{
(void) input;
worker_reported_id = pthread_self();
worker_done = 1;
return (NULL);
}
/* The case that used to fault: a ThreadX thread asking for its pthread ID. */
static VOID plain_entry(ULONG input)
{
(void) input;
plain_reported_id = pthread_self();
plain_done = 1;
}
static VOID checker_entry(ULONG input)
{
(void) input;
printf("Running POSIX Pthread Self Test.................................. ");
/* Both threads run above this one, so they have finished by now. */
if ((worker_done == 0) || (plain_done == 0))
{
printf("ERROR #4\n");
test_control_return(1);
}
/* A pthread must report the ID pthread_create() produced. */
if (worker_reported_id != worker)
{
printf("ERROR #5\n");
test_control_return(1);
}
/* A pthread ID is the address of its control block, so a real one is never
zero. */
if (worker_reported_id == (pthread_t) 0)
{
printf("ERROR #6\n");
test_control_return(1);
}
/* The plain ThreadX thread has no pthread ID, and must be told so rather
than handed something read out of memory that follows its TX_THREAD. */
if (plain_reported_id != (pthread_t) 0)
{
printf("ERROR #7\n");
test_control_return(1);
}
printf("SUCCESS!\n");
test_control_return(0);
}
|