This patch addresses a bug where in a multi-threaded program a new signal
from the inferior may be received before all group-stop messages from an
earlier signal have been handled. The attached .cpp file exposes the issue:

   - clang++ -o thread thread.cpp -lpthread -g -O0
   - lldb ./thread
   - r
   - hit Ctrl-C
   - br set -f thread.cpp -l 11
   - c
   - <hang>

A breakpoint is usually hit before all the group-stop messages involved in
restarting the process are handled and the internal state then gets out of
sync.

The attached patch solves the issue and all unit tests pass, I'm not a
ptrace expert though so there may be a more appropriate fix. The group-stop
handling was taken from the existing ProcessMonitor::MonitorCallback.

Thanks,

Andrew
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

bool running = true;

void *do_calc(void *in)
{
  size_t y = (size_t)in;
  while (running)
    y *= 1.1;
  return 0;
}

int main() 
{
  int sz = 4;
  pthread_t t[sz];

  for (size_t i=0; i<sz; i++)
    pthread_create(&t[i], NULL, &do_calc, (void*)i);

  for (int i=0; i<5; i++)
    sleep(1);
  running = false;

  for (int i=0; i<sz; i++)
    pthread_join(t[i], 0);

  return 0;
}

diff --git a/source/Plugins/Process/Linux/ProcessMonitor.cpp b/source/Plugins/Process/Linux/ProcessMonitor.cpp
index 0f79034..d5a1683 100644
--- a/source/Plugins/Process/Linux/ProcessMonitor.cpp
+++ b/source/Plugins/Process/Linux/ProcessMonitor.cpp
@@ -1798,14 +1798,23 @@ ProcessMonitor::StopThread(lldb::tid_t tid)
         int ptrace_err;
         if (!GetSignalInfo(wait_pid, &info, ptrace_err))
         {
-            if (log)
+            // another signal causing a StopAllThreads may have been received
+            // before wait_pid's group-stop was processed, handle it now
+            if (ptrace_err == EINVAL)
             {
-                log->Printf ("ProcessMonitor::%s() GetSignalInfo failed.", __FUNCTION__);
+                assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP);
 
-                // This would be a particularly interesting case
-                if (ptrace_err == EINVAL)
-                    log->Printf ("ProcessMonitor::%s() in group-stop", __FUNCTION__);
+                if (log)
+                  log->Printf ("ProcessMonitor::%s() resuming from group-stop", __FUNCTION__);
+                // inferior process is in 'group-stop', so deliver SIGSTOP signal
+                if (!Resume(wait_pid, SIGSTOP)) {
+                  assert(0 && "SIGSTOP delivery failed while in 'group-stop' state");
+                }
+                continue;
             }
+
+            if (log)
+                log->Printf ("ProcessMonitor::%s() GetSignalInfo failed.", __FUNCTION__);
             return false;
         }
 
_______________________________________________
lldb-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev

Reply via email to