[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