[Lldb-commits] [lldb] r182809 - Adding support for stopping all threads of multithreaded inferiors on Linux. Also adding multithreaded test cases.

Andrew Kaylor andrew.kaylor at intel.com
Tue May 28 16:04:25 PDT 2013


Author: akaylor
Date: Tue May 28 18:04:25 2013
New Revision: 182809

URL: http://llvm.org/viewvc/llvm-project?rev=182809&view=rev
Log:
Adding support for stopping all threads of multithreaded inferiors on Linux.  Also adding multithreaded test cases.


Added:
    lldb/trunk/test/functionalities/thread/break_after_join/
    lldb/trunk/test/functionalities/thread/break_after_join/Makefile
    lldb/trunk/test/functionalities/thread/break_after_join/TestBreakAfterJoin.py
    lldb/trunk/test/functionalities/thread/break_after_join/main.cpp
    lldb/trunk/test/functionalities/thread/create_during_step/
    lldb/trunk/test/functionalities/thread/create_during_step/Makefile
    lldb/trunk/test/functionalities/thread/create_during_step/TestCreateDuringStep.py
    lldb/trunk/test/functionalities/thread/create_during_step/main.cpp
    lldb/trunk/test/functionalities/thread/exit_during_break/
    lldb/trunk/test/functionalities/thread/exit_during_break/Makefile
    lldb/trunk/test/functionalities/thread/exit_during_break/TestExitDuringBreak.py
    lldb/trunk/test/functionalities/thread/exit_during_break/main.cpp
    lldb/trunk/test/functionalities/thread/exit_during_break/main.d.23591
    lldb/trunk/test/functionalities/thread/exit_during_break/main.d.23604
    lldb/trunk/test/functionalities/thread/exit_during_break/main.d.23614
    lldb/trunk/test/functionalities/thread/exit_during_step/
    lldb/trunk/test/functionalities/thread/exit_during_step/Makefile
    lldb/trunk/test/functionalities/thread/exit_during_step/TestExitDuringStep.py
    lldb/trunk/test/functionalities/thread/exit_during_step/main.cpp
    lldb/trunk/test/functionalities/thread/multi_break/
    lldb/trunk/test/functionalities/thread/multi_break/Makefile
    lldb/trunk/test/functionalities/thread/multi_break/TestMultipleBreakpoints.py
    lldb/trunk/test/functionalities/thread/multi_break/main.cpp
    lldb/trunk/test/functionalities/thread/thread_exit/
    lldb/trunk/test/functionalities/thread/thread_exit/Makefile
    lldb/trunk/test/functionalities/thread/thread_exit/TestThreadExit.py
    lldb/trunk/test/functionalities/thread/thread_exit/main.cpp
Modified:
    lldb/trunk/source/Host/common/Host.cpp
    lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp
    lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h
    lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
    lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h
    lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp
    lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h
    lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.h
    lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
    lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h
    lldb/trunk/source/Target/Process.cpp
    lldb/trunk/test/functionalities/thread/state/Makefile
    lldb/trunk/test/functionalities/thread/state/TestThreadStates.py
    lldb/trunk/test/lldbtest.py

Modified: lldb/trunk/source/Host/common/Host.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/Host.cpp?rev=182809&r1=182808&r2=182809&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/Host.cpp (original)
+++ lldb/trunk/source/Host/common/Host.cpp Tue May 28 18:04:25 2013
@@ -173,7 +173,11 @@ MonitorChildProcessThreadFunction (void
             if (errno == EINTR)
                 continue;
             else
+            {
+                if (log)
+                    log->Printf ("%s (arg = %p) thread exiting because waitpid failed (%s)...", __FUNCTION__, arg, strerror(errno));
                 break;
+            }
         }
         else if (wait_pid > 0)
         {
@@ -190,8 +194,7 @@ MonitorChildProcessThreadFunction (void
             {
                 exit_status = WEXITSTATUS(status);
                 status_cstr = "EXITED";
-                if (wait_pid == pid)
-                    exited = true;
+                exited = true;
             }
             else if (WIFSIGNALED(status))
             {
@@ -230,12 +233,20 @@ MonitorChildProcessThreadFunction (void
                         callback_return = callback (callback_baton, wait_pid, exited, signal, exit_status);
                     
                     // If our process exited, then this thread should exit
-                    if (exited)
+                    if (exited && wait_pid == pid)
+                    {
+                        if (log)
+                            log->Printf ("%s (arg = %p) thread exiting because pid received exit signal...", __FUNCTION__, arg);
                         break;
+                    }
                     // If the callback returns true, it means this process should
                     // exit
                     if (callback_return)
+                    {
+                        if (log)
+                            log->Printf ("%s (arg = %p) thread exiting because callback returned true...", __FUNCTION__, arg);
                         break;
+                    }
                 }
             }
         }

Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp?rev=182809&r1=182808&r2=182809&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp Tue May 28 18:04:25 2013
@@ -64,7 +64,7 @@ ProcessLinux::Initialize()
 // Constructors and destructors.
 
 ProcessLinux::ProcessLinux(Target& target, Listener &listener)
-    : ProcessPOSIX(target, listener)
+    : ProcessPOSIX(target, listener), m_stopping_threads(false)
 {
 #if 0
     // FIXME: Putting this code in the ctor and saving the byte order in a
@@ -134,3 +134,39 @@ ProcessLinux::EnablePluginLogging(Stream
 {
     return NULL;
 }
+
+// ProcessPOSIX override
+void
+ProcessLinux::StopAllThreads(lldb::tid_t stop_tid)
+{
+    // If a breakpoint occurs while we're stopping threads, we'll get back
+    // here, but we don't want to do it again.  Only the MonitorChildProcess
+    // thread calls this function, so we don't need to protect this flag.
+    if (m_stopping_threads)
+      return;
+    m_stopping_threads = true;
+
+    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+    if (log)
+        log->Printf ("ProcessLinux::%s() stopping all threads", __FUNCTION__);
+
+    // Walk the thread list and stop the other threads.  The thread that caused
+    // the stop should already be marked as stopped before we get here.
+    Mutex::Locker thread_list_lock(m_thread_list.GetMutex());
+
+    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());
+        assert(thread);
+        lldb::tid_t tid = thread->GetID();
+        if (!StateIsStoppedState(thread->GetState(), false))
+            m_monitor->StopThread(tid);
+    }
+
+    m_stopping_threads = false;
+
+    if (log)
+        log->Printf ("ProcessLinux::%s() finished", __FUNCTION__);
+}

Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h?rev=182809&r1=182808&r2=182809&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h Tue May 28 18:04:25 2013
@@ -84,11 +84,19 @@ public:
         return m_linux_signals;
     }
 
+    //------------------------------------------------------------------
+    // ProcessPOSIX overrides
+    //------------------------------------------------------------------
+    virtual void
+    StopAllThreads(lldb::tid_t stop_tid);
+
 private:
 
     /// Linux-specific signal set.
     LinuxSignals m_linux_signals;
 
+    // Flag to avoid recursion when stopping all threads.
+    bool m_stopping_threads;
 };
 
 #endif  // liblldb_MacOSXProcess_H_

Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp?rev=182809&r1=182808&r2=182809&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp Tue May 28 18:04:25 2013
@@ -17,6 +17,7 @@
 #include <unistd.h>
 #include <sys/ptrace.h>
 #include <sys/socket.h>
+#include <sys/syscall.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 
@@ -52,6 +53,10 @@
   #define TRAP_HWBKPT 4
 #endif
 
+// Try to define a macro to encapsulate the tgkill syscall
+// fall back on kill() if tgkill isn't available
+#define tgkill(pid, tid, sig)  syscall(SYS_tgkill, pid, tid, sig)
+
 using namespace lldb_private;
 
 // FIXME: this code is host-dependent with respect to types and
@@ -724,7 +729,13 @@ ResumeOperation::Execute(ProcessMonitor
         data = m_signo;
 
     if (PTRACE(PTRACE_CONT, m_tid, NULL, (void*)data, 0))
+    {
+        Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+        if (log)
+            log->Printf ("ResumeOperation (%"  PRIu64 ") failed: %s", m_tid, strerror(errno));
         m_result = false;
+    }
     else
         m_result = true;
 }
@@ -1348,8 +1359,21 @@ ProcessMonitor::MonitorCallback(void *ca
     siginfo_t info;
     int ptrace_err;
 
+    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+    if (exited)
+    {
+        if (log)
+            log->Printf ("ProcessMonitor::%s() got exit signal, tid = %"  PRIu64, __FUNCTION__, pid);
+        message = ProcessMessage::Exit(pid, status);
+        process->SendMessage(message);
+        return pid == process->GetID();
+    }
+
     if (!monitor->GetSignalInfo(pid, &info, ptrace_err)) {
         if (ptrace_err == EINVAL) {
+            if (log)
+                log->Printf ("ProcessMonitor::%s() resuming from group-stop", __FUNCTION__);
             // inferior process is in 'group-stop', so deliver SIGSTOP signal
             if (!monitor->Resume(pid, SIGSTOP)) {
               assert(0 && "SIGSTOP delivery failed while in 'group-stop' state");
@@ -1358,8 +1382,11 @@ ProcessMonitor::MonitorCallback(void *ca
         } else {
             // ptrace(GETSIGINFO) failed (but not due to group-stop). Most likely,
             // this means the child pid is gone (or not being debugged) therefore
-            // stop the monitor thread.
-            stop_monitoring = true;
+            // stop the monitor thread if this is the main pid.
+            if (log)
+                log->Printf ("ProcessMonitor::%s() GetSignalInfo failed: %s, tid = %" PRIu64 ", signal = %d, status = %d", 
+                              __FUNCTION__, strerror(ptrace_err), pid, signal, status);
+            stop_monitoring = pid == monitor->m_process->GetID();
         }
     }
     else {
@@ -1375,7 +1402,7 @@ ProcessMonitor::MonitorCallback(void *ca
         }
 
         process->SendMessage(message);
-        stop_monitoring = !process->IsAlive();
+        stop_monitoring = false;
     }
 
     return stop_monitoring;
@@ -1387,6 +1414,8 @@ ProcessMonitor::MonitorSIGTRAP(ProcessMo
 {
     ProcessMessage message;
 
+    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
     assert(monitor);
     assert(info && info->si_signo == SIGTRAP && "Unexpected child signal!");
 
@@ -1403,6 +1432,9 @@ ProcessMonitor::MonitorSIGTRAP(ProcessMo
 
     case (SIGTRAP | (PTRACE_EVENT_CLONE << 8)):
     {
+        if (log)
+            log->Printf ("ProcessMonitor::%s() received thread creation event, code = %d", __FUNCTION__, info->si_code ^ SIGTRAP);
+
         unsigned long tid = 0;
         if (!monitor->GetEventMessage(pid, &tid))
             tid = -1;
@@ -1417,27 +1449,35 @@ ProcessMonitor::MonitorSIGTRAP(ProcessMo
 
     case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)):
     {
-        // The inferior process is about to exit.  Maintain the process in a
-        // state of "limbo" until we are explicitly commanded to detach,
-        // destroy, resume, etc.
+        // The inferior process or one of its threads is about to exit.
+        // Maintain the process or thread in a state of "limbo" until we are
+        // explicitly commanded to detach, destroy, resume, etc.
         unsigned long data = 0;
         if (!monitor->GetEventMessage(pid, &data))
             data = -1;
+        if (log)
+            log->Printf ("ProcessMonitor::%s() received exit event, data = %lx, pid = %" PRIu64, __FUNCTION__, data, pid);
         message = ProcessMessage::Limbo(pid, (data >> 8));
         break;
     }
 
     case 0:
     case TRAP_TRACE:
+        if (log)
+            log->Printf ("ProcessMonitor::%s() received trace event, pid = %" PRIu64, __FUNCTION__, pid);
         message = ProcessMessage::Trace(pid);
         break;
 
     case SI_KERNEL:
     case TRAP_BRKPT:
+        if (log)
+            log->Printf ("ProcessMonitor::%s() received breakpoint event, pid = %" PRIu64, __FUNCTION__, pid);
         message = ProcessMessage::Break(pid);
         break;
 
     case TRAP_HWBKPT:
+        if (log)
+            log->Printf ("ProcessMonitor::%s() received watchpoint event, pid = %" PRIu64, __FUNCTION__, pid);
         message = ProcessMessage::Watch(pid, (lldb::addr_t)info->si_addr);
         break;
     }
@@ -1452,6 +1492,8 @@ ProcessMonitor::MonitorSignal(ProcessMon
     ProcessMessage message;
     int signo = info->si_signo;
 
+    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
     // POSIX says that process behaviour is undefined after it ignores a SIGFPE,
     // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a
     // kill(2) or raise(3).  Similarly for tgkill(2) on Linux.
@@ -1462,12 +1504,22 @@ ProcessMonitor::MonitorSignal(ProcessMon
     // Similarly, ACK signals generated by this monitor.
     if (info->si_code == SI_TKILL || info->si_code == SI_USER)
     {
+        if (log)
+            log->Printf ("ProcessMonitor::%s() received signal %s with code %s, pid = %" PRIu64,
+                            __FUNCTION__,
+                            monitor->m_process->GetUnixSignals().GetSignalAsCString (signo),
+                            (info->si_code == SI_TKILL ? "SI_TKILL" : "SI_USER"),
+                            info->si_pid);
+
         if (info->si_pid == getpid())
             return ProcessMessage::SignalDelivered(pid, signo);
         else
             return ProcessMessage::Signal(pid, signo);
     }
 
+    if (log)
+        log->Printf ("ProcessMonitor::%s() received signal %s", __FUNCTION__, monitor->m_process->GetUnixSignals().GetSignalAsCString (signo));
+
     if (signo == SIGSEGV) {
         lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
         ProcessMessage::CrashReason reason = GetCrashReasonForSIGSEGV(info);
@@ -1497,6 +1549,144 @@ ProcessMonitor::MonitorSignal(ProcessMon
     return ProcessMessage::Signal(pid, signo);
 }
 
+bool
+ProcessMonitor::StopThread(lldb::tid_t tid)
+{
+    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+    // FIXME: Try to use tgkill or tkill
+    int ret = tgkill(m_pid, tid, SIGSTOP);
+    if (log)
+        log->Printf ("ProcessMonitor::%s(bp) stopping thread, tid = %" PRIu64 ", ret = %d", __FUNCTION__, tid, ret);
+
+    // This can happen if a thread exited while we were trying to stop it.  That's OK.
+    // We'll get the signal for that later.
+    if (ret < 0)
+        return false;
+
+    // Wait for the thread to stop
+    while (true)
+    {
+        int status = -1;
+        if (log)
+            log->Printf ("ProcessMonitor::%s(bp) waitpid...", __FUNCTION__);
+        lldb::pid_t wait_pid = ::waitpid (-1*m_pid, &status, __WALL);
+        if (log)
+            log->Printf ("ProcessMonitor::%s(bp) waitpid, pid = %" PRIu64 ", status = %d", __FUNCTION__, wait_pid, status);
+
+        if (wait_pid == -1)
+        {
+            // If we got interrupted by a signal (in our process, not the
+            // inferior) try again.
+            if (errno == EINTR)
+                continue;
+            else
+                return false; // This is bad, but there's nothing we can do.
+        }
+
+        // If this is a thread exit, we won't get any more information.
+        if (WIFEXITED(status))
+        {
+            m_process->SendMessage(ProcessMessage::Exit(wait_pid, WEXITSTATUS(status)));
+            if (wait_pid == tid)
+                return true;
+            continue;
+        }
+
+        siginfo_t info;
+        int ptrace_err;
+        if (!GetSignalInfo(wait_pid, &info, ptrace_err))
+        {
+            if (log)
+            {
+                log->Printf ("ProcessMonitor::%s() GetSignalInfo failed.", __FUNCTION__);
+
+                // This would be a particularly interesting case
+                if (ptrace_err == EINVAL)
+                    log->Printf ("ProcessMonitor::%s() in group-stop", __FUNCTION__);
+            }
+            return false;
+        }
+
+        // Handle events from other threads
+        if (log)
+            log->Printf ("ProcessMonitor::%s(bp) handling event, tid == %d", __FUNCTION__, wait_pid);
+
+        ProcessMessage message;
+        if (info.si_signo == SIGTRAP)
+            message = MonitorSIGTRAP(this, &info, wait_pid);
+        else
+            message = MonitorSignal(this, &info, wait_pid);
+
+        POSIXThread *thread = static_cast<POSIXThread*>(m_process->GetThreadList().FindThreadByID(wait_pid).get());
+
+        // When a new thread is created, we may get a SIGSTOP for the new thread
+        // just before we get the SIGTRAP that we use to add the thread to our
+        // process thread list.  We don't need to worry about that signal here.
+        assert(thread || message.GetKind() == ProcessMessage::eSignalMessage);
+
+        if (!thread)
+        {
+            m_process->SendMessage(message);
+            continue;
+        }
+
+        switch (message.GetKind())
+        {
+            case ProcessMessage::eInvalidMessage:
+                break;
+
+            // These need special handling because we don't want to send a
+            // resume even if we already sent a SIGSTOP to this thread. In
+            // this case the resume will cause the thread to disappear.  It is
+            // unlikely that we'll ever get eExitMessage here, but the same
+            // reasoning applies.
+            case ProcessMessage::eLimboMessage:
+            case ProcessMessage::eExitMessage:
+                if (log)
+                    log->Printf ("ProcessMonitor::%s(bp) handling message", __FUNCTION__);
+                // SendMessage will set the thread state as needed.
+                m_process->SendMessage(message);
+                // If this is the thread we're waiting for, stop waiting. Even
+                // though this wasn't the signal we expected, it's the last
+                // signal we'll see while this thread is alive.
+                if (wait_pid == tid)
+                    return true;
+                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)
+                {
+                    if (log)
+                        log->Printf ("ProcessMonitor::%s(bp) received signal, done waiting", __FUNCTION__);
+                    thread->SetState(lldb::eStateStopped);
+                    return true;
+                }
+                // else fall-through
+            case ProcessMessage::eSignalMessage:
+            case ProcessMessage::eBreakpointMessage:
+            case ProcessMessage::eTraceMessage:
+            case ProcessMessage::eWatchpointMessage:
+            case ProcessMessage::eCrashMessage:
+            case ProcessMessage::eNewThreadMessage:
+                if (log)
+                    log->Printf ("ProcessMonitor::%s(bp) handling message", __FUNCTION__);
+                // SendMessage will set the thread state as needed.
+                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;
+        }
+    }
+    return false;
+}
+
 ProcessMessage::CrashReason
 ProcessMonitor::GetCrashReasonForSIGSEGV(const siginfo_t *info)
 {
@@ -1808,8 +1998,15 @@ bool
 ProcessMonitor::Resume(lldb::tid_t tid, uint32_t signo)
 {
     bool result;
+    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+    if (log)
+        log->Printf ("ProcessMonitor::%s() resuming thread = %"  PRIu64 " with signal %s", __FUNCTION__, tid,
+                                 m_process->GetUnixSignals().GetSignalAsCString (signo));
     ResumeOperation op(tid, signo, result);
     DoOperation(&op);
+    if (log)
+        log->Printf ("ProcessMonitor::%s() resuming result = %s", __FUNCTION__, result ? "true" : "false");
     return result;
 }
 

Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h?rev=182809&r1=182808&r2=182809&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h Tue May 28 18:04:25 2013
@@ -63,6 +63,11 @@ public:
 
     ~ProcessMonitor();
 
+    enum ResumeSignals 
+    {
+        eResumeSignalNone = 0
+    };
+
     /// Provides the process number of debugee.
     lldb::pid_t
     GetPID() const { return m_pid; }
@@ -172,6 +177,9 @@ public:
     lldb_private::Error
     Detach();
 
+    /// Stops the requested thread and waits for the stop signal.
+    bool
+    StopThread(lldb::tid_t tid);
 
 private:
     ProcessLinux *m_process;

Modified: lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp?rev=182809&r1=182808&r2=182809&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp Tue May 28 18:04:25 2013
@@ -17,6 +17,7 @@
 // Project includes
 #include "lldb/Breakpoint/Watchpoint.h"
 #include "lldb/Core/Debugger.h"
+#include "lldb/Core/State.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/StopInfo.h"
@@ -63,15 +64,24 @@ POSIXThread::GetMonitor()
 void
 POSIXThread::RefreshStateAfterStop()
 {
+    // Invalidate all registers in our register context. We don't set "force" to
+    // true because the stop reply packet might have had some register values
+    // that were expedited and these will already be copied into the register
+    // context by the time this function gets called. The KDPRegisterContext
+    // class has been made smart enough to detect when it needs to invalidate
+    // which registers are valid by putting hooks in the register read and 
+    // register supply functions where they check the process stop ID and do
+    // the right thing.
+    //if (StateIsStoppedState(GetState())
+    {
+        const bool force = false;
+        GetRegisterContext()->InvalidateIfNeeded (force);
+    }
+    // FIXME: This should probably happen somewhere else.
+    SetResumeState(eStateRunning);
     Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
-    if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
-        log->Printf ("POSIXThread::%s ()", __FUNCTION__);
-
-    // Let all threads recover from stopping and do any clean up based
-    // on the previous thread state (if any).
-    ProcessSP base = GetProcess();
-    ProcessPOSIX &process = static_cast<ProcessPOSIX&>(*base);
-    process.GetThreadList().RefreshStateAfterStop();
+    if (log)
+        log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to running", __FUNCTION__, GetID());
 }
 
 const char *
@@ -157,11 +167,20 @@ POSIXThread::GetUnwinder()
 void
 POSIXThread::WillResume(lldb::StateType resume_state)
 {
-	// TODO: the line below shouldn't really be done, but
+    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+    if (log)
+        log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to %s", __FUNCTION__, GetID(), StateAsCString(resume_state));
+    // TODO: the line below shouldn't really be done, but
     // the POSIXThread might rely on this so I will leave this in for now
     SetResumeState(resume_state);
 }
 
+void
+POSIXThread::DidStop()
+{
+    // Don't set the thread state to stopped unless we really stopped.
+}
+
 bool
 POSIXThread::Resume()
 {
@@ -170,8 +189,9 @@ POSIXThread::Resume()
     bool status;
 
     Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
-    if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
-        log->Printf ("POSIXThread::%s ()", __FUNCTION__);
+    if (log)
+        log->Printf ("POSIXThread::%s (), resume_state = %s", __FUNCTION__,
+                         StateAsCString(resume_state));
 
     switch (resume_state)
     {
@@ -211,10 +231,14 @@ POSIXThread::Notify(const ProcessMessage
         assert(false && "Unexpected message kind!");
         break;
 
+    case ProcessMessage::eExitMessage:
+        // Nothing to be done.
+        break;
+
     case ProcessMessage::eLimboMessage:
         LimboNotify(message);
         break;
-        
+
     case ProcessMessage::eSignalMessage:
         SignalNotify(message);
         break;
@@ -318,6 +342,9 @@ POSIXThread::BreakNotify(const ProcessMe
     lldb::break_id_t bp_id = bp_site->GetID();
     assert(bp_site && bp_site->ValidForThisThread(this));
 
+    // Make this thread the selected thread
+    GetProcess()->GetThreadList().SetSelectedThreadByID(GetID());
+
     m_breakpoint = bp_site;
     SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id));
 }
@@ -408,6 +435,7 @@ POSIXThread::SignalDeliveredNotify(const
 void
 POSIXThread::CrashNotify(const ProcessMessage &message)
 {
+    // FIXME: Update stop reason as per bugzilla 14598
     int signo = message.GetSignal();
 
     assert(message.GetKind() == ProcessMessage::eCrashMessage);

Modified: lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h?rev=182809&r1=182808&r2=182809&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h Tue May 28 18:04:25 2013
@@ -39,6 +39,10 @@ public:
     virtual void
     WillResume(lldb::StateType resume_state);
 
+    // This notifies the thread when a private stop occurs.
+    virtual void
+    DidStop ();
+
     const char *
     GetInfo();
 
@@ -108,6 +112,7 @@ private:
     void SignalDeliveredNotify(const ProcessMessage &message);
     void CrashNotify(const ProcessMessage &message);
     void ThreadNotify(const ProcessMessage &message);
+    void ExitNotify(const ProcessMessage &message);
 
     lldb_private::Unwind *
     GetUnwinder();

Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.h?rev=182809&r1=182808&r2=182809&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.h (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.h Tue May 28 18:04:25 2013
@@ -117,11 +117,16 @@ public:
         return message;
     }
 
-    /// Indicates that the thread @p tid was spawned.
+    /// Indicates that the thread @p child_tid was spawned.
     static ProcessMessage NewThread(lldb::tid_t parent_tid, lldb::tid_t child_tid) {
         return ProcessMessage(parent_tid, eNewThreadMessage, child_tid);
     }
 
+    /// Indicates that the thread @p tid is about to exit with status @p status.
+    static ProcessMessage Exit(lldb::tid_t tid, int status) {
+        return ProcessMessage(tid, eExitMessage, status);
+    }
+
     int GetExitStatus() const {
         assert(GetKind() == eExitMessage || GetKind() == eLimboMessage);
         return m_status;

Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp?rev=182809&r1=182808&r2=182809&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp Tue May 28 18:04:25 2013
@@ -75,6 +75,7 @@ ProcessPOSIX::ProcessPOSIX(Target& targe
       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 @@ ProcessPOSIX::SendMessage(const ProcessM
 {
     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 @@ ProcessPOSIX::SendMessage(const ProcessM
         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 @@ ProcessPOSIX::SendMessage(const ProcessM
         }
     }
 
-    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();
 
-    assert(thread);
-    thread->Notify(message);
+        if (thread)
+            thread->Notify(message);
 
-    m_message_queue.pop();
+        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();
+    }
 }
 
 bool

Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h?rev=182809&r1=182808&r2=182809&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h Tue May 28 18:04:25 2013
@@ -152,6 +152,11 @@ public:
     GetFilePath(const lldb_private::ProcessLaunchInfo::FileAction *file_action,
                 const char *default_path);
 
+    /// Stops all threads in the process.
+    /// The \p stop_tid parameter indicates the thread which initiated the stop.
+    virtual void
+    StopAllThreads(lldb::tid_t stop_tid);
+
 protected:
     /// Target byte order.
     lldb::ByteOrder m_byte_order;

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=182809&r1=182808&r2=182809&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Tue May 28 18:04:25 2013
@@ -1720,7 +1720,7 @@ Process::SetPrivateState (StateType new_
         else
             m_private_run_lock.WriteLock();
     }
-    
+
     if (state_changed)
     {
         m_private_state.SetValueNoLock (new_state);

Added: lldb/trunk/test/functionalities/thread/break_after_join/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/break_after_join/Makefile?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/break_after_join/Makefile (added)
+++ lldb/trunk/test/functionalities/thread/break_after_join/Makefile Tue May 28 18:04:25 2013
@@ -0,0 +1,4 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/functionalities/thread/break_after_join/TestBreakAfterJoin.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/break_after_join/TestBreakAfterJoin.py?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/break_after_join/TestBreakAfterJoin.py (added)
+++ lldb/trunk/test/functionalities/thread/break_after_join/TestBreakAfterJoin.py Tue May 28 18:04:25 2013
@@ -0,0 +1,102 @@
+"""
+Test number of threads.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+class BreakpointAfterJoinTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "thread", "break_after_join")
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @dsym_test
+    def test_with_dsym(self):
+        """Test breakpoint handling after a thread join."""
+        self.buildDsym(dictionary=self.getBuildFlags())
+        self.breakpoint_after_join_test()
+
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @skipIfLinux # Fails intermittently, llvm.org/pr16170"
+    @dwarf_test
+    def test_with_dwarf(self):
+        """Test breakpoint handling after a thread join."""
+        self.buildDwarf(dictionary=self.getBuildFlags())
+        self.breakpoint_after_join_test()
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Find the line number for our breakpoint.
+        self.breakpoint = line_number('main.cpp', '// Set breakpoint here')
+
+    def breakpoint_after_join_test(self):
+        """Test breakpoint handling after a thread join."""
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        # This should create a breakpoint in the main thread.
+        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.breakpoint, num_expected_locations=1)
+
+        # The breakpoint list should show 1 location.
+        self.expect("breakpoint list -f", "Breakpoint location shown correctly",
+            substrs = ["1: file ='main.cpp', line = %d, locations = 1" % self.breakpoint])
+
+        # Run the program.
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # The stop reason of the thread should be breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs = ['stopped',
+                       'stop reason = breakpoint'])
+
+        # Get the target process
+        target = self.dbg.GetSelectedTarget()
+        process = target.GetProcess()
+
+        # The exit probably occured during breakpoint handling, but it isn't
+        # guaranteed.  The main thing we're testing here is that the debugger
+        # handles this cleanly is some way.
+
+        # Get the number of threads
+        num_threads = process.GetNumThreads()
+
+        # Make sure we see six threads
+        self.assertTrue(num_threads == 6, 'Number of expected threads and actual threads do not match.')
+
+        # Get the thread objects
+        thread1 = process.GetThreadAtIndex(0)
+        thread2 = process.GetThreadAtIndex(1)
+        thread3 = process.GetThreadAtIndex(2)
+        thread4 = process.GetThreadAtIndex(3)
+        thread5 = process.GetThreadAtIndex(4)
+        thread6 = process.GetThreadAtIndex(5)
+
+        # Make sure all threads are stopped
+        self.assertTrue(thread1.IsStopped(), "Thread 1 didn't stop during breakpoint")
+        self.assertTrue(thread2.IsStopped(), "Thread 2 didn't stop during breakpoint")
+        self.assertTrue(thread3.IsStopped(), "Thread 3 didn't stop during breakpoint")
+        self.assertTrue(thread4.IsStopped(), "Thread 4 didn't stop during breakpoint")
+        self.assertTrue(thread5.IsStopped(), "Thread 5 didn't stop during breakpoint")
+        self.assertTrue(thread6.IsStopped(), "Thread 6 didn't stop during breakpoint")
+
+        # Run to completion
+        self.runCmd("continue")
+
+        # If the process hasn't exited, collect some information
+        if process.GetState() != lldb.eStateExited:
+            self.runCmd("thread list")
+            self.runCmd("process status")
+
+        # At this point, the inferior process should have exited.
+        self.assertTrue(process.GetState() == lldb.eStateExited, PROCESS_EXITED)
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/thread/break_after_join/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/break_after_join/main.cpp?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/break_after_join/main.cpp (added)
+++ lldb/trunk/test/functionalities/thread/break_after_join/main.cpp Tue May 28 18:04:25 2013
@@ -0,0 +1,125 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This test is intended to create a situation in which one thread will exit
+// while a breakpoint is being handled in another thread.  This may not always
+// happen because it's possible that the exiting thread will exit before the
+// breakpoint is hit.  The test case should be flexible enough to treat that
+// as success.
+
+#include <pthread.h>
+#include <unistd.h>
+#include <atomic>
+
+volatile int g_test = 0;
+
+// Note that although hogging the CPU while waiting for a variable to change
+// would be terrible in production code, it's great for testing since it
+// avoids a lot of messy context switching to get multiple threads synchronized.
+#define do_nothing()  
+
+#define pseudo_barrier_wait(bar) \
+    --bar;                       \
+    while (bar > 0)              \
+        do_nothing();
+
+#define pseudo_barrier_init(bar, count) (bar = count)
+
+// A barrier to synchronize all the threads.
+std::atomic_int g_barrier1;
+
+// A barrier to keep the threads from exiting until after the breakpoint has
+// been passed.
+std::atomic_int g_barrier2;
+
+void *
+break_thread_func (void *input)
+{
+    // Wait until all the threads are running
+    pseudo_barrier_wait(g_barrier1);
+
+    // Wait for the join thread to join
+    usleep(50);
+
+    // Do something
+    g_test++;       // Set breakpoint here
+
+    // Synchronize after the breakpoint
+    pseudo_barrier_wait(g_barrier2);
+
+    // Return
+    return NULL;
+}
+
+void *
+wait_thread_func (void *input)
+{
+    // Wait until the entire first group of threads is running
+    pseudo_barrier_wait(g_barrier1);
+
+    // Wait until the breakpoint has been passed
+    pseudo_barrier_wait(g_barrier2);
+
+    // Return
+    return NULL;
+}
+
+void *
+join_thread_func (void *input)
+{
+    pthread_t *thread_to_join = (pthread_t*)input;
+
+    // Sync up with the rest of the threads.
+    pseudo_barrier_wait(g_barrier1);
+
+    // Join the other thread
+    pthread_join(*thread_to_join, NULL);
+
+    // Return
+    return NULL;
+}
+
+int main ()
+{
+    pthread_t thread_1;
+    pthread_t thread_2;
+    pthread_t thread_3;
+    pthread_t thread_4;
+    pthread_t thread_5;
+
+    // The first barrier waits for the non-joining threads to start.
+    // This thread will also participate in that barrier.
+    // The idea here is to guarantee that the joining thread will be
+    // last in the internal list maintained by the debugger.
+    pseudo_barrier_init(g_barrier1, 5);
+
+    // The second barrier keeps the waiting threads around until the breakpoint
+    // has been passed.
+    pseudo_barrier_init(g_barrier2, 4);
+
+    // Create a thread to hit the breakpoint
+    pthread_create (&thread_1, NULL, break_thread_func, NULL);
+
+    // Create more threads to slow the debugger down during processing.
+    pthread_create (&thread_2, NULL, wait_thread_func, NULL);
+    pthread_create (&thread_3, NULL, wait_thread_func, NULL);
+    pthread_create (&thread_4, NULL, wait_thread_func, NULL);
+
+    // Create a thread to join the breakpoint thread
+    pthread_create (&thread_5, NULL, join_thread_func, &thread_4);
+
+    // Wait for the threads to finish
+    pthread_join(thread_5, NULL);
+    pthread_join(thread_4, NULL);
+    pthread_join(thread_3, NULL);
+    pthread_join(thread_2, NULL);
+    pthread_join(thread_1, NULL);
+
+    return 0;
+}

Added: lldb/trunk/test/functionalities/thread/create_during_step/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/create_during_step/Makefile?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/create_during_step/Makefile (added)
+++ lldb/trunk/test/functionalities/thread/create_during_step/Makefile Tue May 28 18:04:25 2013
@@ -0,0 +1,4 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/functionalities/thread/create_during_step/TestCreateDuringStep.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/create_during_step/TestCreateDuringStep.py?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/create_during_step/TestCreateDuringStep.py (added)
+++ lldb/trunk/test/functionalities/thread/create_during_step/TestCreateDuringStep.py Tue May 28 18:04:25 2013
@@ -0,0 +1,157 @@
+"""
+Test number of threads.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+class CreateDuringStepTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "thread", "create_during_step")
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @dsym_test
+    def test_step_inst_with_dsym(self):
+        """Test thread creation during step-inst handling."""
+        self.buildDsym(dictionary=self.getBuildFlags())
+        self.create_during_step_inst_test()
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @dsym_test
+    def test_step_over_with_dsym(self):
+        """Test thread creation during step-over handling."""
+        self.buildDsym(dictionary=self.getBuildFlags())
+        self.create_during_step_over_test()
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @dsym_test
+    def test_step_in_with_dsym(self):
+        """Test thread creation during step-in handling."""
+        self.buildDsym(dictionary=self.getBuildFlags())
+        self.create_during_step_in_test()
+
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @dwarf_test
+    def test_step_inst_with_dwarf(self):
+        """Test thread creation during step-inst handling."""
+        self.buildDwarf(dictionary=self.getBuildFlags())
+        self.create_during_step_inst_test()
+
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @expectedFailureLinux("llvm.org/pr16171") # step in/over don't behave in the multithreaded case
+    @dwarf_test
+    def test_step_over_with_dwarf(self):
+        """Test thread creation during step-over handling."""
+        self.buildDwarf(dictionary=self.getBuildFlags())
+        self.create_during_step_over_test()
+
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @expectedFailureLinux("llvm.org/pr16171") # step in/over don't behave in the multithreaded case
+    @dwarf_test
+    def test_step_in_with_dwarf(self):
+        """Test thread creation during step-in handling."""
+        self.buildDwarf(dictionary=self.getBuildFlags())
+        self.create_during_step_in_test()
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Find the line numbers to break and continue.
+        self.breakpoint = line_number('main.cpp', '// Set breakpoint here')
+        self.continuepoint = line_number('main.cpp', '// Continue from here')
+
+    def create_during_step_inst_test(self):
+        """Test thread creation while using step-inst."""
+        self.create_during_step_base("thread step-inst -m all-threads")
+
+    def create_during_step_over_test(self):
+        """Test thread creation while using step-over."""
+        self.create_during_step_base("thread step-over -m all-threads")
+
+    def create_during_step_in_test(self):
+        """Test thread creation while using step-in."""
+        self.create_during_step_base("thread step-in -m all-threads")
+
+    def create_during_step_base(self, step_cmd):
+        """Test thread creation while using step-in."""
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        # This should create a breakpoint in the stepping thread.
+        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.breakpoint, num_expected_locations=1)
+
+        # The breakpoint list should show 1 location.
+        self.expect("breakpoint list -f", "Breakpoint location shown correctly",
+            substrs = ["1: file ='main.cpp', line = %d, locations = 1" % self.breakpoint])
+
+        # Run the program.
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # The stop reason of the thread should be breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs = ['stopped',
+                       'stop reason = breakpoint'])
+
+        # Get the target process
+        target = self.dbg.GetSelectedTarget()
+        process = target.GetProcess()
+
+        # Get the number of threads
+        num_threads = process.GetNumThreads()
+
+        # Make sure we see only two threads
+        self.assertTrue(num_threads == 2, 'Number of expected threads and actual threads do not match.')
+
+        # Get the thread objects
+        thread1 = process.GetThreadAtIndex(0)
+        thread2 = process.GetThreadAtIndex(1)
+
+        # Make sure both threads are stopped
+        self.assertTrue(thread1.IsStopped(), "Thread 1 didn't stop during breakpoint")
+        self.assertTrue(thread2.IsStopped(), "Thread 2 didn't stop during breakpoint")
+
+        # Keep stepping until we've reached our designated continue point
+        stepping_thread = process.GetSelectedThread()
+        current_line = self.breakpoint
+        while current_line != self.continuepoint:
+            self.runCmd(step_cmd)
+
+            # The thread creation may change the selected thread.
+            # If it does, we just change it back here.
+            if stepping_thread != process.GetSelectedThread():
+                process.SetSelectedThread(stepping_thread)
+
+            frame = stepping_thread.GetFrameAtIndex(0)
+            current_line = frame.GetLineEntry().GetLine()
+
+            # Make sure we're still where we thought we were
+            self.assertTrue(current_line >= self.breakpoint, "Stepped to unexpected line, " + str(current_line))
+            self.assertTrue(current_line <= self.continuepoint, "Stepped to unexpected line, " + str(current_line))
+
+        # Update the number of threads
+        num_threads = process.GetNumThreads()
+
+        # Check to see that we increased the number of threads as expected
+        self.assertTrue(num_threads == 3, 'Number of expected threads and actual threads do not match after thread exit.')
+
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+                substrs = ['stopped',
+                           'top reason = instruction step int'])
+
+        # Run to completion
+        self.runCmd("process continue")
+
+        # At this point, the inferior process should have exited.
+        self.assertTrue(process.GetState() == lldb.eStateExited, PROCESS_EXITED)
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/thread/create_during_step/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/create_during_step/main.cpp?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/create_during_step/main.cpp (added)
+++ lldb/trunk/test/functionalities/thread/create_during_step/main.cpp Tue May 28 18:04:25 2013
@@ -0,0 +1,92 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This test is intended to create a situation in which one thread will be
+// created while a the debugger is stepping in another thread.
+
+#include <pthread.h>
+#include <atomic>
+
+// Note that although hogging the CPU while waiting for a variable to change
+// would be terrible in production code, it's great for testing since it
+// avoids a lot of messy context switching to get multiple threads synchronized.
+#define do_nothing()
+
+#define pseudo_barrier_wait(bar) \
+    --bar;                       \
+    while (bar > 0)              \
+        do_nothing();
+
+#define pseudo_barrier_init(bar, count) (bar = count)
+
+std::atomic_int g_barrier;
+
+volatile int g_thread_created = 0;
+volatile int g_test = 0;
+
+void *
+step_thread_func (void *input)
+{
+    g_test = 0;         // Set breakpoint here
+
+    while (!g_thread_created)
+        g_test++;
+
+    // One more time to provide a continue point
+    g_test++;           // Continue from here
+
+    // Return
+    return NULL;
+}
+
+void *
+create_thread_func (void *input)
+{
+    pthread_t *step_thread = (pthread_t*)input;
+
+    // Wait until the main thread knows this thread is started.
+    pseudo_barrier_wait(g_barrier);
+
+    // Wait until the other thread is done.
+    pthread_join(*step_thread, NULL);
+
+    // Return
+    return NULL;
+}
+
+int main ()
+{
+    pthread_t thread_1;
+    pthread_t thread_2;
+
+    // Use a simple count to simulate a barrier.
+    pseudo_barrier_init(g_barrier, 2);
+
+    // Create a thread to hit the breakpoint.
+    pthread_create (&thread_1, NULL, step_thread_func, NULL);
+
+    // Wait until the step thread is stepping
+    while (g_test < 1)
+        do_nothing();
+
+    // Create a thread to exit while we're stepping.
+    pthread_create (&thread_2, NULL, create_thread_func, &thread_1);
+
+    // Wait until that thread is started
+    pseudo_barrier_wait(g_barrier);
+
+    // Let the stepping thread know the other thread is there
+    g_thread_created = 1;
+
+    // Wait for the threads to finish.
+    pthread_join(thread_2, NULL);
+    pthread_join(thread_1, NULL);
+
+    return 0;
+}

Added: lldb/trunk/test/functionalities/thread/exit_during_break/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/exit_during_break/Makefile?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/exit_during_break/Makefile (added)
+++ lldb/trunk/test/functionalities/thread/exit_during_break/Makefile Tue May 28 18:04:25 2013
@@ -0,0 +1,4 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/functionalities/thread/exit_during_break/TestExitDuringBreak.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/exit_during_break/TestExitDuringBreak.py?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/exit_during_break/TestExitDuringBreak.py (added)
+++ lldb/trunk/test/functionalities/thread/exit_during_break/TestExitDuringBreak.py Tue May 28 18:04:25 2013
@@ -0,0 +1,94 @@
+"""
+Test number of threads.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+class ExitDuringBreakpointTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "thread", "exit_during_break")
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @dsym_test
+    def test_with_dsym(self):
+        """Test thread exit during breakpoint handling."""
+        self.buildDsym(dictionary=self.getBuildFlags())
+        self.exit_during_breakpoint_test()
+
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @dwarf_test
+    def test_with_dwarf(self):
+        """Test thread exit during breakpoint handling."""
+        self.buildDwarf(dictionary=self.getBuildFlags())
+        self.exit_during_breakpoint_test()
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Find the line number for our breakpoint.
+        self.breakpoint = line_number('main.cpp', '// Set breakpoint here')
+
+    def exit_during_breakpoint_test(self):
+        """Test thread exit during breakpoint handling."""
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        # This should create a breakpoint in the main thread.
+        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.breakpoint, num_expected_locations=1)
+
+        # The breakpoint list should show 1 location.
+        self.expect("breakpoint list -f", "Breakpoint location shown correctly",
+            substrs = ["1: file ='main.cpp', line = %d, locations = 1" % self.breakpoint])
+
+        # Run the program.
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # The stop reason of the thread should be breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs = ['stopped',
+                       'stop reason = breakpoint'])
+
+        # Get the target process
+        target = self.dbg.GetSelectedTarget()
+        process = target.GetProcess()
+
+        # The exit probably occured during breakpoint handling, but it isn't
+        # guaranteed.  The main thing we're testing here is that the debugger
+        # handles this cleanly is some way.
+
+        # Get the number of threads
+        num_threads = process.GetNumThreads()
+
+        # Make sure we see at least five threads
+        self.assertTrue(num_threads >= 5, 'Number of expected threads and actual threads do not match.')
+
+        # Get the thread objects
+        thread1 = process.GetThreadAtIndex(0)
+        thread2 = process.GetThreadAtIndex(1)
+        thread3 = process.GetThreadAtIndex(2)
+        thread4 = process.GetThreadAtIndex(3)
+        thread5 = process.GetThreadAtIndex(4)
+
+        # Make sure all threads are stopped
+        self.assertTrue(thread1.IsStopped(), "Thread 1 didn't stop during breakpoint")
+        self.assertTrue(thread2.IsStopped(), "Thread 2 didn't stop during breakpoint")
+        self.assertTrue(thread3.IsStopped(), "Thread 3 didn't stop during breakpoint")
+        self.assertTrue(thread4.IsStopped(), "Thread 4 didn't stop during breakpoint")
+        self.assertTrue(thread5.IsStopped(), "Thread 5 didn't stop during breakpoint")
+
+        # Run to completion
+        self.runCmd("continue")
+
+        # At this point, the inferior process should have exited.
+        self.assertTrue(process.GetState() == lldb.eStateExited, PROCESS_EXITED)
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/thread/exit_during_break/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/exit_during_break/main.cpp?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/exit_during_break/main.cpp (added)
+++ lldb/trunk/test/functionalities/thread/exit_during_break/main.cpp Tue May 28 18:04:25 2013
@@ -0,0 +1,135 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This test is intended to create a situation in which one thread will exit
+// while a breakpoint is being handled in another thread.  This may not always
+// happen because it's possible that the exiting thread will exit before the
+// breakpoint is hit.  The test case should be flexible enough to treat that
+// as success.
+
+#include <pthread.h>
+#include <unistd.h>
+#include <atomic>
+
+volatile int g_test = 0;
+
+// Note that although hogging the CPU while waiting for a variable to change
+// would be terrible in production code, it's great for testing since it
+// avoids a lot of messy context switching to get multiple threads synchronized.
+#define do_nothing()  
+
+#define pseudo_barrier_wait(bar) \
+    --bar;                       \
+    while (bar > 0)              \
+        do_nothing();
+
+#define pseudo_barrier_init(bar, count) (bar = count)
+
+// A barrier to synchronize all the threads except the one that will exit.
+std::atomic_int g_barrier1;
+
+// A barrier to synchronize all the threads including the one that will exit.
+std::atomic_int g_barrier2;
+
+// A barrier to keep the first group of threads from exiting until after the
+// breakpoint has been passed.
+std::atomic_int g_barrier3;
+
+void *
+break_thread_func (void *input)
+{
+    // Wait until the entire first group of threads is running
+    pseudo_barrier_wait(g_barrier1);
+
+    // Wait for the exiting thread to start
+    pseudo_barrier_wait(g_barrier2);
+
+    // Do something
+    g_test++;       // Set breakpoint here
+
+    // Synchronize after the breakpoint
+    pseudo_barrier_wait(g_barrier3);
+
+    // Return
+    return NULL;
+}
+
+void *
+wait_thread_func (void *input)
+{
+    // Wait until the entire first group of threads is running
+    pseudo_barrier_wait(g_barrier1);
+
+    // Wait for the exiting thread to start
+    pseudo_barrier_wait(g_barrier2);
+
+    // Wait until the breakpoint has been passed
+    pseudo_barrier_wait(g_barrier3);
+
+    // Return
+    return NULL;
+}
+
+void *
+exit_thread_func (void *input)
+{
+    // Sync up with the rest of the threads.
+    pseudo_barrier_wait(g_barrier2);
+
+    // Try to make sure this thread doesn't exit until the breakpoint is hit.
+    usleep(1);
+
+    // Return
+    return NULL;
+}
+
+int main ()
+{
+    pthread_t thread_1;
+    pthread_t thread_2;
+    pthread_t thread_3;
+    pthread_t thread_4;
+    pthread_t thread_5;
+
+    // The first barrier waits for the non-exiting threads to start.
+    // This thread will also participate in that barrier.
+    // The idea here is to guarantee that the exiting thread will be
+    // last in the internal list maintained by the debugger.
+    pseudo_barrier_init(g_barrier1, 5);
+
+    // The second break synchronyizes thread exection with the breakpoint.
+    pseudo_barrier_init(g_barrier2, 5);
+
+    // The third barrier keeps the waiting threads around until the breakpoint
+    // has been passed.
+    pseudo_barrier_init(g_barrier3, 4);
+
+    // Create a thread to hit the breakpoint
+    pthread_create (&thread_1, NULL, break_thread_func, NULL);
+
+    // Create more threads to slow the debugger down during processing.
+    pthread_create (&thread_2, NULL, wait_thread_func, NULL);
+    pthread_create (&thread_3, NULL, wait_thread_func, NULL);
+    pthread_create (&thread_4, NULL, wait_thread_func, NULL);
+
+    // Wait for all these threads to get started.
+    pseudo_barrier_wait(g_barrier1);
+
+    // Create a thread to exit during the breakpoint
+    pthread_create (&thread_5, NULL, exit_thread_func, NULL);
+
+    // Wait for the threads to finish
+    pthread_join(thread_5, NULL);
+    pthread_join(thread_4, NULL);
+    pthread_join(thread_3, NULL);
+    pthread_join(thread_2, NULL);
+    pthread_join(thread_1, NULL);
+
+    return 0;
+}

Added: lldb/trunk/test/functionalities/thread/exit_during_break/main.d.23591
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/exit_during_break/main.d.23591?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/exit_during_break/main.d.23591 (added)
+++ lldb/trunk/test/functionalities/thread/exit_during_break/main.d.23591 Tue May 28 18:04:25 2013
@@ -0,0 +1,39 @@
+main.o: main.cpp /usr/include/pthread.h /usr/include/features.h \
+  /usr/include/x86_64-linux-gnu/bits/predefs.h \
+  /usr/include/x86_64-linux-gnu/sys/cdefs.h \
+  /usr/include/x86_64-linux-gnu/bits/wordsize.h \
+  /usr/include/x86_64-linux-gnu/gnu/stubs.h \
+  /usr/include/x86_64-linux-gnu/gnu/stubs-64.h /usr/include/endian.h \
+  /usr/include/x86_64-linux-gnu/bits/endian.h \
+  /usr/include/x86_64-linux-gnu/bits/byteswap.h /usr/include/sched.h \
+  /usr/include/x86_64-linux-gnu/bits/types.h \
+  /usr/include/x86_64-linux-gnu/bits/typesizes.h \
+  /home/akaylor/clang-install/bin/../lib/clang/3.3/include/stddef.h \
+  /usr/include/time.h /usr/include/x86_64-linux-gnu/bits/sched.h \
+  /usr/include/x86_64-linux-gnu/bits/time.h \
+  /usr/include/x86_64-linux-gnu/bits/timex.h /usr/include/xlocale.h \
+  /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
+  /usr/include/x86_64-linux-gnu/bits/setjmp.h /usr/include/stdio.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
+  /home/akaylor/clang-install/bin/../lib/clang/3.3/include/stdarg.h \
+  /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
+  /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/unistd.h \
+  /usr/include/x86_64-linux-gnu/bits/posix_opt.h \
+  /usr/include/x86_64-linux-gnu/bits/environments.h \
+  /usr/include/x86_64-linux-gnu/bits/confname.h /usr/include/getopt.h \
+  /usr/include/x86_64-linux-gnu/sys/types.h \
+  /usr/include/x86_64-linux-gnu/sys/select.h \
+  /usr/include/x86_64-linux-gnu/bits/select.h \
+  /usr/include/x86_64-linux-gnu/bits/sigset.h \
+  /usr/include/x86_64-linux-gnu/sys/sysmacros.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/atomic \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/c++0x_warning.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/atomic_base.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/x86_64-linux-gnu/bits/c++config.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/x86_64-linux-gnu/bits/os_defines.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/x86_64-linux-gnu/bits/cpu_defines.h \
+  /home/akaylor/clang-install/bin/../lib/clang/3.3/include/stdbool.h \
+  /home/akaylor/clang-install/bin/../lib/clang/3.3/include/stdint.h \
+  /usr/include/stdint.h /usr/include/x86_64-linux-gnu/bits/wchar.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/atomic_0.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/atomic_2.h

Added: lldb/trunk/test/functionalities/thread/exit_during_break/main.d.23604
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/exit_during_break/main.d.23604?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/exit_during_break/main.d.23604 (added)
+++ lldb/trunk/test/functionalities/thread/exit_during_break/main.d.23604 Tue May 28 18:04:25 2013
@@ -0,0 +1,39 @@
+main.o: main.cpp /usr/include/pthread.h /usr/include/features.h \
+  /usr/include/x86_64-linux-gnu/bits/predefs.h \
+  /usr/include/x86_64-linux-gnu/sys/cdefs.h \
+  /usr/include/x86_64-linux-gnu/bits/wordsize.h \
+  /usr/include/x86_64-linux-gnu/gnu/stubs.h \
+  /usr/include/x86_64-linux-gnu/gnu/stubs-64.h /usr/include/endian.h \
+  /usr/include/x86_64-linux-gnu/bits/endian.h \
+  /usr/include/x86_64-linux-gnu/bits/byteswap.h /usr/include/sched.h \
+  /usr/include/x86_64-linux-gnu/bits/types.h \
+  /usr/include/x86_64-linux-gnu/bits/typesizes.h \
+  /home/akaylor/clang-install/bin/../lib/clang/3.3/include/stddef.h \
+  /usr/include/time.h /usr/include/x86_64-linux-gnu/bits/sched.h \
+  /usr/include/x86_64-linux-gnu/bits/time.h \
+  /usr/include/x86_64-linux-gnu/bits/timex.h /usr/include/xlocale.h \
+  /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
+  /usr/include/x86_64-linux-gnu/bits/setjmp.h /usr/include/stdio.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
+  /home/akaylor/clang-install/bin/../lib/clang/3.3/include/stdarg.h \
+  /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
+  /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/unistd.h \
+  /usr/include/x86_64-linux-gnu/bits/posix_opt.h \
+  /usr/include/x86_64-linux-gnu/bits/environments.h \
+  /usr/include/x86_64-linux-gnu/bits/confname.h /usr/include/getopt.h \
+  /usr/include/x86_64-linux-gnu/sys/types.h \
+  /usr/include/x86_64-linux-gnu/sys/select.h \
+  /usr/include/x86_64-linux-gnu/bits/select.h \
+  /usr/include/x86_64-linux-gnu/bits/sigset.h \
+  /usr/include/x86_64-linux-gnu/sys/sysmacros.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/atomic \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/c++0x_warning.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/atomic_base.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/x86_64-linux-gnu/bits/c++config.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/x86_64-linux-gnu/bits/os_defines.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/x86_64-linux-gnu/bits/cpu_defines.h \
+  /home/akaylor/clang-install/bin/../lib/clang/3.3/include/stdbool.h \
+  /home/akaylor/clang-install/bin/../lib/clang/3.3/include/stdint.h \
+  /usr/include/stdint.h /usr/include/x86_64-linux-gnu/bits/wchar.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/atomic_0.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/atomic_2.h

Added: lldb/trunk/test/functionalities/thread/exit_during_break/main.d.23614
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/exit_during_break/main.d.23614?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/exit_during_break/main.d.23614 (added)
+++ lldb/trunk/test/functionalities/thread/exit_during_break/main.d.23614 Tue May 28 18:04:25 2013
@@ -0,0 +1,39 @@
+main.o: main.cpp /usr/include/pthread.h /usr/include/features.h \
+  /usr/include/x86_64-linux-gnu/bits/predefs.h \
+  /usr/include/x86_64-linux-gnu/sys/cdefs.h \
+  /usr/include/x86_64-linux-gnu/bits/wordsize.h \
+  /usr/include/x86_64-linux-gnu/gnu/stubs.h \
+  /usr/include/x86_64-linux-gnu/gnu/stubs-64.h /usr/include/endian.h \
+  /usr/include/x86_64-linux-gnu/bits/endian.h \
+  /usr/include/x86_64-linux-gnu/bits/byteswap.h /usr/include/sched.h \
+  /usr/include/x86_64-linux-gnu/bits/types.h \
+  /usr/include/x86_64-linux-gnu/bits/typesizes.h \
+  /home/akaylor/clang-install/bin/../lib/clang/3.3/include/stddef.h \
+  /usr/include/time.h /usr/include/x86_64-linux-gnu/bits/sched.h \
+  /usr/include/x86_64-linux-gnu/bits/time.h \
+  /usr/include/x86_64-linux-gnu/bits/timex.h /usr/include/xlocale.h \
+  /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
+  /usr/include/x86_64-linux-gnu/bits/setjmp.h /usr/include/stdio.h \
+  /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
+  /home/akaylor/clang-install/bin/../lib/clang/3.3/include/stdarg.h \
+  /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
+  /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/unistd.h \
+  /usr/include/x86_64-linux-gnu/bits/posix_opt.h \
+  /usr/include/x86_64-linux-gnu/bits/environments.h \
+  /usr/include/x86_64-linux-gnu/bits/confname.h /usr/include/getopt.h \
+  /usr/include/x86_64-linux-gnu/sys/types.h \
+  /usr/include/x86_64-linux-gnu/sys/select.h \
+  /usr/include/x86_64-linux-gnu/bits/select.h \
+  /usr/include/x86_64-linux-gnu/bits/sigset.h \
+  /usr/include/x86_64-linux-gnu/sys/sysmacros.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/atomic \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/c++0x_warning.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/atomic_base.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/x86_64-linux-gnu/bits/c++config.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/x86_64-linux-gnu/bits/os_defines.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/x86_64-linux-gnu/bits/cpu_defines.h \
+  /home/akaylor/clang-install/bin/../lib/clang/3.3/include/stdbool.h \
+  /home/akaylor/clang-install/bin/../lib/clang/3.3/include/stdint.h \
+  /usr/include/stdint.h /usr/include/x86_64-linux-gnu/bits/wchar.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/atomic_0.h \
+  /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/atomic_2.h

Added: lldb/trunk/test/functionalities/thread/exit_during_step/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/exit_during_step/Makefile?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/exit_during_step/Makefile (added)
+++ lldb/trunk/test/functionalities/thread/exit_during_step/Makefile Tue May 28 18:04:25 2013
@@ -0,0 +1,4 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/functionalities/thread/exit_during_step/TestExitDuringStep.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/exit_during_step/TestExitDuringStep.py?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/exit_during_step/TestExitDuringStep.py (added)
+++ lldb/trunk/test/functionalities/thread/exit_during_step/TestExitDuringStep.py Tue May 28 18:04:25 2013
@@ -0,0 +1,113 @@
+"""
+Test number of threads.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+class ExitDuringStepTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "thread", "exit_during_step")
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @dsym_test
+    def test_with_dsym(self):
+        """Test thread exit during step handling."""
+        self.buildDsym(dictionary=self.getBuildFlags())
+        self.exit_during_step_test()
+
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @dwarf_test
+    def test_with_dwarf(self):
+        """Test thread exit during step handling."""
+        self.buildDwarf(dictionary=self.getBuildFlags())
+        self.exit_during_step_test()
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Find the line numbers to break and continue.
+        self.breakpoint = line_number('main.cpp', '// Set breakpoint here')
+        self.continuepoint = line_number('main.cpp', '// Continue from here')
+
+    def exit_during_step_test(self):
+        """Test thread exit during step handling."""
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        # This should create a breakpoint in the main thread.
+        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.breakpoint, num_expected_locations=1)
+
+        # The breakpoint list should show 1 location.
+        self.expect("breakpoint list -f", "Breakpoint location shown correctly",
+            substrs = ["1: file ='main.cpp', line = %d, locations = 1" % self.breakpoint])
+
+        # Run the program.
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # The stop reason of the thread should be breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs = ['stopped',
+                       'stop reason = breakpoint'])
+
+        # Get the target process
+        target = self.dbg.GetSelectedTarget()
+        process = target.GetProcess()
+
+        # Get the number of threads
+        num_threads = process.GetNumThreads()
+
+        # Make sure we see all three threads
+        self.assertTrue(num_threads == 3, 'Number of expected threads and actual threads do not match.')
+
+        # Get the thread objects
+        thread1 = process.GetThreadAtIndex(0)
+        thread2 = process.GetThreadAtIndex(1)
+        thread3 = process.GetThreadAtIndex(2)
+
+        # Make sure all threads are stopped
+        self.assertTrue(thread1.IsStopped(), "Thread 1 didn't stop during breakpoint")
+        self.assertTrue(thread2.IsStopped(), "Thread 2 didn't stop during breakpoint")
+        self.assertTrue(thread3.IsStopped(), "Thread 3 didn't stop during breakpoint")
+
+        # Keep stepping until we've reached our designated continue point
+        stepping_thread = process.GetSelectedThread()
+        current_line = self.breakpoint
+        stepping_frame = stepping_thread.GetFrameAtIndex(0)
+        self.assertTrue(current_line == stepping_frame.GetLineEntry().GetLine(), "Starting line for stepping doesn't match breakpoint line.")
+        while current_line != self.continuepoint:
+            self.runCmd("thread step-inst -m all-threads")
+
+            if stepping_thread != process.GetSelectedThread():
+                process.SetSelectedThread(stepping_thread)
+
+            frame = stepping_thread.GetFrameAtIndex(0)
+
+            current_line = frame.GetLineEntry().GetLine()
+
+            self.assertTrue(current_line >= self.breakpoint, "Stepped to unexpected line, " + str(current_line))
+            self.assertTrue(current_line <= self.continuepoint, "Stepped to unexpected line, " + str(current_line))
+
+        self.runCmd("thread list")
+
+        # Update the number of threads
+        num_threads = process.GetNumThreads()
+
+        # Check to see that we reduced the number of threads as expected
+        self.assertTrue(num_threads == 2, 'Number of expected threads and actual threads do not match after thread exit.')
+
+        # Run to completion
+        self.runCmd("continue")
+
+        # At this point, the inferior process should have exited.
+        self.assertTrue(process.GetState() == lldb.eStateExited, PROCESS_EXITED)
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/thread/exit_during_step/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/exit_during_step/main.cpp?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/exit_during_step/main.cpp (added)
+++ lldb/trunk/test/functionalities/thread/exit_during_step/main.cpp Tue May 28 18:04:25 2013
@@ -0,0 +1,91 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This test is intended to create a situation in which one thread will exit
+// while a the debugger is stepping in another thread.
+
+#include <pthread.h>
+#include <unistd.h>
+
+// Note that although hogging the CPU while waiting for a variable to change
+// would be terrible in production code, it's great for testing since it
+// avoids a lot of messy context switching to get multiple threads synchronized.
+#define do_nothing()
+
+#define pseudo_barrier_wait(bar) \
+    --bar;                       \
+    while (bar > 0)              \
+        do_nothing();
+
+#define pseudo_barrier_init(bar, count) (bar = count)
+
+// A barrier to synchronize thread start.
+volatile int g_barrier;
+
+volatile int g_thread_exited = 0;
+
+volatile int g_test = 0;
+
+void *
+step_thread_func (void *input)
+{
+    // Wait until both threads are started.
+    pseudo_barrier_wait(g_barrier);
+
+    g_test = 0;         // Set breakpoint here
+
+    while (!g_thread_exited)
+        g_test++;
+
+    // One more time to provide a continue point
+    g_test++;           // Continue from here
+
+    // Return
+    return NULL;
+}
+
+void *
+exit_thread_func (void *input)
+{
+    // Wait until both threads are started.
+    pseudo_barrier_wait(g_barrier);
+
+    // Wait until the other thread is stepping.
+    while (g_test == 0)
+      do_nothing();
+
+    // Return
+    return NULL;
+}
+
+int main ()
+{
+    pthread_t thread_1;
+    pthread_t thread_2;
+
+    // Synchronize thread start so that doesn't happen during stepping.
+    pseudo_barrier_init(g_barrier, 2);
+
+    // Create a thread to hit the breakpoint.
+    pthread_create (&thread_1, NULL, step_thread_func, NULL);
+
+    // Create a thread to exit while we're stepping.
+    pthread_create (&thread_2, NULL, exit_thread_func, NULL);
+
+    // Wait for the exit thread to finish.
+    pthread_join(thread_2, NULL);
+
+    // Let the stepping thread know the other thread is gone.
+    g_thread_exited = 1;
+
+    // Wait for the stepping thread to finish.
+    pthread_join(thread_1, NULL);
+
+    return 0;
+}

Added: lldb/trunk/test/functionalities/thread/multi_break/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/multi_break/Makefile?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/multi_break/Makefile (added)
+++ lldb/trunk/test/functionalities/thread/multi_break/Makefile Tue May 28 18:04:25 2013
@@ -0,0 +1,4 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/functionalities/thread/multi_break/TestMultipleBreakpoints.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/multi_break/TestMultipleBreakpoints.py?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/multi_break/TestMultipleBreakpoints.py (added)
+++ lldb/trunk/test/functionalities/thread/multi_break/TestMultipleBreakpoints.py Tue May 28 18:04:25 2013
@@ -0,0 +1,90 @@
+"""
+Test number of threads.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+class MultipleBreakpointTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "thread", "multi_break")
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @dsym_test
+    def test_with_dsym(self):
+        """Test simultaneous breakpoints in multiple threads."""
+        self.buildDsym(dictionary=self.getBuildFlags())
+        self.multiple_breakpoint_test()
+
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @dwarf_test
+    def test_with_dwarf(self):
+        """Test simultaneous breakpoints in multiple threads."""
+        self.buildDwarf(dictionary=self.getBuildFlags())
+        self.multiple_breakpoint_test()
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Find the line number for our breakpoint.
+        self.breakpoint = line_number('main.cpp', '// Set breakpoint here')
+
+    def multiple_breakpoint_test(self):
+        """Test simultaneous breakpoints in multiple threads."""
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        # This should create a breakpoint in the main thread.
+        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.breakpoint, num_expected_locations=1)
+
+        # The breakpoint list should show 1 location.
+        self.expect("breakpoint list -f", "Breakpoint location shown correctly",
+            substrs = ["1: file ='main.cpp', line = %d, locations = 1" % self.breakpoint])
+
+        # Run the program.
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # The stop reason of the thread should be breakpoint.
+        # The breakpoint may be hit in either thread 2 or thread 3.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs = ['stopped',
+                       'stop reason = breakpoint'])
+
+        # Get the target process
+        target = self.dbg.GetSelectedTarget()
+        process = target.GetProcess()
+
+        # Get the number of threads
+        num_threads = process.GetNumThreads()
+
+        # Make sure we see all three threads
+        self.assertTrue(num_threads == 3, 'Number of expected threads and actual threads do not match.')
+
+        # Get the thread objects
+        thread1 = process.GetThreadAtIndex(0)
+        thread2 = process.GetThreadAtIndex(1)
+        thread3 = process.GetThreadAtIndex(2)
+
+        # Make sure both threads are stopped
+        self.assertTrue(thread1.IsStopped(), "Primary thread didn't stop during breakpoint")
+        self.assertTrue(thread2.IsStopped(), "Secondary thread didn't stop during breakpoint")
+        self.assertTrue(thread3.IsStopped(), "Tertiary thread didn't stop during breakpoint")
+
+        # Delete the first breakpoint then continue
+        self.runCmd("breakpoint delete 1")
+
+        # Run to completion
+        self.runCmd("continue")
+
+        # At this point, the inferior process should have exited.
+        self.assertTrue(process.GetState() == lldb.eStateExited, PROCESS_EXITED)
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/thread/multi_break/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/multi_break/main.cpp?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/multi_break/main.cpp (added)
+++ lldb/trunk/test/functionalities/thread/multi_break/main.cpp Tue May 28 18:04:25 2013
@@ -0,0 +1,64 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This test is intended to create a situation in which a breakpoint will be
+// hit in two threads at nearly the same moment.  The expected result is that
+// the breakpoint in the second thread will be hit while the breakpoint handler
+// in the first thread is trying to stop all threads.
+
+#include <pthread.h>
+#include <atomic>
+
+// Note that although hogging the CPU while waiting for a variable to change
+// would be terrible in production code, it's great for testing since it
+// avoids a lot of messy context switching to get multiple threads synchronized.
+#define do_nothing()
+
+#define pseudo_barrier_wait(bar) \
+    --bar;                       \
+    while (bar > 0)              \
+        do_nothing();
+
+#define pseudo_barrier_init(bar, count) (bar = count)
+
+std::atomic_int g_barrier;
+
+volatile int g_test = 0;
+
+void *
+thread_func (void *input)
+{
+    // Wait until both threads are running
+    pseudo_barrier_wait(g_barrier);
+
+    // Do something
+    g_test++;       // Set breakpoint here
+
+    // Return
+    return NULL;
+}
+
+int main ()
+{
+    pthread_t thread_1;
+    pthread_t thread_2;
+
+    // Don't let either thread do anything until they're both ready.
+    pseudo_barrier_init(g_barrier, 2);
+
+    // Create two threads
+    pthread_create (&thread_1, NULL, thread_func, NULL);
+    pthread_create (&thread_2, NULL, thread_func, NULL);
+
+    // Wait for the threads to finish
+    pthread_join(thread_1, NULL);
+    pthread_join(thread_2, NULL);
+
+    return 0;
+}

Modified: lldb/trunk/test/functionalities/thread/state/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/state/Makefile?rev=182809&r1=182808&r2=182809&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/thread/state/Makefile (original)
+++ lldb/trunk/test/functionalities/thread/state/Makefile Tue May 28 18:04:25 2013
@@ -1,5 +1,4 @@
 LEVEL = ../../../make
 
 C_SOURCES := main.c
-LD_EXTRAS := -lpthread
 include $(LEVEL)/Makefile.rules

Modified: lldb/trunk/test/functionalities/thread/state/TestThreadStates.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/state/TestThreadStates.py?rev=182809&r1=182808&r2=182809&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/thread/state/TestThreadStates.py (original)
+++ lldb/trunk/test/functionalities/thread/state/TestThreadStates.py Tue May 28 18:04:25 2013
@@ -8,7 +8,7 @@ import lldb
 from lldbtest import *
 import lldbutil
 
-class StopThreadsTestCase(TestBase):
+class ThreadStateTestCase(TestBase):
 
     mydir = os.path.join("functionalities", "thread", "state")
 
@@ -16,54 +16,54 @@ class StopThreadsTestCase(TestBase):
     @dsym_test
     def test_state_after_breakpoint_with_dsym(self):
         """Test thread state after breakpoint."""
-        self.buildDsym()
+        self.buildDsym(dictionary=self.getBuildFlags(use_cpp11=False))
         self.thread_state_after_breakpoint_test()
 
     @dwarf_test
     def test_state_after_breakpoint_with_dwarf(self):
         """Test thread state after breakpoint."""
-        self.buildDwarf()
+        self.buildDwarf(dictionary=self.getBuildFlags(use_cpp11=False))
         self.thread_state_after_breakpoint_test()
 
     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     @dsym_test
     def test_state_after_continue_with_dsym(self):
         """Test thread state after continue."""
-        self.buildDsym()
+        self.buildDsym(dictionary=self.getBuildFlags(use_cpp11=False))
         self.thread_state_after_continue_test()
 
     @dwarf_test
     def test_state_after_continue_with_dwarf(self):
         """Test thread state after continue."""
-        self.buildDwarf()
+        self.buildDwarf(dictionary=self.getBuildFlags(use_cpp11=False))
         self.thread_state_after_continue_test()
 
     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     @dsym_test
     def test_state_after_expression_with_dsym(self):
         """Test thread state after expression."""
-        self.buildDsym()
+        self.buildDsym(dictionary=self.getBuildFlags(use_cpp11=False))
         self.thread_state_after_continue_test()
 
     @dwarf_test
     def test_state_after_expression_with_dwarf(self):
         """Test thread state after expression."""
-        self.buildDwarf()
+        self.buildDwarf(dictionary=self.getBuildFlags(use_cpp11=False))
         self.thread_state_after_continue_test()
 
     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
     @dsym_test
-    @unittest2.expectedFailure("llvm.org/pr15824") # thread states not properly maintained
+    @unittest2.expectedFailure("llvm.org/pr16172") # thread states not properly maintained
     def test_process_interrupt_with_dsym(self):
         """Test process interrupt."""
-        self.buildDsym()
+        self.buildDsym(dictionary=self.getBuildFlags(use_cpp11=False))
         self.process_interrupt_test()
 
     @dwarf_test
-    @unittest2.expectedFailure("llvm.org/pr15824") # thread states not properly maintained
+    @unittest2.expectedFailure("llvm.org/pr16712") # thread states not properly maintained
     def test_process_interrupt_with_dwarf(self):
         """Test process interrupt."""
-        self.buildDwarf()
+        self.buildDwarf(dictionary=self.getBuildFlags(use_cpp11=False))
         self.process_interrupt_test()
 
     @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
@@ -71,14 +71,14 @@ class StopThreadsTestCase(TestBase):
     @unittest2.expectedFailure("llvm.org/pr15824") # thread states not properly maintained
     def test_process_state_with_dsym(self):
         """Test thread states (comprehensive)."""
-        self.buildDsym()
+        self.buildDsym(dictionary=self.getBuildFlags(use_cpp11=False))
         self.thread_states_test()
 
     @dwarf_test
     @unittest2.expectedFailure("llvm.org/pr15824") # thread states not properly maintained
     def test_process_state_with_dwarf(self):
         """Test thread states (comprehensive)."""
-        self.buildDwarf()
+        self.buildDwarf(dictionary=self.getBuildFlags(use_cpp11=False))
         self.thread_states_test()
 
     def setUp(self):

Added: lldb/trunk/test/functionalities/thread/thread_exit/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/thread_exit/Makefile?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/thread_exit/Makefile (added)
+++ lldb/trunk/test/functionalities/thread/thread_exit/Makefile Tue May 28 18:04:25 2013
@@ -0,0 +1,4 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/functionalities/thread/thread_exit/TestThreadExit.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/thread_exit/TestThreadExit.py?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/thread_exit/TestThreadExit.py (added)
+++ lldb/trunk/test/functionalities/thread/thread_exit/TestThreadExit.py Tue May 28 18:04:25 2013
@@ -0,0 +1,132 @@
+"""
+Test number of threads.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+class ThreadExitTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "thread", "thread_exit")
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @dsym_test
+    def test_with_dsym(self):
+        """Test thread exit handling."""
+        self.buildDsym(dictionary=self.getBuildFlags())
+        self.thread_exit_test()
+
+    @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+    @dwarf_test
+    def test_with_dwarf(self):
+        """Test thread exit handling."""
+        self.buildDwarf(dictionary=self.getBuildFlags())
+        self.thread_exit_test()
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Find the line numbers for our breakpoints.
+        self.break_1 = line_number('main.cpp', '// Set first breakpoint here')
+        self.break_2 = line_number('main.cpp', '// Set second breakpoint here')
+        self.break_3 = line_number('main.cpp', '// Set third breakpoint here')
+        self.break_4 = line_number('main.cpp', '// Set fourth breakpoint here')
+
+    def thread_exit_test(self):
+        """Test thread exit handling."""
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        # This should create a breakpoint with 1 location.
+        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.break_1, num_expected_locations=1)
+        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.break_2, num_expected_locations=1)
+        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.break_3, num_expected_locations=1)
+        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.break_4, num_expected_locations=1)
+
+        # The breakpoint list should show 1 locations.
+        self.expect("breakpoint list -f", "Breakpoint location shown correctly",
+            substrs = ["1: file ='main.cpp', line = %d, locations = 1" % self.break_1,
+                       "2: file ='main.cpp', line = %d, locations = 1" % self.break_2,
+                       "3: file ='main.cpp', line = %d, locations = 1" % self.break_3,
+                       "4: file ='main.cpp', line = %d, locations = 1" % self.break_4])
+
+        # Run the program.
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # The stop reason of the thread should be breakpoint 1.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT + " 1",
+            substrs = ['stopped',
+                       '* thread #1',
+                       'stop reason = breakpoint 1',
+                       'thread #2'])
+
+        # Get the target process
+        target = self.dbg.GetSelectedTarget()
+        process = target.GetProcess()
+
+        # Get the number of threads
+        num_threads = process.GetNumThreads()
+
+        self.assertTrue(num_threads == 2, 'Number of expected threads and actual threads do not match at breakpoint 1.')
+
+        # Run to the second breakpoint
+        self.runCmd("continue")
+
+        # The stop reason of the thread should be breakpoint 1.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT + " 2",
+            substrs = ['stopped',
+                       'thread #1',
+                       '* thread #2',
+                       'stop reason = breakpoint 2',
+                       'thread #3'])
+
+        # Update the number of threads
+        num_threads = process.GetNumThreads()
+
+        self.assertTrue(num_threads == 3, 'Number of expected threads and actual threads do not match at breakpoint 2.')
+
+        # Run to the third breakpoint
+        self.runCmd("continue")
+
+        # The stop reason of the thread should be breakpoint 3.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT + " 3",
+            substrs = ['stopped',
+                       '* thread #1',
+                       'stop reason = breakpoint 3',
+                       'thread #3',
+                       ])
+
+        # Update the number of threads
+        num_threads = process.GetNumThreads()
+
+        self.assertTrue(num_threads == 2, 'Number of expected threads and actual threads do not match at breakpoint 3.')
+
+        # Run to the fourth breakpoint
+        self.runCmd("continue")
+
+        # The stop reason of the thread should be breakpoint 4.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT + " 4",
+            substrs = ['stopped',
+                       '* thread #1',
+                       'stop reason = breakpoint 4'])
+
+        # Update the number of threads
+        num_threads = process.GetNumThreads()
+
+        self.assertTrue(num_threads == 1, 'Number of expected threads and actual threads do not match at breakpoint 4.')
+
+        # Run to completion
+        self.runCmd("continue")
+
+        # At this point, the inferior process should have exited.
+        self.assertTrue(process.GetState() == lldb.eStateExited, PROCESS_EXITED)
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/thread/thread_exit/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/thread_exit/main.cpp?rev=182809&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/thread_exit/main.cpp (added)
+++ lldb/trunk/test/functionalities/thread/thread_exit/main.cpp Tue May 28 18:04:25 2013
@@ -0,0 +1,89 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This test verifies the correct handling of child thread exits.
+
+#include <pthread.h>
+#include <atomic>
+
+// Note that although hogging the CPU while waiting for a variable to change
+// would be terrible in production code, it's great for testing since it
+// avoids a lot of messy context switching to get multiple threads synchronized.
+#define do_nothing()
+
+#define pseudo_barrier_wait(bar) \
+    --bar;                       \
+    while (bar > 0)              \
+        do_nothing();
+
+#define pseudo_barrier_init(bar, count) (bar = count)
+
+std::atomic_int g_barrier1;
+std::atomic_int g_barrier2;
+std::atomic_int g_barrier3;
+
+void *
+thread1 (void *input)
+{
+    // Synchronize with the main thread.
+    pseudo_barrier_wait(g_barrier1);
+
+    // Synchronize with the main thread and thread2.
+    pseudo_barrier_wait(g_barrier2);
+
+    // Return
+    return NULL;                                      // Set second breakpoint here
+}
+
+void *
+thread2 (void *input)
+{
+    // Synchronize with thread1 and the main thread.
+    pseudo_barrier_wait(g_barrier2);
+
+    // Synchronize with the main thread.
+    pseudo_barrier_wait(g_barrier3);
+
+    // Return
+    return NULL;
+}
+
+int main ()
+{
+    pthread_t thread_1;
+    pthread_t thread_2;
+    pthread_t thread_3;
+
+    pseudo_barrier_init(g_barrier1, 2);
+    pseudo_barrier_init(g_barrier2, 3);
+    pseudo_barrier_init(g_barrier3, 2);
+
+    // Create a thread.
+    pthread_create (&thread_1, NULL, thread1, NULL);
+
+    // Wait for thread1 to start.
+    pseudo_barrier_wait(g_barrier1);
+
+    // Create another thread.
+    pthread_create (&thread_2, NULL, thread2, NULL);  // Set first breakpoint here
+
+    // Wait for thread2 to start.
+    pseudo_barrier_wait(g_barrier2);
+
+    // Wait for the first thread to finish
+    pthread_join(thread_1, NULL);
+
+    // Synchronize with the remaining thread
+    pseudo_barrier_wait(g_barrier3);                  // Set third breakpoint here
+
+    // Wait for the second thread to finish
+    pthread_join(thread_2, NULL);
+
+    return 0;                                         // Set fourth breakpoint here
+}

Modified: lldb/trunk/test/lldbtest.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lldbtest.py?rev=182809&r1=182808&r2=182809&view=diff
==============================================================================
--- lldb/trunk/test/lldbtest.py (original)
+++ lldb/trunk/test/lldbtest.py Tue May 28 18:04:25 2013
@@ -1251,6 +1251,29 @@ class Base(unittest2.TestCase):
         if not module.buildDwarf(self, architecture, compiler, dictionary, clean):
             raise Exception("Don't know how to build binary with dwarf")
 
+    def getBuildFlags(self, use_cpp11=True, use_pthreads=True):
+        """ Returns a dictionary (which can be provided to build* functions above) which
+            contains OS-specific build flags.
+        """
+        cflags = ""
+        if use_cpp11:
+            cflags += "-std="
+            if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion():
+                cflags += "c++0x"
+            else:
+                cflags += "c++11"
+        if sys.platform.startswith("darwin"):
+            cflags += " -stdlib=libc++"
+        elif "clang" in self.getCompiler():
+            cflags += " -stdlib=libstdc++"
+
+        if use_pthreads:
+            ldflags = "-lpthread"
+
+        return {'CFLAGS_EXTRAS' : cflags,
+                'LD_EXTRAS' : ldflags,
+               }
+
     def cleanup(self, dictionary=None):
         """Platform specific way to do cleanup after build."""
         if lldb.skip_build_and_cleanup:





More information about the lldb-commits mailing list