Fix signal handling for POSIX (only tested on Linux) processes in multi-threaded programs.
Also fix a related issue where if a thread exits after a thread continue, lldb would hang.


git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@185944 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Plugins/Process/Linux/ProcessMonitor.cpp b/source/Plugins/Process/Linux/ProcessMonitor.cpp
index 512639c..fe61798 100644
--- a/source/Plugins/Process/Linux/ProcessMonitor.cpp
+++ b/source/Plugins/Process/Linux/ProcessMonitor.cpp
@@ -1236,6 +1236,8 @@
         log->Printf ("ProcessMonitor::%s() adding pid = %" PRIu64, __FUNCTION__, pid);
     process.GetThreadList().AddThread(inferior);
 
+    process.AddThreadForInitialStopIfNeeded(pid);
+
     // Let our process instance know the thread has stopped.
     process.SendMessage(ProcessMessage::Trace(pid));
 
@@ -1294,7 +1296,6 @@
 
     // Use a map to keep track of the threads which we have attached/need to attach.
     Host::TidMap tids_to_attach;
-
     if (pid <= 1)
     {
         args->m_error.SetErrorToGenericError();
@@ -1360,6 +1361,7 @@
                     log->Printf ("ProcessMonitor::%s() adding tid = %" PRIu64, __FUNCTION__, tid);
                 process.GetThreadList().AddThread(inferior);
                 it->second = true;
+                process.AddThreadForInitialStopIfNeeded(tid);
             }
         }
     }
@@ -1513,7 +1515,7 @@
         if (!monitor->GetEventMessage(pid, &data))
             data = -1;
         if (log)
-            log->Printf ("ProcessMonitor::%s() received exit event, data = %lx, pid = %" PRIu64, __FUNCTION__, data, pid);
+            log->Printf ("ProcessMonitor::%s() received limbo event, data = %lx, pid = %" PRIu64, __FUNCTION__, data, pid);
         message = ProcessMessage::Limbo(pid, (data >> 8));
         break;
     }
@@ -1711,6 +1713,27 @@
                     return true;
                 break;
 
+            case ProcessMessage::eSignalMessage:
+                if (log)
+                    log->Printf ("ProcessMonitor::%s(bp) handling message", __FUNCTION__);
+                if (WSTOPSIG(status) == SIGSTOP)
+                {
+                    m_process->AddThreadForInitialStopIfNeeded(tid);
+                    thread->SetState(lldb::eStateStopped);
+                }
+                else
+                {
+                    m_process->SendMessage(message);
+                    // This isn't the stop we were expecting, but the thread is
+                    // stopped. SendMessage will handle processing of this event,
+                    // but we need to resume here to get the stop we are waiting
+                    // for (otherwise the thread will stop again immediately when
+                    // we try to resume).
+                    if (wait_pid == tid)
+                        Resume(wait_pid, eResumeSignalNone);
+                }
+                break;
+
             case ProcessMessage::eSignalDeliveredMessage:
                 // This is the stop we're expecting.
                 if (wait_pid == tid && WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP && info.si_code == SI_TKILL)
@@ -1721,7 +1744,6 @@
                     return true;
                 }
                 // else fall-through
-            case ProcessMessage::eSignalMessage:
             case ProcessMessage::eBreakpointMessage:
             case ProcessMessage::eTraceMessage:
             case ProcessMessage::eWatchpointMessage:
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
index 6f25585..e09bfca 100644
--- a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
@@ -76,7 +76,8 @@
       m_monitor(NULL),
       m_module(NULL),
       m_message_mutex (Mutex::eMutexTypeRecursive),
-      m_exit_now(false)
+      m_exit_now(false),
+      m_seen_initial_stop()
 {
     // FIXME: Putting this code in the ctor and saving the byte order in a
     // member variable is a hack to avoid const qual issues in GetByteOrder.
@@ -412,8 +413,23 @@
             m_exit_status = message.GetExitStatus();
             SetExitStatus(m_exit_status, NULL);
         }
+        else if (!IsAThreadRunning())
+            SetPrivateState(eStateStopped);
         break;
 
+        assert(thread);
+        thread->SetState(eStateStopped);
+        StopAllThreads(message.GetTID());
+        SetPrivateState(eStateStopped);
+        break;
+
+    case ProcessMessage::eSignalMessage:
+    case ProcessMessage::eSignalDeliveredMessage:
+        if (message.GetSignal() == SIGSTOP &&
+            AddThreadForInitialStopIfNeeded(message.GetTID()))
+            return;
+        // Intentional fall-through
+
     case ProcessMessage::eBreakpointMessage:
     case ProcessMessage::eTraceMessage:
     case ProcessMessage::eWatchpointMessage:
@@ -424,24 +440,6 @@
         StopAllThreads(message.GetTID());
         SetPrivateState(eStateStopped);
         break;
-
-    case ProcessMessage::eSignalMessage:
-    case ProcessMessage::eSignalDeliveredMessage:
-    {
-        lldb::tid_t tid = message.GetTID();
-        lldb::tid_t pid = GetID();
-        if (tid == pid) {
-            assert(thread);
-            thread->SetState(eStateStopped);
-            StopAllThreads(message.GetTID());
-            SetPrivateState(eStateStopped);
-            break;
-        } else {
-            // FIXME: Ignore any signals generated by children.
-            return;
-        }
-    }
-
     }
 
     m_message_queue.push(message);
@@ -453,6 +451,19 @@
     // FIXME: Will this work the same way on FreeBSD and Linux?
 }
 
+bool
+ProcessPOSIX::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid)
+{
+    bool added_to_set = false;
+    ThreadStopSet::iterator it = m_seen_initial_stop.find(stop_tid);
+    if (it == m_seen_initial_stop.end())
+    {
+        m_seen_initial_stop.insert(stop_tid);
+        added_to_set = true;
+    }
+    return added_to_set;
+}
+
 void
 ProcessPOSIX::RefreshStateAfterStop()
 {
@@ -497,6 +508,7 @@
                 log->Printf ("ProcessPOSIX::%s() removing thread, tid = %" PRIi64, __FUNCTION__, tid);
             ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false);
             thread_sp.reset();
+            m_seen_initial_stop.erase(tid);
         }
 
         m_message_queue.pop();
@@ -851,3 +863,22 @@
 
     return false;
 }
+
+bool
+ProcessPOSIX::IsAThreadRunning()
+{
+    bool is_running = false;
+    uint32_t thread_count = m_thread_list.GetSize(false);
+    for (uint32_t i = 0; i < thread_count; ++i)
+    {
+        POSIXThread *thread = static_cast<POSIXThread*>(
+            m_thread_list.GetThreadAtIndex(i, false).get());
+        StateType thread_state = thread->GetState();
+        if (thread_state == eStateRunning || thread_state == eStateStepping)
+        {
+            is_running = true;
+            break;
+        }
+    }
+    return is_running;
+}
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.h b/source/Plugins/Process/POSIX/ProcessPOSIX.h
index 8402aad..a865fe2 100644
--- a/source/Plugins/Process/POSIX/ProcessPOSIX.h
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.h
@@ -14,6 +14,7 @@
 
 // C++ Includes
 #include <queue>
+#include <set>
 
 // Other libraries and framework includes
 #include "lldb/Target/Process.h"
@@ -157,6 +158,11 @@
     virtual void
     StopAllThreads(lldb::tid_t stop_tid);
 
+    /// Adds the thread to the list of threads for which we have received the initial stopping signal.
+    /// The \p stop_tid paramter indicates the thread which the stop happened for.
+    bool
+    AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid);
+
 protected:
     /// Target byte order.
     lldb::ByteOrder m_byte_order;
@@ -183,8 +189,16 @@
     /// Returns true if the process is stopped.
     bool IsStopped();
 
+    /// Returns true if at least one running is currently running
+    bool IsAThreadRunning();
+
     typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
     MMapMap m_addr_to_mmap_size;
+
+    typedef std::set<lldb::tid_t> ThreadStopSet;
+    /// Every thread begins with a stop signal. This keeps track
+    /// of the threads for which we have received the stop signal.
+    ThreadStopSet m_seen_initial_stop;
 };
 
 #endif  // liblldb_MacOSXProcess_H_