summaryrefslogtreecommitdiff
path: root/test/posix/regression/posix_pthread_self_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/posix/regression/posix_pthread_self_test.c')
-rw-r--r--test/posix/regression/posix_pthread_self_test.c177
1 files changed, 177 insertions, 0 deletions
diff --git a/test/posix/regression/posix_pthread_self_test.c b/test/posix/regression/posix_pthread_self_test.c
new file mode 100644
index 00000000..7cbb6450
--- /dev/null
+++ b/test/posix/regression/posix_pthread_self_test.c
@@ -0,0 +1,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, &param);
+ 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);
+}