summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrédéric Desbiens <[email protected]>2026-10-14 10:57:14 -0400
committerFrédéric Desbiens <[email protected]>2026-10-14 10:57:14 -0400
commitb017aea7e4e8a3e3d81fc110a5b815af754438eb (patch)
tree7b7a51cba70c049d740e900af85795cc8f97472d
parent74d9e3937fa913380fdfdd902e528411c661ea3f (diff)
Restored the Linux port mutex retryv6.4.1_cert
This was reverted because a NetX Secure regression test segfaulted with it in place. The cause was the test: it hands the certificate verify path a stack-local certificate whose signature it never assigns, and this change moves the stack layout that decides whether the unassigned slot reads null or a readable leftover. That test has been fixed, so the retry comes back. Measured with the test unfixed and this change in place, on a layout built without the stack protector: eight of eight runs segfault, the fault read from the faulting process as a null signature dereferenced by the ECDSA verify. With the test fixed, nineteen build configurations run it eight times each with no fault. Without this change, a thread signalled into the port's suspend handler never returns to the contended-mutex loop, the next unlock's wake-up is lost, the scheduler is left parked, and the timer interrupt never runs -- which stalls the tick and hangs about 0.39% of instances of a few TCP tests for their full timeout.
-rw-r--r--ports/linux/gnu/inc/tx_port.h13
-rw-r--r--ports/linux/gnu/src/tx_thread_schedule.c45
2 files changed, 57 insertions, 1 deletions
diff --git a/ports/linux/gnu/inc/tx_port.h b/ports/linux/gnu/inc/tx_port.h
index dc39b5f9..70a9fb9d 100644
--- a/ports/linux/gnu/inc/tx_port.h
+++ b/ports/linux/gnu/inc/tx_port.h
@@ -525,7 +525,7 @@ VOID _tx_thread_interrupt_restore(UINT previous_posture);
#define TX_RESTORE _tx_linux_debug_entry_insert("RESTORE", __FILE__, __LINE__); \
_tx_thread_interrupt_restore(tx_saved_posture);
#endif /* TX_LINUX_DEBUG_ENABLE */
-#define tx_linux_mutex_lock(p) pthread_mutex_lock(&p)
+#define tx_linux_mutex_lock(p) _tx_linux_mutex_lock_retry(&p)
#define tx_linux_mutex_unlock(p) pthread_mutex_unlock(&p)
#define tx_linux_mutex_recursive_unlock(p) {\
int _recursive_count = (int)tx_linux_mutex_recursive_count;\
@@ -566,6 +566,17 @@ extern CHAR _tx_version_id[];
/* Define externals for the Linux port of ThreadX. */
extern pthread_mutex_t _tx_linux_mutex;
+
+/* Define how long a thread waits on the Linux mutex before retrying. A thread
+ parked on the mutex can be suspended by the port's signal handler and so never
+ act on the wake-up the next unlock sends it, which leaves the wake-up lost and
+ every other waiter parked on a mutex that is free. */
+
+#ifndef TX_LINUX_MUTEX_RETRY_NSEC
+#define TX_LINUX_MUTEX_RETRY_NSEC 1000000
+#endif
+
+void _tx_linux_mutex_lock_retry(pthread_mutex_t *mutex);
extern sem_t _tx_linux_semaphore;
extern sem_t _tx_linux_semaphore_no_idle;
extern ULONG _tx_linux_global_int_disabled_flag;
diff --git a/ports/linux/gnu/src/tx_thread_schedule.c b/ports/linux/gnu/src/tx_thread_schedule.c
index d65104a1..c66aa891 100644
--- a/ports/linux/gnu/src/tx_thread_schedule.c
+++ b/ports/linux/gnu/src/tx_thread_schedule.c
@@ -8,6 +8,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -206,6 +208,49 @@ struct timespec ts;
}
}
+/* Define the ThreadX Linux mutex lock function. The wait is timed and retried
+ rather than left to pthread_mutex_lock, because a thread can be signalled into
+ the port's suspend handler while it is parked on this mutex. That handler does
+ not return until the thread is resumed, so the wake-up the next unlock sends is
+ delivered to a thread that never retries and is lost. Any other thread parked
+ on the mutex then waits on a mutex that is free. Retrying on a timeout costs
+ nothing when the mutex is handed over normally, and turns that lost wake-up into
+ a delay of at most the retry period. */
+
+void _tx_linux_mutex_lock_retry(pthread_mutex_t *mutex)
+{
+
+INT linux_status;
+struct timespec ts;
+
+
+ do
+ {
+
+ /* Set the deadline for this attempt. */
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_nsec = ts.tv_nsec + TX_LINUX_MUTEX_RETRY_NSEC;
+ if (ts.tv_nsec >= 1000000000)
+ {
+
+ ts.tv_nsec = ts.tv_nsec - 1000000000;
+ ts.tv_sec++;
+ }
+
+ linux_status = pthread_mutex_timedlock(mutex, &ts);
+
+ /* Anything but the deadline expiring is a real failure to obtain the
+ mutex, so stop retrying. */
+ if ((linux_status != 0) && (linux_status != ETIMEDOUT))
+ {
+
+ break;
+ }
+
+ } while (linux_status != 0);
+}
+
+
void _tx_thread_delete_port_completion(TX_THREAD *thread_ptr, UINT tx_saved_posture)
{
INT linux_status;