[Lldb-commits] [lldb] [lldb] Fix race/timeout in TestInternalThreadSuspension (PR #203202)

Raphael Isemann via lldb-commits lldb-commits at lists.llvm.org
Thu Jun 11 02:01:17 PDT 2026


https://github.com/Teemperor created https://github.com/llvm/llvm-project/pull/203202

This test launches a thread and then waits for a signal from the launched thread. Below is one possible interleaving, where the `pthread_cond_signal` (2) wins the race and becomes a no-op while (3) is locking until the test times out.

```
void *
suspend_func (void *unused) {
  [...]
  // 2. Created thread reaches this and signals.
  pthread_cond_signal(&signal_cond);
  [...]
}

int main() {

  pthread_mutex_lock(&signal_mutex);
  // 1. Thread is created
  pthread_create(&suspend_thread, NULL, suspend_func, NULL);

  // Enable this to make race reliable:
  // sleep(1);

  // 3. We start waiting on signal_cond, but 2. already executed.
  pthread_cond_wait(&signal_cond, &signal_mutex);
```

This patch guards (2) with signal_mutex so it can only be executed after pthread_cond_wait unlocks signal_mutex. I also added a check for spurious wakeups.

>From 9553e8b0e203e6402e26924c0308884240b10941 Mon Sep 17 00:00:00 2001
From: Raphael Isemann <rise at apple.com>
Date: Wed, 10 Jun 2026 13:21:50 +0100
Subject: [PATCH] [lldb] Fix race/timeout in TestInternalThreadSuspension

This test launches a thread and then waits for a signal from the
launched thread. Below is one possible interleaving, where the
`pthread_cond_signal` (2) wins the race and becomes a no-op while (3)
is locking until the test times out.

```
void *
suspend_func (void *unused) {
  [...]
  // 2. Created thread reaches this and signals.
  pthread_cond_signal(&signal_cond);
  [...]
}

int main() {

  pthread_mutex_lock(&signal_mutex);
  // 1. Thread is created
  pthread_create(&suspend_thread, NULL, suspend_func, NULL);

  // Enable this to make race reliable:
  // sleep(1);

  // 3. We start waiting on signal_cond, but 2. already executed.
  pthread_cond_wait(&signal_cond, &signal_mutex);
```

This patch guards (2) with signal_mutex so it can only be executed
after pthread_cond_wait unlocks signal_mutex. I also added a check for
spurious wakeups.
---
 lldb/test/API/macosx/thread_suspend/main.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/lldb/test/API/macosx/thread_suspend/main.c b/lldb/test/API/macosx/thread_suspend/main.c
index 03da7a71505c7..115ca4b49cc9c 100644
--- a/lldb/test/API/macosx/thread_suspend/main.c
+++ b/lldb/test/API/macosx/thread_suspend/main.c
@@ -6,6 +6,7 @@ pthread_mutex_t suspend_mutex = PTHREAD_MUTEX_INITIALIZER;
 pthread_mutex_t signal_mutex = PTHREAD_MUTEX_INITIALIZER;
 pthread_cond_t signal_cond = PTHREAD_COND_INITIALIZER;
 
+int g_signaled = 0;
 int g_running_count = 0;
 
 int
@@ -16,7 +17,10 @@ function_to_call() {
 void *
 suspend_func (void *unused) {
   pthread_setname_np("Look for me");
+  pthread_mutex_lock(&signal_mutex);
+  g_signaled = 1;
   pthread_cond_signal(&signal_cond);
+  pthread_mutex_unlock(&signal_mutex);
   pthread_mutex_lock(&suspend_mutex);
 
   return NULL; // We allowed the suspend thread to run
@@ -40,8 +44,9 @@ main()
   pthread_mutex_lock(&signal_mutex);
   pthread_create(&suspend_thread, NULL, suspend_func, NULL);
 
-  pthread_cond_wait(&signal_cond, &signal_mutex);
-  
+  while (!g_signaled)
+    pthread_cond_wait(&signal_cond, &signal_mutex);
+
   mach_port_t th_port = pthread_mach_thread_np(suspend_thread);
   thread_suspend(th_port);
 



More information about the lldb-commits mailing list