/***************************************************************************/ /* 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 #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); }