Adding support for stopping all threads of multithreaded inferiors on Linux.  Also adding multithreaded test cases.

llvm-svn: 182809
diff --git a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
index 471843b..b2db43e 100644
--- a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
+++ b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
@@ -75,6 +75,7 @@
       m_byte_order(lldb::endian::InlHostByteOrder()),
       m_monitor(NULL),
       m_module(NULL),
+      m_message_mutex (Mutex::eMutexTypeRecursive),
       m_in_limbo(false),
       m_exit_now(false)
 {
@@ -374,31 +375,58 @@
 {
     Mutex::Locker lock(m_message_mutex);
 
+    POSIXThread *thread = static_cast<POSIXThread*>(
+        m_thread_list.FindThreadByID(message.GetTID(), false).get());
+
     switch (message.GetKind())
     {
     case ProcessMessage::eInvalidMessage:
         return;
 
     case ProcessMessage::eLimboMessage:
-        m_in_limbo = true;
-        m_exit_status = message.GetExitStatus();
-        if (m_exit_now)
+        assert(thread);
+        thread->SetState(eStateStopped);
+        if (message.GetTID() == GetID())
         {
-            SetPrivateState(eStateExited);
-            m_monitor->Detach();
+            m_in_limbo = true;
+            m_exit_status = message.GetExitStatus();
+            if (m_exit_now)
+            {
+                SetPrivateState(eStateExited);
+                m_monitor->Detach();
+            }
+            else
+            {
+                StopAllThreads(message.GetTID());
+                SetPrivateState(eStateStopped);
+            }
         }
         else
+        {
+            StopAllThreads(message.GetTID());
             SetPrivateState(eStateStopped);
+        }
         break;
 
     case ProcessMessage::eExitMessage:
-        m_exit_status = message.GetExitStatus();
-        SetExitStatus(m_exit_status, NULL);
+        assert(thread);
+        thread->SetState(eStateExited);
+        // FIXME: I'm not sure we need to do this.
+        if (message.GetTID() == GetID())
+        {
+            m_exit_status = message.GetExitStatus();
+            SetExitStatus(m_exit_status, NULL);
+        }
         break;
 
-    case ProcessMessage::eTraceMessage:
     case ProcessMessage::eBreakpointMessage:
+    case ProcessMessage::eTraceMessage:
     case ProcessMessage::eWatchpointMessage:
+    case ProcessMessage::eNewThreadMessage:
+    case ProcessMessage::eCrashMessage:
+        assert(thread);
+        thread->SetState(eStateStopped);
+        StopAllThreads(message.GetTID());
         SetPrivateState(eStateStopped);
         break;
 
@@ -408,6 +436,9 @@
         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 {
@@ -416,51 +447,65 @@
         }
     }
 
-    case ProcessMessage::eCrashMessage:
-        // FIXME: Update stop reason as per bugzilla 14598
-        SetPrivateState(eStateStopped);
-        break;
-
-    case ProcessMessage::eNewThreadMessage:
-        SetPrivateState(eStateStopped);
-        break;
     }
 
     m_message_queue.push(message);
 }
 
+void 
+ProcessPOSIX::StopAllThreads(lldb::tid_t stop_tid)
+{
+    // FIXME: Will this work the same way on FreeBSD and Linux?
+}
+
 void
 ProcessPOSIX::RefreshStateAfterStop()
 {
     Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
     if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
-        log->Printf ("ProcessPOSIX::%s()", __FUNCTION__);
+        log->Printf ("ProcessPOSIX::%s(), message_queue size = %d", __FUNCTION__, (int)m_message_queue.size());
 
     Mutex::Locker lock(m_message_mutex);
-    if (m_message_queue.empty())
-        return;
 
-    ProcessMessage &message = m_message_queue.front();
+    // This method used to only handle one message.  Changing it to loop allows
+    // it to handle the case where we hit a breakpoint while handling a different
+    // breakpoint.
+    while (!m_message_queue.empty())
+    {
+        ProcessMessage &message = m_message_queue.front();
 
-    // Resolve the thread this message corresponds to and pass it along.
-    // FIXME: we're really dealing with the pid here.  This should get
-    // fixed when this code is fixed to handle multiple threads.
-    lldb::tid_t tid = message.GetTID();
-    if (log)
-        log->Printf ("ProcessPOSIX::%s() pid = %" PRIi64, __FUNCTION__, tid);
-    POSIXThread *thread = static_cast<POSIXThread*>(
-        GetThreadList().FindThreadByID(tid, false).get());
+        // Resolve the thread this message corresponds to and pass it along.
+        lldb::tid_t tid = message.GetTID();
+        if (log)
+            log->Printf ("ProcessPOSIX::%s(), message_queue size = %d, pid = %" PRIi64, __FUNCTION__, (int)m_message_queue.size(), tid);
+        POSIXThread *thread = static_cast<POSIXThread*>(
+            GetThreadList().FindThreadByID(tid, false).get());
 
-    if (message.GetKind() == ProcessMessage::eNewThreadMessage) {
-        ThreadSP thread_sp;
-        thread_sp.reset(new POSIXThread(*this, message.GetChildTID()));
-        m_thread_list.AddThread(thread_sp);
+        if (message.GetKind() == ProcessMessage::eNewThreadMessage)
+        {
+            if (log)
+                log->Printf ("ProcessPOSIX::%s() adding thread, tid = %" PRIi64, __FUNCTION__, message.GetChildTID());
+            ThreadSP thread_sp;
+            thread_sp.reset(new POSIXThread(*this, message.GetChildTID()));
+            m_thread_list.AddThread(thread_sp);
+        }
+
+        m_thread_list.RefreshStateAfterStop();
+
+        if (thread)
+            thread->Notify(message);
+
+        if (message.GetKind() == ProcessMessage::eExitMessage)
+        {
+            // FIXME: We should tell the user about this, but the limbo message is probably better for that.
+            if (log)
+                log->Printf ("ProcessPOSIX::%s() removing thread, tid = %" PRIi64, __FUNCTION__, tid);
+            ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false);
+            thread_sp.reset();
+        }
+
+        m_message_queue.pop();
     }
-
-    assert(thread);
-    thread->Notify(message);
-
-    m_message_queue.pop();
 }
 
 bool