Skip to content

Stopped the Linux port losing a mutex wake-up to a suspend signal - #754

Open
fdesbiens wants to merge 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix-linux-mutex-wakeup
Open

fdesbiens wants to merge 1 commit into
eclipse-threadx:devfrom
fdesbiens:fix-linux-mutex-wakeup

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

Part of #752. This is the ThreadX half of what #753 fixes for ThreadX SMP.

The Linux port has both halves of the same defect. Its suspend handler in ports/linux/gnu/src/tx_initialize_low_level.c calls sigsuspend and does not return until the thread is resumed, and tx_linux_mutex_lock in ports/linux/gnu/inc/tx_port.h is a bare pthread_mutex_lock. A thread can therefore be signalled while it is parked on _tx_linux_mutex; glibc waits for a contended mutex in a loop that re-arms the futex wait after a signal, and this handler never returns to it, so the next unlock hands its wake-up to a thread that will not act on it and any other waiter is left on a mutex that reads free. #752 has the captures of that state from the SMP port.

tx_linux_mutex_lock now calls a helper that waits with pthread_mutex_timedlock and retries, so the wait is re-armed every TX_LINUX_MUTEX_RETRY_NSEC — one millisecond — and a lost wake-up costs a retry rather than the process. Nothing else changes; the hand-over path is untouched whenever the wake-up arrives. pthread_mutex_timedlock needs _GNU_SOURCE under -std=c99, and ports/linux/gnu/CMakeLists.txt and the port's example Makefile both already define it.

These are the only two ports affected. A sigsuspend-based suspend handler exists in ports/linux/gnu and ports_smp/linux/gnu and nowhere else in the tree, and those two are also the only ports that take a critical section with pthread_mutex_lock. The Win32 ports use Windows primitives and are unaffected.

What is different from #753, and worth being explicit about: this port has never been observed to deadlock. The ThreadX regression suite recorded no first-attempt failure across 105 configuration-runs with retries disabled, and none in any of the 33 CI runs dispatched while the SMP defect was being characterised — including the two whose SMP job failed. That is consistent with one emulated core and far less suspend and resume traffic, not with the code being different. So this is a fix by inspection rather than one driven by a reproduction, and it is offered as such.

What it is verified to do is break nothing: all seven build configurations pass with retries disabled and CTEST_PARALLEL_LEVEL=1, 105/105 in five and 100/100 in two, 715 test executions.

This is the ThreadX half of the defect fixed for ThreadX SMP in an earlier pull
request. The Linux port suspends a thread with a signal whose handler calls
sigsuspend and does not return until the thread is resumed, and it takes its
critical section with a bare pthread_mutex_lock through tx_linux_mutex_lock. A
thread can therefore be signalled while it is parked on _tx_linux_mutex.

glibc waits for a contended mutex in a loop that re-arms the futex wait after a
signal, and this handler never returns to it. The next unlock hands its wake-up to
that thread, which will not act on it, and any other thread parked on the mutex is
never woken, leaving the mutex free with waiters on it.

tx_linux_mutex_lock now calls a helper that waits with pthread_mutex_timedlock and
retries, so the wait is re-armed every TX_LINUX_MUTEX_RETRY_NSEC and a lost
wake-up costs one retry period instead of the process. The period is one
millisecond. pthread_mutex_timedlock needs _GNU_SOURCE under -std=c99, which both
of this port's build systems already define.

These are the only two ports affected: a sigsuspend-based suspend handler exists
in the Linux and SMP Linux ports and nowhere else, and those two are also the only
ports taking a critical section with pthread_mutex_lock.

Unlike the SMP port, this one has never been observed to deadlock, which is
consistent with one emulated core and far less suspend and resume traffic. The fix
is by inspection, and verified as breaking nothing: all seven configurations pass
with retries disabled, 105/105 in five and 100/100 in two.

Assisted-by: Claude Code (Opus 5) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant