summaryrefslogtreecommitdiffstats
path: root/packages/Python/lldbsuite/test/functionalities/thread
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2016-01-06 20:12:03 +0000
committerdim <dim@FreeBSD.org>2016-01-06 20:12:03 +0000
commit78b9749c0a4ea980a8b934645da6ae98fcc665e8 (patch)
treedd2a1ddf0476664c2b823409c36cbccd52662ca7 /packages/Python/lldbsuite/test/functionalities/thread
parent60cb593f9d55fa5ca7a5372b731f2330345b4b9a (diff)
downloadFreeBSD-src-78b9749c0a4ea980a8b934645da6ae98fcc665e8.zip
FreeBSD-src-78b9749c0a4ea980a8b934645da6ae98fcc665e8.tar.gz
Vendor import of lldb trunk r256945:
https://llvm.org/svn/llvm-project/lldb/trunk@256945
Diffstat (limited to 'packages/Python/lldbsuite/test/functionalities/thread')
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/TestNumThreads.py53
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/Makefile6
-rwxr-xr-xpackages/Python/lldbsuite/test/functionalities/thread/backtrace_all/ParallelTask.cpp151
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/TestBacktraceAll.py57
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/break_after_join/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/break_after_join/TestBreakAfterJoin.py77
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/break_after_join/main.cpp118
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/Makefile7
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py491
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/main.cpp200
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/Makefile4
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/TestCrashDuringStep.py53
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/main.cpp16
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/TestCreateAfterAttach.py122
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/main.cpp78
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/create_during_step/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/create_during_step/TestCreateDuringStep.py127
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/create_during_step/main.cpp89
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/TestExitDuringBreak.py81
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/main.cpp130
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/TestExitDuringStep.py144
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/main.cpp87
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/jump/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/jump/TestThreadJump.py60
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/jump/main.cpp35
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/jump/other.cpp13
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/main.cpp50
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/multi_break/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/multi_break/TestMultipleBreakpoints.py77
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/multi_break/main.cpp61
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/state/Makefile4
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/state/TestThreadStates.py333
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/state/main.cpp45
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/step_out/Makefile6
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/step_out/TestThreadStepOut.py131
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/step_out/main.cpp63
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/thread_exit/Makefile5
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/thread_exit/TestThreadExit.py116
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/thread_exit/main.cpp85
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/Makefile6
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/TestThreadSpecificBreakpoint.py63
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/main.cpp20
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/Makefile6
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/TestThreadSpecificBpPlusCondition.py65
-rw-r--r--packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/main.cpp39
49 files changed, 3414 insertions, 0 deletions
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/Makefile
new file mode 100644
index 0000000..644e297
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../make
+
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/TestNumThreads.py b/packages/Python/lldbsuite/test/functionalities/thread/TestNumThreads.py
new file mode 100644
index 0000000..8184ddc
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/TestNumThreads.py
@@ -0,0 +1,53 @@
+"""
+Test number of threads.
+"""
+
+from __future__ import print_function
+
+
+
+import os, time
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class NumberOfThreadsTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+ # Find the line number to break inside main().
+ self.line = line_number('main.cpp', '// Set break point at this line.')
+
+ def test(self):
+ """Test number of threads."""
+ self.build()
+ 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.line, num_expected_locations=1)
+
+ # The breakpoint list should show 3 locations.
+ self.expect("breakpoint list -f", "Breakpoint location shown correctly",
+ substrs = ["1: file = 'main.cpp', line = %d, exact_match = 0, locations = 1" % self.line])
+
+ # Run the program.
+ self.runCmd("run", RUN_SUCCEEDED)
+
+ # Stopped once.
+ self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+ substrs = ["stop reason = breakpoint 1."])
+
+ # Get the target process
+ target = self.dbg.GetSelectedTarget()
+ process = target.GetProcess()
+
+ # Get the number of threads
+ num_threads = process.GetNumThreads()
+
+ # Using std::thread may involve extra threads, so we assert that there are
+ # at least 4 rather than exactly 4.
+ self.assertTrue(num_threads >= 4, 'Number of expected threads and actual threads do not match.')
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/Makefile
new file mode 100644
index 0000000..24e6801
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/Makefile
@@ -0,0 +1,6 @@
+LEVEL = ../../../make
+
+CXXFLAGS += -std=c++11
+CXX_SOURCES := ParallelTask.cpp
+ENABLE_THREADS := YES
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/ParallelTask.cpp b/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/ParallelTask.cpp
new file mode 100755
index 0000000..71fb8e3
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/ParallelTask.cpp
@@ -0,0 +1,151 @@
+#include <cstdint>
+#include <thread>
+#include <vector>
+#include <queue>
+#include <future>
+#include <iostream>
+#include <cassert>
+
+class TaskPoolImpl
+{
+public:
+ TaskPoolImpl(uint32_t num_threads) :
+ m_stop(false)
+ {
+ for (uint32_t i = 0; i < num_threads; ++i)
+ m_threads.emplace_back(Worker, this);
+ }
+
+ ~TaskPoolImpl()
+ {
+ Stop();
+ }
+
+ template<typename F, typename... Args>
+ std::future<typename std::result_of<F(Args...)>::type>
+ AddTask(F&& f, Args&&... args)
+ {
+ auto task = std::make_shared<std::packaged_task<typename std::result_of<F(Args...)>::type()>>(
+ std::bind(std::forward<F>(f), std::forward<Args>(args)...));
+
+ std::unique_lock<std::mutex> lock(m_tasks_mutex);
+ assert(!m_stop && "Can't add task to TaskPool after it is stopped");
+ m_tasks.emplace([task](){ (*task)(); });
+ lock.unlock();
+ m_tasks_cv.notify_one();
+
+ return task->get_future();
+ }
+
+ void
+ Stop()
+ {
+ std::unique_lock<std::mutex> lock(m_tasks_mutex);
+ m_stop = true;
+ m_tasks_mutex.unlock();
+ m_tasks_cv.notify_all();
+ for (auto& t : m_threads)
+ t.join();
+ }
+
+private:
+ static void
+ Worker(TaskPoolImpl* pool)
+ {
+ while (true)
+ {
+ std::unique_lock<std::mutex> lock(pool->m_tasks_mutex);
+ if (pool->m_tasks.empty())
+ pool->m_tasks_cv.wait(lock, [pool](){ return !pool->m_tasks.empty() || pool->m_stop; });
+ if (pool->m_tasks.empty())
+ break;
+
+ std::function<void()> f = pool->m_tasks.front();
+ pool->m_tasks.pop();
+ lock.unlock();
+
+ f();
+ }
+ }
+
+ std::queue<std::function<void()>> m_tasks;
+ std::mutex m_tasks_mutex;
+ std::condition_variable m_tasks_cv;
+ bool m_stop;
+ std::vector<std::thread> m_threads;
+};
+
+class TaskPool
+{
+public:
+ // Add a new task to the thread pool and return a std::future belongs for the newly created task.
+ // The caller of this function have to wait on the future for this task to complete.
+ template<typename F, typename... Args>
+ static std::future<typename std::result_of<F(Args...)>::type>
+ AddTask(F&& f, Args&&... args)
+ {
+ return GetImplementation().AddTask(std::forward<F>(f), std::forward<Args>(args)...);
+ }
+
+ // Run all of the specified tasks on the thread pool and wait until all of them are finished
+ // before returning
+ template<typename... T>
+ static void
+ RunTasks(T&&... t)
+ {
+ RunTaskImpl<T...>::Run(std::forward<T>(t)...);
+ }
+
+private:
+ static TaskPoolImpl&
+ GetImplementation()
+ {
+ static TaskPoolImpl g_task_pool_impl(std::thread::hardware_concurrency());
+ return g_task_pool_impl;
+ }
+
+ template<typename... T>
+ struct RunTaskImpl;
+};
+
+template<typename H, typename... T>
+struct TaskPool::RunTaskImpl<H, T...>
+{
+ static void
+ Run(H&& h, T&&... t)
+ {
+ auto f = AddTask(std::forward<H>(h));
+ RunTaskImpl<T...>::Run(std::forward<T>(t)...);
+ f.wait();
+ }
+};
+
+template<>
+struct TaskPool::RunTaskImpl<>
+{
+ static void
+ Run() {}
+};
+
+int main()
+{
+ std::vector<std::future<uint32_t>> tasks;
+ for (int i = 0; i < 100000; ++i)
+ {
+ tasks.emplace_back(TaskPool::AddTask([](int i){
+ uint32_t s = 0;
+ for (int j = 0; j <= i; ++j)
+ s += j;
+ return s;
+ },
+ i));
+ }
+
+ for (auto& it : tasks) // Set breakpoint here
+ it.wait();
+
+ TaskPool::RunTasks(
+ []() { return 1; },
+ []() { return "aaaa"; }
+ );
+}
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/TestBacktraceAll.py b/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/TestBacktraceAll.py
new file mode 100644
index 0000000..91bc685
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/TestBacktraceAll.py
@@ -0,0 +1,57 @@
+"""
+Test regression for Bug 25251.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class BreakpointAfterJoinTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+ # Find the line number for our breakpoint.
+ self.breakpoint = line_number('ParallelTask.cpp', '// Set breakpoint here')
+
+ @skipIfTargetAndroid(archs=["arm"]) # The android-arm compiler can't compile the inferior
+ # because of an issue around std::future.
+ # TODO: Change the test to don't depend on std::future<T>
+ def test(self):
+ """Test breakpoint handling after a thread join."""
+ self.build(dictionary=self.getBuildFlags())
+
+ exe = os.path.join(os.getcwd(), "a.out")
+ self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+ # This should create a breakpoint
+ lldbutil.run_break_set_by_file_and_line (self, "ParallelTask.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 = 'ParallelTask.cpp', line = %d, exact_match = 0" % 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'])
+
+ # This should not result in a segmentation fault
+ self.expect("thread backtrace all", STOPPED_DUE_TO_BREAKPOINT,
+ substrs = ["stop reason = breakpoint 1."])
+
+ # Run to completion
+ self.runCmd("continue")
+
+if __name__ == '__main__':
+ import atexit
+ lldb.SBDebugger.Initialize()
+ atexit.register(lambda: lldb.SBDebugger.Terminate())
+ unittest2.main()
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/break_after_join/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/break_after_join/Makefile
new file mode 100644
index 0000000..67aa166
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/break_after_join/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/break_after_join/TestBreakAfterJoin.py b/packages/Python/lldbsuite/test/functionalities/thread/break_after_join/TestBreakAfterJoin.py
new file mode 100644
index 0000000..43397a1
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/break_after_join/TestBreakAfterJoin.py
@@ -0,0 +1,77 @@
+"""
+Test number of threads.
+"""
+
+from __future__ import print_function
+
+
+
+import os, time
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class BreakpointAfterJoinTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ 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')
+
+ @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+ @expectedFailureFreeBSD("llvm.org/pr18190") # thread states not properly maintained
+ @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained
+ def test(self):
+ """Test breakpoint handling after a thread join."""
+ self.build(dictionary=self.getBuildFlags())
+
+ 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, exact_match = 0, 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 occurred 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 six threads
+ self.assertTrue(num_threads >= 6, 'Number of expected threads and actual threads do not match.')
+
+ # Make sure all threads are stopped
+ for i in range(0, num_threads):
+ self.assertTrue(process.GetThreadAtIndex(i).IsStopped(),
+ "Thread {0} didn't stop during breakpoint.".format(i))
+
+ # 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)
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/break_after_join/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/break_after_join/main.cpp
new file mode 100644
index 0000000..a630795
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/break_after_join/main.cpp
@@ -0,0 +1,118 @@
+//===-- 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 <atomic>
+#include <chrono>
+#include <thread>
+
+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 ()
+{
+ // Wait until all the threads are running
+ pseudo_barrier_wait(g_barrier1);
+
+ // Wait for the join thread to join
+ std::this_thread::sleep_for(std::chrono::microseconds(50));
+
+ // Do something
+ g_test++; // Set breakpoint here
+
+ // Synchronize after the breakpoint
+ pseudo_barrier_wait(g_barrier2);
+
+ // Return
+ return NULL;
+}
+
+void *
+wait_thread_func ()
+{
+ // 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)
+{
+ std::thread *thread_to_join = (std::thread *)input;
+
+ // Sync up with the rest of the threads.
+ pseudo_barrier_wait(g_barrier1);
+
+ // Join the other thread
+ thread_to_join->join();
+
+ // Return
+ return NULL;
+}
+
+int main ()
+{
+ // 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
+ std::thread thread_1(break_thread_func);
+
+ // Create more threads to slow the debugger down during processing.
+ std::thread thread_2(wait_thread_func);
+ std::thread thread_3(wait_thread_func);
+ std::thread thread_4(wait_thread_func);
+
+ // Create a thread to join the breakpoint thread
+ std::thread thread_5(join_thread_func, &thread_1);
+
+ // Wait for the threads to finish
+ thread_5.join(); // implies thread_1 is already finished
+ thread_4.join();
+ thread_3.join();
+ thread_2.join();
+
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/Makefile
new file mode 100644
index 0000000..469c080
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/Makefile
@@ -0,0 +1,7 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+ENABLE_THREADS := YES
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py b/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py
new file mode 100644
index 0000000..9eb25b6
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py
@@ -0,0 +1,491 @@
+"""
+A stress-test of sorts for LLDB's handling of threads in the inferior.
+
+This test sets a breakpoint in the main thread where test parameters (numbers of
+threads) can be adjusted, runs the inferior to that point, and modifies the
+locals that control the event thread counts. This test also sets a breakpoint in
+breakpoint_func (the function executed by each 'breakpoint' thread) and a
+watchpoint on a global modified in watchpoint_func. The inferior is continued
+until exit or a crash takes place, and the number of events seen by LLDB is
+verified to match the expected number of events.
+"""
+
+from __future__ import print_function
+
+
+
+import unittest2
+import os, time
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+@skipIfWindows
+@expectedFailureAll(archs=['mips64', 'mips64el']) # Atomic sequences are not supported yet for MIPS in LLDB.
+class ConcurrentEventsTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ #
+ ## Tests for multiple threads that generate a single event.
+ #
+ @unittest2.skipIf(TestBase.skipLongRunningTest(), "Skip this long running test")
+ def test_many_breakpoints(self):
+ """Test 100 breakpoints from 100 threads."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_breakpoint_threads=100)
+
+ @unittest2.skipIf(TestBase.skipLongRunningTest(), "Skip this long running test")
+ def test_many_watchpoints(self):
+ """Test 100 watchpoints from 100 threads."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_watchpoint_threads=100)
+
+ @unittest2.skipIf(TestBase.skipLongRunningTest(), "Skip this long running test")
+ def test_many_signals(self):
+ """Test 100 signals from 100 threads."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_signal_threads=100)
+
+ @unittest2.skipIf(TestBase.skipLongRunningTest(), "Skip this long running test")
+ def test_many_crash(self):
+ """Test 100 threads that cause a segfault."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_crash_threads=100)
+
+
+ #
+ ## Tests for concurrent signal and breakpoint
+ #
+ @skipIfFreeBSD # timing out on buildbot
+ def test_signal_break(self):
+ """Test signal and a breakpoint in multiple threads."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_breakpoint_threads=1, num_signal_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ def test_delay_signal_break(self):
+ """Test (1-second delay) signal and a breakpoint in multiple threads."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_breakpoint_threads=1, num_delay_signal_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ def test_signal_delay_break(self):
+ """Test signal and a (1 second delay) breakpoint in multiple threads."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_delay_breakpoint_threads=1, num_signal_threads=1)
+
+
+ #
+ ## Tests for concurrent watchpoint and breakpoint
+ #
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_watch_break(self):
+ """Test watchpoint and a breakpoint in multiple threads."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_breakpoint_threads=1, num_watchpoint_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_delay_watch_break(self):
+ """Test (1-second delay) watchpoint and a breakpoint in multiple threads."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_breakpoint_threads=1, num_delay_watchpoint_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_watch_break_delay(self):
+ """Test watchpoint and a (1 second delay) breakpoint in multiple threads."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_delay_breakpoint_threads=1, num_watchpoint_threads=1)
+
+ #
+ ## Tests for concurrent signal and watchpoint
+ #
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_signal_watch(self):
+ """Test a watchpoint and a signal in multiple threads."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_signal_threads=1, num_watchpoint_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_delay_signal_watch(self):
+ """Test a watchpoint and a (1 second delay) signal in multiple threads."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_delay_signal_threads=1, num_watchpoint_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ @expectedFailureAll("llvm.org/pr16714", oslist=["linux"], archs=["i386"])
+ def test_signal_delay_watch(self):
+ """Test a (1 second delay) watchpoint and a signal in multiple threads."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_signal_threads=1, num_delay_watchpoint_threads=1)
+
+
+ #
+ ## Tests for multiple breakpoint threads
+ #
+ @skipIfFreeBSD # timing out on buildbot
+ def test_two_breakpoint_threads(self):
+ """Test two threads that trigger a breakpoint. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_breakpoint_threads=2)
+
+ @skipIfFreeBSD # timing out on buildbot
+ def test_breakpoint_one_delay_breakpoint_threads(self):
+ """Test threads that trigger a breakpoint where one thread has a 1 second delay. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_breakpoint_threads=1,
+ num_delay_breakpoint_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ def test_two_breakpoints_one_signal(self):
+ """Test two threads that trigger a breakpoint and one signal thread. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_breakpoint_threads=2, num_signal_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ def test_breakpoint_delay_breakpoint_one_signal(self):
+ """Test two threads that trigger a breakpoint (one with a 1 second delay) and one signal thread. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_breakpoint_threads=1,
+ num_delay_breakpoint_threads=1,
+ num_signal_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ def test_two_breakpoints_one_delay_signal(self):
+ """Test two threads that trigger a breakpoint and one (1 second delay) signal thread. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_breakpoint_threads=2, num_delay_signal_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_two_breakpoints_one_watchpoint(self):
+ """Test two threads that trigger a breakpoint and one watchpoint thread. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_breakpoint_threads=2, num_watchpoint_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_breakpoints_delayed_breakpoint_one_watchpoint(self):
+ """Test a breakpoint, a delayed breakpoint, and one watchpoint thread. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_breakpoint_threads=1,
+ num_delay_breakpoint_threads=1,
+ num_watchpoint_threads=1)
+
+ #
+ ## Tests for multiple watchpoint threads
+ #
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_two_watchpoint_threads(self):
+ """Test two threads that trigger a watchpoint. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_watchpoint_threads=2)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_watchpoint_with_delay_watchpoint_threads(self):
+ """Test two threads that trigger a watchpoint where one thread has a 1 second delay. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_watchpoint_threads=1,
+ num_delay_watchpoint_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_two_watchpoints_one_breakpoint(self):
+ """Test two threads that trigger a watchpoint and one breakpoint thread. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_watchpoint_threads=2, num_breakpoint_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_two_watchpoints_one_delay_breakpoint(self):
+ """Test two threads that trigger a watchpoint and one (1 second delay) breakpoint thread. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_watchpoint_threads=2, num_delay_breakpoint_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_watchpoint_delay_watchpoint_one_breakpoint(self):
+ """Test two threads that trigger a watchpoint (one with a 1 second delay) and one breakpoint thread. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_watchpoint_threads=1,
+ num_delay_watchpoint_threads=1,
+ num_breakpoint_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_two_watchpoints_one_signal(self):
+ """Test two threads that trigger a watchpoint and one signal thread. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_watchpoint_threads=2, num_signal_threads=1)
+
+ #
+ ## Test for watchpoint, signal and breakpoint happening concurrently
+ #
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_signal_watch_break(self):
+ """Test a signal/watchpoint/breakpoint in multiple threads."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_signal_threads=1,
+ num_watchpoint_threads=1,
+ num_breakpoint_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_signal_watch_break(self):
+ """Test one signal thread with 5 watchpoint and breakpoint threads."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_signal_threads=1,
+ num_watchpoint_threads=5,
+ num_breakpoint_threads=5)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_signal_watch_break(self):
+ """Test with 5 watchpoint and breakpoint threads."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_watchpoint_threads=5,
+ num_breakpoint_threads=5)
+
+
+ #
+ ## Test for crashing threads happening concurrently with other events
+ #
+ @skipIfFreeBSD # timing out on buildbot
+ def test_crash_with_break(self):
+ """ Test a thread that crashes while another thread hits a breakpoint."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_crash_threads=1, num_breakpoint_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_crash_with_watchpoint(self):
+ """ Test a thread that crashes while another thread hits a watchpoint."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_crash_threads=1, num_watchpoint_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ def test_crash_with_signal(self):
+ """ Test a thread that crashes while another thread generates a signal."""
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_crash_threads=1, num_signal_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_crash_with_watchpoint_breakpoint_signal(self):
+ """ Test a thread that crashes while other threads generate a signal and hit a watchpoint and breakpoint. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_crash_threads=1,
+ num_breakpoint_threads=1,
+ num_signal_threads=1,
+ num_watchpoint_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ @skipIfRemoteDueToDeadlock
+ def test_delayed_crash_with_breakpoint_watchpoint(self):
+ """ Test a thread with a delayed crash while other threads hit a watchpoint and a breakpoint. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_delay_crash_threads=1,
+ num_breakpoint_threads=1,
+ num_watchpoint_threads=1)
+
+ @skipIfFreeBSD # timing out on buildbot
+ def test_delayed_crash_with_breakpoint_signal(self):
+ """ Test a thread with a delayed crash while other threads generate a signal and hit a breakpoint. """
+ self.build(dictionary=self.getBuildFlags())
+ self.do_thread_actions(num_delay_crash_threads=1,
+ num_breakpoint_threads=1,
+ num_signal_threads=1)
+
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+ # Find the line number for our breakpoint.
+ self.filename = 'main.cpp'
+ self.thread_breakpoint_line = line_number(self.filename, '// Set breakpoint here')
+ self.setup_breakpoint_line = line_number(self.filename, '// Break here and adjust num')
+ self.finish_breakpoint_line = line_number(self.filename, '// Break here and verify one thread is active')
+
+ def describe_threads(self):
+ ret = []
+ for x in self.inferior_process:
+ id = x.GetIndexID()
+ reason = x.GetStopReason()
+ status = "stopped" if x.IsStopped() else "running"
+ reason_str = lldbutil.stop_reason_to_str(reason)
+ if reason == lldb.eStopReasonBreakpoint:
+ bpid = x.GetStopReasonDataAtIndex(0)
+ bp = self.inferior_target.FindBreakpointByID(bpid)
+ reason_str = "%s hit %d times" % (lldbutil.get_description(bp), bp.GetHitCount())
+ elif reason == lldb.eStopReasonWatchpoint:
+ watchid = x.GetStopReasonDataAtIndex(0)
+ watch = self.inferior_target.FindWatchpointByID(watchid)
+ reason_str = "%s hit %d times" % (lldbutil.get_description(watch), watch.GetHitCount())
+ elif reason == lldb.eStopReasonSignal:
+ signals = self.inferior_process.GetUnixSignals()
+ signal_name = signals.GetSignalAsCString(x.GetStopReasonDataAtIndex(0))
+ reason_str = "signal %s" % signal_name
+
+ location = "\t".join([lldbutil.get_description(x.GetFrameAtIndex(i)) for i in range(x.GetNumFrames())])
+ ret.append("thread %d %s due to %s at\n\t%s" % (id, status, reason_str, location))
+ return ret
+
+ def add_breakpoint(self, line, descriptions):
+ """ Adds a breakpoint at self.filename:line and appends its description to descriptions, and
+ returns the LLDB SBBreakpoint object.
+ """
+
+ bpno = lldbutil.run_break_set_by_file_and_line(self, self.filename, line, num_expected_locations=-1)
+ bp = self.inferior_target.FindBreakpointByID(bpno)
+ descriptions.append(": file = 'main.cpp', line = %d" % self.finish_breakpoint_line)
+ return bp
+
+ def inferior_done(self):
+ """ Returns true if the inferior is done executing all the event threads (and is stopped at self.finish_breakpoint,
+ or has terminated execution.
+ """
+ return self.finish_breakpoint.GetHitCount() > 0 or \
+ self.crash_count > 0 or \
+ self.inferior_process.GetState() == lldb.eStateExited
+
+ def count_signaled_threads(self):
+ count = 0
+ for thread in self.inferior_process:
+ if thread.GetStopReason() == lldb.eStopReasonSignal and thread.GetStopReasonDataAtIndex(0) == self.inferior_process.GetUnixSignals().GetSignalNumberFromName('SIGUSR1'):
+ count += 1
+ return count
+
+ def do_thread_actions(self,
+ num_breakpoint_threads = 0,
+ num_signal_threads = 0,
+ num_watchpoint_threads = 0,
+ num_crash_threads = 0,
+ num_delay_breakpoint_threads = 0,
+ num_delay_signal_threads = 0,
+ num_delay_watchpoint_threads = 0,
+ num_delay_crash_threads = 0):
+ """ Sets a breakpoint in the main thread where test parameters (numbers of threads) can be adjusted, runs the inferior
+ to that point, and modifies the locals that control the event thread counts. Also sets a breakpoint in
+ breakpoint_func (the function executed by each 'breakpoint' thread) and a watchpoint on a global modified in
+ watchpoint_func. The inferior is continued until exit or a crash takes place, and the number of events seen by LLDB
+ is verified to match the expected number of events.
+ """
+ exe = os.path.join(os.getcwd(), "a.out")
+ self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+ # Get the target
+ self.inferior_target = self.dbg.GetSelectedTarget()
+
+ expected_bps = []
+
+ # Initialize all the breakpoints (main thread/aux thread)
+ self.setup_breakpoint = self.add_breakpoint(self.setup_breakpoint_line, expected_bps)
+ self.finish_breakpoint = self.add_breakpoint(self.finish_breakpoint_line, expected_bps)
+
+ # Set the thread breakpoint
+ if num_breakpoint_threads + num_delay_breakpoint_threads > 0:
+ self.thread_breakpoint = self.add_breakpoint(self.thread_breakpoint_line, expected_bps)
+
+ # Verify breakpoints
+ self.expect("breakpoint list -f", "Breakpoint locations shown correctly", substrs = expected_bps)
+
+ # Run the program.
+ self.runCmd("run", RUN_SUCCEEDED)
+
+ # Check we are at line self.setup_breakpoint
+ self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
+ substrs = ["stop reason = breakpoint 1."])
+
+ # Initialize the (single) watchpoint on the global variable (g_watchme)
+ if num_watchpoint_threads + num_delay_watchpoint_threads > 0:
+ self.runCmd("watchpoint set variable g_watchme")
+ for w in self.inferior_target.watchpoint_iter():
+ self.thread_watchpoint = w
+ self.assertTrue("g_watchme" in str(self.thread_watchpoint), "Watchpoint location not shown correctly")
+
+ # Get the process
+ self.inferior_process = self.inferior_target.GetProcess()
+
+ # We should be stopped at the setup site where we can set the number of
+ # threads doing each action (break/crash/signal/watch)
+ self.assertEqual(self.inferior_process.GetNumThreads(), 1, 'Expected to stop before any additional threads are spawned.')
+
+ self.runCmd("expr num_breakpoint_threads=%d" % num_breakpoint_threads)
+ self.runCmd("expr num_crash_threads=%d" % num_crash_threads)
+ self.runCmd("expr num_signal_threads=%d" % num_signal_threads)
+ self.runCmd("expr num_watchpoint_threads=%d" % num_watchpoint_threads)
+
+ self.runCmd("expr num_delay_breakpoint_threads=%d" % num_delay_breakpoint_threads)
+ self.runCmd("expr num_delay_crash_threads=%d" % num_delay_crash_threads)
+ self.runCmd("expr num_delay_signal_threads=%d" % num_delay_signal_threads)
+ self.runCmd("expr num_delay_watchpoint_threads=%d" % num_delay_watchpoint_threads)
+
+ # Continue the inferior so threads are spawned
+ self.runCmd("continue")
+
+ # Make sure we see all the threads. The inferior program's threads all synchronize with a pseudo-barrier; that is,
+ # the inferior program ensures all threads are started and running before any thread triggers its 'event'.
+ num_threads = self.inferior_process.GetNumThreads()
+ expected_num_threads = num_breakpoint_threads + num_delay_breakpoint_threads \
+ + num_signal_threads + num_delay_signal_threads \
+ + num_watchpoint_threads + num_delay_watchpoint_threads \
+ + num_crash_threads + num_delay_crash_threads + 1
+ self.assertEqual(num_threads, expected_num_threads,
+ 'Expected to see %d threads, but seeing %d. Details:\n%s' % (expected_num_threads,
+ num_threads,
+ "\n\t".join(self.describe_threads())))
+
+ self.signal_count = self.count_signaled_threads()
+ self.crash_count = len(lldbutil.get_crashed_threads(self, self.inferior_process))
+
+ # Run to completion (or crash)
+ while not self.inferior_done():
+ if self.TraceOn():
+ self.runCmd("thread backtrace all")
+ self.runCmd("continue")
+ self.signal_count += self.count_signaled_threads()
+ self.crash_count += len(lldbutil.get_crashed_threads(self, self.inferior_process))
+
+ if num_crash_threads > 0 or num_delay_crash_threads > 0:
+ # Expecting a crash
+ self.assertTrue(self.crash_count > 0,
+ "Expecting at least one thread to crash. Details: %s" % "\t\n".join(self.describe_threads()))
+
+ # Ensure the zombie process is reaped
+ self.runCmd("process kill")
+
+ elif num_crash_threads == 0 and num_delay_crash_threads == 0:
+ # There should be a single active thread (the main one) which hit the breakpoint after joining
+ self.assertEqual(1, self.finish_breakpoint.GetHitCount(), "Expected main thread (finish) breakpoint to be hit once")
+
+ num_threads = self.inferior_process.GetNumThreads()
+ self.assertEqual(1, num_threads, "Expecting 1 thread but seeing %d. Details:%s" % (num_threads,
+ "\n\t".join(self.describe_threads())))
+ self.runCmd("continue")
+
+ # The inferior process should have exited without crashing
+ self.assertEqual(0, self.crash_count, "Unexpected thread(s) in crashed state")
+ self.assertEqual(self.inferior_process.GetState(), lldb.eStateExited, PROCESS_EXITED)
+
+ # Verify the number of actions took place matches expected numbers
+ expected_breakpoint_threads = num_delay_breakpoint_threads + num_breakpoint_threads
+ breakpoint_hit_count = self.thread_breakpoint.GetHitCount() if expected_breakpoint_threads > 0 else 0
+ self.assertEqual(expected_breakpoint_threads, breakpoint_hit_count,
+ "Expected %d breakpoint hits, but got %d" % (expected_breakpoint_threads, breakpoint_hit_count))
+
+ expected_signal_threads = num_delay_signal_threads + num_signal_threads
+ self.assertEqual(expected_signal_threads, self.signal_count,
+ "Expected %d stops due to signal delivery, but got %d" % (expected_signal_threads, self.signal_count))
+
+ expected_watchpoint_threads = num_delay_watchpoint_threads + num_watchpoint_threads
+ watchpoint_hit_count = self.thread_watchpoint.GetHitCount() if expected_watchpoint_threads > 0 else 0
+ self.assertEqual(expected_watchpoint_threads, watchpoint_hit_count,
+ "Expected %d watchpoint hits, got %d" % (expected_watchpoint_threads, watchpoint_hit_count))
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/main.cpp
new file mode 100644
index 0000000..ac2535c
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/main.cpp
@@ -0,0 +1,200 @@
+//===-- 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 multiple events
+// (breakpoints, watchpoints, crashes, and signal generation/delivery) happen
+// from multiple threads. The test expects the debugger to set a breakpoint on
+// the main thread (before any worker threads are spawned) and modify variables
+// which control the number of threads that are spawned for each action.
+
+#include <atomic>
+#include <vector>
+using namespace std;
+
+#include <pthread.h>
+
+#include <signal.h>
+#include <sys/types.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)
+
+typedef std::vector<std::pair<unsigned, void*(*)(void*)> > action_counts;
+typedef std::vector<pthread_t> thread_vector;
+
+std::atomic_int g_barrier;
+int g_breakpoint = 0;
+int g_sigusr1_count = 0;
+std::atomic_int g_watchme;
+
+struct action_args {
+ int delay;
+};
+
+// Perform any extra actions required by thread 'input' arg
+void do_action_args(void *input) {
+ if (input) {
+ action_args *args = static_cast<action_args*>(input);
+ sleep(args->delay);
+ }
+}
+
+void *
+breakpoint_func (void *input)
+{
+ // Wait until all threads are running
+ pseudo_barrier_wait(g_barrier);
+ do_action_args(input);
+
+ // Do something
+ g_breakpoint++; // Set breakpoint here
+ return 0;
+}
+
+void *
+signal_func (void *input) {
+ // Wait until all threads are running
+ pseudo_barrier_wait(g_barrier);
+ do_action_args(input);
+
+ // Send a user-defined signal to the current process
+ //kill(getpid(), SIGUSR1);
+ // Send a user-defined signal to the current thread
+ pthread_kill(pthread_self(), SIGUSR1);
+
+ return 0;
+}
+
+void *
+watchpoint_func (void *input) {
+ pseudo_barrier_wait(g_barrier);
+ do_action_args(input);
+
+ g_watchme += 1; // watchpoint triggers here
+ return 0;
+}
+
+void *
+crash_func (void *input) {
+ pseudo_barrier_wait(g_barrier);
+ do_action_args(input);
+
+ int *a = 0;
+ *a = 5; // crash happens here
+ return 0;
+}
+
+void sigusr1_handler(int sig) {
+ if (sig == SIGUSR1)
+ g_sigusr1_count += 1; // Break here in signal handler
+}
+
+/// Register a simple function for to handle signal
+void register_signal_handler(int signal, void (*handler)(int))
+{
+ sigset_t empty_sigset;
+ sigemptyset(&empty_sigset);
+
+ struct sigaction action;
+ action.sa_sigaction = 0;
+ action.sa_mask = empty_sigset;
+ action.sa_flags = 0;
+ action.sa_handler = handler;
+ sigaction(SIGUSR1, &action, 0);
+}
+
+void start_threads(thread_vector& threads,
+ action_counts& actions,
+ void* args = 0) {
+ action_counts::iterator b = actions.begin(), e = actions.end();
+ for(action_counts::iterator i = b; i != e; ++i) {
+ for(unsigned count = 0; count < i->first; ++count) {
+ pthread_t t;
+ pthread_create(&t, 0, i->second, args);
+ threads.push_back(t);
+ }
+ }
+}
+
+int dotest()
+{
+ g_watchme = 0;
+
+ // Actions are triggered immediately after the thread is spawned
+ unsigned num_breakpoint_threads = 1;
+ unsigned num_watchpoint_threads = 0;
+ unsigned num_signal_threads = 1;
+ unsigned num_crash_threads = 0;
+
+ // Actions below are triggered after a 1-second delay
+ unsigned num_delay_breakpoint_threads = 0;
+ unsigned num_delay_watchpoint_threads = 0;
+ unsigned num_delay_signal_threads = 0;
+ unsigned num_delay_crash_threads = 0;
+
+ register_signal_handler(SIGUSR1, sigusr1_handler); // Break here and adjust num_[breakpoint|watchpoint|signal|crash]_threads
+
+ unsigned total_threads = num_breakpoint_threads \
+ + num_watchpoint_threads \
+ + num_signal_threads \
+ + num_crash_threads \
+ + num_delay_breakpoint_threads \
+ + num_delay_watchpoint_threads \
+ + num_delay_signal_threads \
+ + num_delay_crash_threads;
+
+ // Don't let either thread do anything until they're both ready.
+ pseudo_barrier_init(g_barrier, total_threads);
+
+ action_counts actions;
+ actions.push_back(std::make_pair(num_breakpoint_threads, breakpoint_func));
+ actions.push_back(std::make_pair(num_watchpoint_threads, watchpoint_func));
+ actions.push_back(std::make_pair(num_signal_threads, signal_func));
+ actions.push_back(std::make_pair(num_crash_threads, crash_func));
+
+ action_counts delay_actions;
+ delay_actions.push_back(std::make_pair(num_delay_breakpoint_threads, breakpoint_func));
+ delay_actions.push_back(std::make_pair(num_delay_watchpoint_threads, watchpoint_func));
+ delay_actions.push_back(std::make_pair(num_delay_signal_threads, signal_func));
+ delay_actions.push_back(std::make_pair(num_delay_crash_threads, crash_func));
+
+ // Create threads that handle instant actions
+ thread_vector threads;
+ start_threads(threads, actions);
+
+ // Create threads that handle delayed actions
+ action_args delay_arg;
+ delay_arg.delay = 1;
+ start_threads(threads, delay_actions, &delay_arg);
+
+ // Join all threads
+ typedef std::vector<pthread_t>::iterator thread_iterator;
+ for(thread_iterator t = threads.begin(); t != threads.end(); ++t)
+ pthread_join(*t, 0);
+
+ return 0;
+}
+
+int main ()
+{
+ dotest();
+ return 0; // Break here and verify one thread is active.
+}
+
+
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/Makefile
new file mode 100644
index 0000000..26db481
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/Makefile
@@ -0,0 +1,4 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/TestCrashDuringStep.py b/packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/TestCrashDuringStep.py
new file mode 100644
index 0000000..24b5bf0
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/TestCrashDuringStep.py
@@ -0,0 +1,53 @@
+"""
+Test that step-inst over a crash behaves correctly.
+"""
+
+from __future__ import print_function
+
+
+
+import os
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class CreateDuringStepTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def setUp(self):
+ TestBase.setUp(self)
+ self.breakpoint = line_number('main.cpp', '// Set breakpoint here')
+
+ @expectedFailureWindows("llvm.org/pr24778")
+ @expectedFailureAndroid("llvm.org/pr24497", archs=['arm', 'aarch64'])
+ @expectedFailureAll(archs=['mips', 'mipsel', 'mips64', 'mips64el']) # IO error due to breakpoint at invalid address
+ def test_step_inst_with(self):
+ """Test thread creation during step-inst handling."""
+ self.build(dictionary=self.getBuildFlags())
+ exe = os.path.join(os.getcwd(), "a.out")
+
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target and target.IsValid(), "Target is valid")
+
+ self.bp_num = lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.breakpoint, num_expected_locations=1)
+
+ # Run the program.
+ process = target.LaunchSimple(None, None, self.get_process_working_directory())
+ self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID)
+
+ # The stop reason should be breakpoint.
+ self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
+ self.assertEqual(lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint).IsValid(), 1,
+ STOPPED_DUE_TO_BREAKPOINT)
+
+ thread = process.GetThreadAtIndex(0)
+ self.assertTrue(thread and thread.IsValid(), "Thread is valid")
+
+ # Keep stepping until the inferior crashes
+ while process.GetState() == lldb.eStateStopped and not lldbutil.is_thread_crashed(self, thread):
+ thread.StepInstruction(False)
+
+ self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
+ self.assertTrue(lldbutil.is_thread_crashed(self, thread), "Thread has crashed")
+ process.Kill()
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/main.cpp
new file mode 100644
index 0000000..02f3ce3
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/main.cpp
@@ -0,0 +1,16 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+void (*crash)() = nullptr;
+
+int main()
+{
+ crash(); // Set breakpoint here
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/Makefile
new file mode 100644
index 0000000..67aa166
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/TestCreateAfterAttach.py b/packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/TestCreateAfterAttach.py
new file mode 100644
index 0000000..9772543
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/TestCreateAfterAttach.py
@@ -0,0 +1,122 @@
+"""
+Test thread creation after process attach.
+"""
+
+from __future__ import print_function
+
+
+
+import os, time
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class CreateAfterAttachTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfFreeBSD # Hangs. May be the same as Linux issue llvm.org/pr16229 but
+ # not yet investigated. Revisit once required functionality
+ # is implemented for FreeBSD.
+ @skipIfWindows # Occasionally hangs on Windows, may be same as other issues.
+ @skipIfiOSSimulator
+ def test_create_after_attach_with_popen(self):
+ """Test thread creation after process attach."""
+ self.build(dictionary=self.getBuildFlags(use_cpp11=False))
+ self.create_after_attach(use_fork=False)
+
+ @skipIfFreeBSD # Hangs. Revisit once required functionality is implemented
+ # for FreeBSD.
+ @skipIfRemote
+ @skipIfWindows # Windows doesn't have fork.
+ @expectedFlakeyLinux("llvm.org/pr16229") # 1/100 dosep, build 3546, clang-3.5 x84_64
+ @skipIfiOSSimulator
+ def test_create_after_attach_with_fork(self):
+ """Test thread creation after process attach."""
+ self.build(dictionary=self.getBuildFlags(use_cpp11=False))
+ self.create_after_attach(use_fork=True)
+
+ 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')
+
+ def create_after_attach(self, use_fork):
+ """Test thread creation after process attach."""
+
+ exe = os.path.join(os.getcwd(), "a.out")
+
+ # Spawn a new process
+ if use_fork:
+ pid = self.forkSubprocess(exe)
+ else:
+ popen = self.spawnSubprocess(exe)
+ pid = popen.pid
+ self.addTearDownHook(self.cleanupSubprocesses)
+
+ # Attach to the spawned process
+ self.runCmd("process attach -p " + str(pid))
+
+ target = self.dbg.GetSelectedTarget()
+
+ process = target.GetProcess()
+ self.assertTrue(process, PROCESS_IS_VALID)
+
+ # This should create a breakpoint in the main thread.
+ lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.break_1, num_expected_locations=1)
+
+ # This should create a breakpoint in the second child thread.
+ lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.break_2, num_expected_locations=1)
+
+ # This should create a breakpoint in the first child thread.
+ lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.break_3, num_expected_locations=1)
+
+ # Note: With std::thread, we cannot rely on particular thread numbers. Using
+ # std::thread may cause the program to spin up a thread pool (and it does on
+ # Windows), so the thread numbers are non-deterministic.
+
+ # Run to the first breakpoint
+ self.runCmd("continue")
+
+ # The stop reason of the thread should be breakpoint.
+ self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+ substrs = ['stopped',
+ '* thread #',
+ 'main',
+ 'stop reason = breakpoint'])
+
+ # Change a variable to escape the loop
+ self.runCmd("expression main_thread_continue = 1")
+
+ # Run to the second breakpoint
+ self.runCmd("continue")
+
+ # The stop reason of the thread should be breakpoint.
+ self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+ substrs = ['stopped',
+ '* thread #',
+ 'thread_2_func',
+ 'stop reason = breakpoint'])
+
+ # Change a variable to escape the loop
+ self.runCmd("expression child_thread_continue = 1")
+
+ # Run to the third breakpoint
+ self.runCmd("continue")
+
+ # The stop reason of the thread should be breakpoint.
+ # Thread 3 may or may not have already exited.
+ self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+ substrs = ['stopped',
+ '* thread #',
+ 'thread_1_func',
+ 'stop reason = breakpoint'])
+
+ # Run to completion
+ self.runCmd("continue")
+
+ # At this point, the inferior process should have exited.
+ self.assertTrue(process.GetState() == lldb.eStateExited, PROCESS_EXITED)
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/main.cpp
new file mode 100644
index 0000000..8434458
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/main.cpp
@@ -0,0 +1,78 @@
+#include <stdio.h>
+#include <chrono>
+#include <thread>
+
+using std::chrono::microseconds;
+
+#if defined(__linux__)
+#include <sys/prctl.h>
+#endif
+
+volatile int g_thread_2_continuing = 0;
+
+void *
+thread_1_func (void *input)
+{
+ // Waiting to be released by the debugger.
+ while (!g_thread_2_continuing) // Another thread will change this value
+ {
+ std::this_thread::sleep_for(microseconds(1));
+ }
+
+ // Return
+ return NULL; // Set third breakpoint here
+}
+
+void *
+thread_2_func (void *input)
+{
+ // Waiting to be released by the debugger.
+ int child_thread_continue = 0;
+ while (!child_thread_continue) // The debugger will change this value
+ {
+ std::this_thread::sleep_for(microseconds(1)); // Set second breakpoint here
+ }
+
+ // Release thread 1
+ g_thread_2_continuing = 1;
+
+ // Return
+ return NULL;
+}
+
+int main(int argc, char const *argv[])
+{
+#if defined(__linux__)
+ // Immediately enable any ptracer so that we can allow the stub attach
+ // operation to succeed. Some Linux kernels are locked down so that
+ // only an ancestor process can be a ptracer of a process. This disables that
+ // restriction. Without it, attach-related stub tests will fail.
+#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY)
+ int prctl_result;
+
+ // For now we execute on best effort basis. If this fails for
+ // some reason, so be it.
+ prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
+ (void) prctl_result;
+#endif
+#endif
+
+ // Create a new thread
+ std::thread thread_1(thread_1_func, nullptr);
+
+ // Waiting to be attached by the debugger.
+ int main_thread_continue = 0;
+ while (!main_thread_continue) // The debugger will change this value
+ {
+ std::this_thread::sleep_for(microseconds(1)); // Set first breakpoint here
+ }
+
+ // Create another new thread
+ std::thread thread_2(thread_2_func, nullptr);
+
+ // Wait for the threads to finish.
+ thread_1.join();
+ thread_2.join();
+
+ printf("Exiting now\n");
+}
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/create_during_step/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/create_during_step/Makefile
new file mode 100644
index 0000000..67aa166
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/create_during_step/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/create_during_step/TestCreateDuringStep.py b/packages/Python/lldbsuite/test/functionalities/thread/create_during_step/TestCreateDuringStep.py
new file mode 100644
index 0000000..046a865
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/create_during_step/TestCreateDuringStep.py
@@ -0,0 +1,127 @@
+"""
+Test number of threads.
+"""
+
+from __future__ import print_function
+
+
+
+import os, time
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class CreateDuringStepTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+ @expectedFailureFreeBSD("llvm.org/pr18190") # thread states not properly maintained
+ @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained
+ @expectedFailureWindows("llvm.org/pr24668") # Breakpoints not resolved correctly
+ def test_step_inst(self):
+ """Test thread creation during step-inst handling."""
+ self.build(dictionary=self.getBuildFlags())
+ self.create_during_step_base("thread step-inst -m all-threads", 'stop reason = instruction step')
+
+ @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+ @expectedFailureFreeBSD("llvm.org/pr18190") # thread states not properly maintained
+ @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained
+ @expectedFailureWindows("llvm.org/pr24668") # Breakpoints not resolved correctly
+ def test_step_over(self):
+ """Test thread creation during step-over handling."""
+ self.build(dictionary=self.getBuildFlags())
+ self.create_during_step_base("thread step-over -m all-threads", 'stop reason = step over')
+
+ @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+ @expectedFailureFreeBSD("llvm.org/pr18190") # thread states not properly maintained
+ @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained
+ @expectedFailureWindows("llvm.org/pr24668") # Breakpoints not resolved correctly
+ def test_step_in(self):
+ """Test thread creation during step-in handling."""
+ self.build(dictionary=self.getBuildFlags())
+ self.create_during_step_base("thread step-in -m all-threads", 'stop reason = step in')
+
+ 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_base(self, step_cmd, step_stop_reason):
+ """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.
+ self.bp_num = 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")
+
+ # Find the thread that is stopped at the breakpoint
+ stepping_thread = None
+ for thread in process:
+ expected_bp_desc = "breakpoint %s." % self.bp_num
+ if expected_bp_desc in thread.GetStopDescription(100):
+ stepping_thread = thread
+ break
+ self.assertTrue(stepping_thread != None, "unable to find thread stopped at %s" % expected_bp_desc)
+ current_line = self.breakpoint
+ # Keep stepping until we've reached our designated continue point
+ while current_line != self.continuepoint:
+ if stepping_thread != process.GetSelectedThread():
+ process.SetSelectedThread(stepping_thread)
+
+ self.runCmd(step_cmd)
+
+ 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", 'Process state is stopped due to step',
+ substrs = ['stopped',
+ step_stop_reason])
+
+ # Run to completion
+ self.runCmd("process continue")
+
+ # At this point, the inferior process should have exited.
+ self.assertTrue(process.GetState() == lldb.eStateExited, PROCESS_EXITED)
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/create_during_step/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/create_during_step/main.cpp
new file mode 100644
index 0000000..3a00248
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/create_during_step/main.cpp
@@ -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 is intended to create a situation in which one thread will be
+// created while the debugger is stepping in another thread.
+
+#include <atomic>
+#include <thread>
+
+// 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 ()
+{
+ 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)
+{
+ std::thread *step_thread = (std::thread*)input;
+
+ // Wait until the main thread knows this thread is started.
+ pseudo_barrier_wait(g_barrier);
+
+ // Wait until the other thread is done.
+ step_thread->join();
+
+ // Return
+ return NULL;
+}
+
+int main ()
+{
+ // Use a simple count to simulate a barrier.
+ pseudo_barrier_init(g_barrier, 2);
+
+ // Create a thread to hit the breakpoint.
+ std::thread thread_1(step_thread_func);
+
+ // Wait until the step thread is stepping
+ while (g_test < 1)
+ do_nothing();
+
+ // Create a thread to exit while we're stepping.
+ std::thread thread_2(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.
+ thread_2.join();
+ thread_1.join();
+
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/Makefile
new file mode 100644
index 0000000..67aa166
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/TestExitDuringBreak.py b/packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/TestExitDuringBreak.py
new file mode 100644
index 0000000..f999ffe
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/TestExitDuringBreak.py
@@ -0,0 +1,81 @@
+"""
+Test number of threads.
+"""
+
+from __future__ import print_function
+
+
+
+import os, time
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class ExitDuringBreakpointTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ 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')
+
+ @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+ @expectedFailureFreeBSD("llvm.org/pr18190") # thread states not properly maintained
+ @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained
+ @expectedFailureWindows("llvm.org/pr24668") # Breakpoints not resolved correctly
+ def test(self):
+ """Test thread exit during breakpoint handling."""
+ self.build(dictionary=self.getBuildFlags())
+ 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 occurred 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)
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/main.cpp
new file mode 100644
index 0000000..3570637
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/main.cpp
@@ -0,0 +1,130 @@
+//===-- 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 <atomic>
+#include <chrono>
+#include <thread>
+
+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 ()
+{
+ // 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 ()
+{
+ // 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 ()
+{
+ // 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.
+ std::this_thread::sleep_for(std::chrono::microseconds(1));
+
+ // Return
+ return NULL;
+}
+
+int main ()
+{
+
+ // 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
+ std::thread thread_1(break_thread_func);
+
+ // Create more threads to slow the debugger down during processing.
+ std::thread thread_2(wait_thread_func);
+ std::thread thread_3(wait_thread_func);
+ std::thread thread_4(wait_thread_func);
+
+ // Wait for all these threads to get started.
+ pseudo_barrier_wait(g_barrier1);
+
+ // Create a thread to exit during the breakpoint
+ std::thread thread_5(exit_thread_func);
+
+ // Wait for the threads to finish
+ thread_5.join();
+ thread_4.join();
+ thread_3.join();
+ thread_2.join();
+ thread_1.join();
+
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/Makefile
new file mode 100644
index 0000000..d06a7d4
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+ENABLE_THREADS := YES
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/TestExitDuringStep.py b/packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/TestExitDuringStep.py
new file mode 100644
index 0000000..67d1c96
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/TestExitDuringStep.py
@@ -0,0 +1,144 @@
+"""
+Test number of threads.
+"""
+
+from __future__ import print_function
+
+
+
+import os, time
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class ExitDuringStepTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+ @expectedFailureFreeBSD("llvm.org/pr18190") # thread states not properly maintained
+ @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained
+ @expectedFailureWindows("llvm.org/pr24681")
+ def test_thread_state_is_stopped(self):
+ """Test thread exit during step handling."""
+ self.build(dictionary=self.getBuildFlags())
+ self.exit_during_step_base("thread step-in -m all-threads", 'stop reason = step in', True)
+
+ @skipIfFreeBSD # llvm.org/pr21411: test is hanging
+ @expectedFailureWindows("llvm.org/pr24681")
+ def test(self):
+ """Test thread exit during step handling."""
+ self.build(dictionary=self.getBuildFlags())
+ self.exit_during_step_base("thread step-inst -m all-threads", 'stop reason = instruction step', False)
+
+ @skipIfFreeBSD # llvm.org/pr21411: test is hanging
+ @expectedFailureWindows("llvm.org/pr24681")
+ def test_step_over(self):
+ """Test thread exit during step-over handling."""
+ self.build(dictionary=self.getBuildFlags())
+ self.exit_during_step_base("thread step-over -m all-threads", 'stop reason = step over', False)
+
+ @skipIfFreeBSD # llvm.org/pr21411: test is hanging
+ @expectedFailureWindows("llvm.org/pr24681")
+ def test_step_in(self):
+ """Test thread exit during step-in handling."""
+ self.build(dictionary=self.getBuildFlags())
+ self.exit_during_step_base("thread step-in -m all-threads", 'stop reason = step in', False)
+
+ 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_base(self, step_cmd, step_stop_reason, test_thread_state):
+ """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.
+ self.bp_num = 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, exact_match = 0, 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
+ if test_thread_state:
+ 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")
+ return
+
+ # Find the thread that is stopped at the breakpoint
+ stepping_thread = None
+ for thread in process:
+ expected_bp_desc = "breakpoint %s." % self.bp_num
+ stop_desc = thread.GetStopDescription(100)
+ if stop_desc and (expected_bp_desc in stop_desc):
+ stepping_thread = thread
+ break
+ self.assertTrue(stepping_thread != None, "unable to find thread stopped at %s" % expected_bp_desc)
+
+ 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.")
+
+ # Keep stepping until we've reached our designated continue point
+ while current_line != self.continuepoint:
+ # Since we're using the command interpreter to issue the thread command
+ # (on the selected thread) we need to ensure the selected thread is the
+ # stepping thread.
+ if stepping_thread != process.GetSelectedThread():
+ process.SetSelectedThread(stepping_thread)
+
+ self.runCmd(step_cmd)
+
+ 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.')
+
+ self.expect("thread list", 'Process state is stopped due to step',
+ substrs = ['stopped',
+ step_stop_reason])
+
+ # Run to completion
+ self.runCmd("continue")
+
+ # At this point, the inferior process should have exited.
+ self.assertTrue(process.GetState() == lldb.eStateExited, PROCESS_EXITED)
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/main.cpp
new file mode 100644
index 0000000..d1b364b
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/main.cpp
@@ -0,0 +1,87 @@
+//===-- 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 the debugger is stepping in another thread.
+
+#include <thread>
+
+// 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 ()
+{
+ // 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 ()
+{
+ // 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 ()
+{
+ // Synchronize thread start so that doesn't happen during stepping.
+ pseudo_barrier_init(g_barrier, 2);
+
+ // Create a thread to hit the breakpoint.
+ std::thread thread_1(step_thread_func);
+
+ // Create a thread to exit while we're stepping.
+ std::thread thread_2(exit_thread_func);
+
+ // Wait for the exit thread to finish.
+ thread_2.join();
+
+ // Let the stepping thread know the other thread is gone.
+ g_thread_exited = 1;
+
+ // Wait for the stepping thread to finish.
+ thread_1.join();
+
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/jump/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/jump/Makefile
new file mode 100644
index 0000000..b726fc3
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/jump/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+ENABLE_THREADS := YES
+CXX_SOURCES := main.cpp other.cpp
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/jump/TestThreadJump.py b/packages/Python/lldbsuite/test/functionalities/thread/jump/TestThreadJump.py
new file mode 100644
index 0000000..be49a21
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/jump/TestThreadJump.py
@@ -0,0 +1,60 @@
+"""
+Test jumping to different places.
+"""
+
+from __future__ import print_function
+
+
+
+import os, time
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class ThreadJumpTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def test(self):
+ """Test thread jump handling."""
+ self.build(dictionary=self.getBuildFlags())
+ exe = os.path.join(os.getcwd(), "a.out")
+ self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+ # Find the line numbers for our breakpoints.
+ self.mark1 = line_number('main.cpp', '// 1st marker')
+ self.mark2 = line_number('main.cpp', '// 2nd marker')
+ self.mark3 = line_number('main.cpp', '// 3rd marker')
+ self.mark4 = line_number('main.cpp', '// 4th marker')
+ self.mark5 = line_number('other.cpp', '// other marker')
+
+ lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.mark3, num_expected_locations=1)
+ 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'])
+
+ self.do_min_test(self.mark3, self.mark1, "i", "4"); # Try the int path, force it to return 'a'
+ self.do_min_test(self.mark3, self.mark2, "i", "5"); # Try the int path, force it to return 'b'
+ self.do_min_test(self.mark4, self.mark1, "j", "7"); # Try the double path, force it to return 'a'
+ self.do_min_test(self.mark4, self.mark2, "j", "8"); # Try the double path, force it to return 'b'
+
+ # Try jumping to another function in a different file.
+ self.runCmd("thread jump --file other.cpp --line %i --force" % self.mark5)
+ self.expect("process status",
+ substrs = ["at other.cpp:%i" % self.mark5])
+
+ # Try jumping to another function (without forcing)
+ self.expect("j main.cpp:%i" % self.mark1, COMMAND_FAILED_AS_EXPECTED, error = True,
+ substrs = ["error"])
+
+ def do_min_test(self, start, jump, var, value):
+ self.runCmd("j %i" % start) # jump to the start marker
+ self.runCmd("thread step-in") # step into the min fn
+ self.runCmd("j %i" % jump) # jump to the branch we're interested in
+ self.runCmd("thread step-out") # return out
+ self.runCmd("thread step-over") # assign to the global
+ self.expect("expr %s" % var, substrs = [value]) # check it
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/jump/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/jump/main.cpp
new file mode 100644
index 0000000..3497155
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/jump/main.cpp
@@ -0,0 +1,35 @@
+//===-- 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 program counter jumps.
+
+int otherfn();
+
+template<typename T>
+T min(T a, T b)
+{
+ if (a < b)
+ {
+ return a; // 1st marker
+ } else {
+ return b; // 2nd marker
+ }
+}
+
+int main ()
+{
+ int i;
+ double j;
+ int min_i_a = 4, min_i_b = 5;
+ double min_j_a = 7.0, min_j_b = 8.0;
+ i = min(min_i_a, min_i_b); // 3rd marker
+ j = min(min_j_a, min_j_b); // 4th marker
+
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/jump/other.cpp b/packages/Python/lldbsuite/test/functionalities/thread/jump/other.cpp
new file mode 100644
index 0000000..8108a52
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/jump/other.cpp
@@ -0,0 +1,13 @@
+//===-- other.cpp -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+int otherfn()
+{
+ return 4; // other marker
+}
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/main.cpp
new file mode 100644
index 0000000..6a0ea4e
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/main.cpp
@@ -0,0 +1,50 @@
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+
+std::mutex mutex;
+std::condition_variable cond;
+
+void *
+thread3(void *input)
+{
+ std::unique_lock<std::mutex> lock(mutex);
+ cond.notify_all(); // Set break point at this line.
+ return NULL;
+}
+
+void *
+thread2(void *input)
+{
+ std::unique_lock<std::mutex> lock(mutex);
+ cond.notify_all();
+ cond.wait(lock);
+ return NULL;
+}
+
+void *
+thread1(void *input)
+{
+ std::thread thread_2(thread2, nullptr);
+ thread_2.join();
+
+ return NULL;
+}
+
+int main()
+{
+ std::unique_lock<std::mutex> lock(mutex);
+
+ std::thread thread_1(thread1, nullptr);
+ cond.wait(lock);
+
+ std::thread thread_3(thread3, nullptr);
+ cond.wait(lock);
+
+ lock.unlock();
+
+ thread_1.join();
+ thread_3.join();
+
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/multi_break/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/multi_break/Makefile
new file mode 100644
index 0000000..67aa166
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/multi_break/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/multi_break/TestMultipleBreakpoints.py b/packages/Python/lldbsuite/test/functionalities/thread/multi_break/TestMultipleBreakpoints.py
new file mode 100644
index 0000000..9dd2124
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/multi_break/TestMultipleBreakpoints.py
@@ -0,0 +1,77 @@
+"""
+Test number of threads.
+"""
+
+from __future__ import print_function
+
+
+
+import os, time
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class MultipleBreakpointTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ 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')
+
+ @expectedFailureDarwin("llvm.org/pr15824") # thread states not properly maintained
+ @expectedFailureFreeBSD("llvm.org/pr18190") # thread states not properly maintained
+ @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained
+ @expectedFailureWindows("llvm.org/pr24668") # Breakpoints not resolved correctly
+ def test(self):
+ """Test simultaneous breakpoints in multiple threads."""
+ self.build(dictionary=self.getBuildFlags())
+ 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)
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/multi_break/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/multi_break/main.cpp
new file mode 100644
index 0000000..01f4b8f
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/multi_break/main.cpp
@@ -0,0 +1,61 @@
+//===-- 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 <atomic>
+#include <thread>
+
+// 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 ()
+{
+ // Wait until both threads are running
+ pseudo_barrier_wait(g_barrier);
+
+ // Do something
+ g_test++; // Set breakpoint here
+
+ // Return
+ return NULL;
+}
+
+int main ()
+{
+ // Don't let either thread do anything until they're both ready.
+ pseudo_barrier_init(g_barrier, 2);
+
+ // Create two threads
+ std::thread thread_1(thread_func);
+ std::thread thread_2(thread_func);
+
+ // Wait for the threads to finish
+ thread_1.join();
+ thread_2.join();
+
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/state/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/state/Makefile
new file mode 100644
index 0000000..26db481
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/state/Makefile
@@ -0,0 +1,4 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/state/TestThreadStates.py b/packages/Python/lldbsuite/test/functionalities/thread/state/TestThreadStates.py
new file mode 100644
index 0000000..623c659
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/state/TestThreadStates.py
@@ -0,0 +1,333 @@
+"""
+Test thread states.
+"""
+
+from __future__ import print_function
+
+
+
+import unittest2
+import os, time
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class ThreadStateTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @expectedFailureDarwin("rdar://15367566")
+ @expectedFailureFreeBSD('llvm.org/pr15824')
+ @expectedFailureLinux("llvm.org/pr15824") # thread states not properly maintained
+ @expectedFailureWindows("llvm.org/pr24668") # Breakpoints not resolved correctly
+ def test_state_after_breakpoint(self):
+ """Test thread state after breakpoint."""
+ self.build(dictionary=self.getBuildFlags(use_cpp11=False))
+ self.thread_state_after_breakpoint_test()
+
+ @skipIfDarwin # 'llvm.org/pr23669', cause Python crash randomly
+ @expectedFailureDarwin('llvm.org/pr23669')
+ @expectedFailureFreeBSD('llvm.org/pr15824')
+ @expectedFailureWindows("llvm.org/pr24660")
+ def test_state_after_continue(self):
+ """Test thread state after continue."""
+ self.build(dictionary=self.getBuildFlags(use_cpp11=False))
+ self.thread_state_after_continue_test()
+
+ @skipIfDarwin # 'llvm.org/pr23669', cause Python crash randomly
+ @expectedFailureDarwin('llvm.org/pr23669')
+ @expectedFailureWindows("llvm.org/pr24660")
+ @unittest2.expectedFailure("llvm.org/pr16712") # thread states not properly maintained
+ def test_state_after_expression(self):
+ """Test thread state after expression."""
+ self.build(dictionary=self.getBuildFlags(use_cpp11=False))
+ self.thread_state_after_expression_test()
+
+ @unittest2.expectedFailure("llvm.org/pr16712") # thread states not properly maintained
+ @expectedFailureWindows("llvm.org/pr24668") # Breakpoints not resolved correctly
+ def test_process_interrupt(self):
+ """Test process interrupt."""
+ self.build(dictionary=self.getBuildFlags(use_cpp11=False))
+ self.process_interrupt_test()
+
+ @unittest2.expectedFailure("llvm.org/pr15824") # thread states not properly maintained
+ @expectedFailureWindows("llvm.org/pr24668") # Breakpoints not resolved correctly
+ def test_process_state(self):
+ """Test thread states (comprehensive)."""
+ self.build(dictionary=self.getBuildFlags(use_cpp11=False))
+ self.thread_states_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')
+
+ def thread_state_after_breakpoint_test(self):
+ """Test thread state after breakpoint."""
+ 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.break_1, num_expected_locations=1)
+
+ # 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',
+ '* thread #1',
+ 'stop reason = breakpoint'])
+
+ # Get the target process
+ target = self.dbg.GetSelectedTarget()
+ process = target.GetProcess()
+
+ # Get the number of threads
+ num_threads = process.GetNumThreads()
+
+ self.assertTrue(num_threads == 1, 'Number of expected threads and actual threads do not match.')
+
+ # Get the thread object
+ thread = process.GetThreadAtIndex(0)
+
+ # Make sure the thread is in the stopped state.
+ self.assertTrue(thread.IsStopped(), "Thread state isn't \'stopped\' during breakpoint 1.")
+ self.assertFalse(thread.IsSuspended(), "Thread state is \'suspended\' during breakpoint 1.")
+
+ # Kill the process
+ self.runCmd("process kill")
+
+ def wait_for_running_event(self):
+ listener = self.dbg.GetListener()
+ if lldb.remote_platform:
+ lldbutil.expect_state_changes(self, listener, [lldb.eStateConnected])
+ lldbutil.expect_state_changes(self, listener, [lldb.eStateRunning])
+
+ def thread_state_after_continue_test(self):
+ """Test thread state after continue."""
+ 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.break_1, num_expected_locations=1)
+ lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.break_2, num_expected_locations=1)
+
+ # 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',
+ '* thread #1',
+ 'stop reason = breakpoint'])
+
+ # Get the target process
+ target = self.dbg.GetSelectedTarget()
+ process = target.GetProcess()
+
+ # Get the number of threads
+ num_threads = process.GetNumThreads()
+
+ self.assertTrue(num_threads == 1, 'Number of expected threads and actual threads do not match.')
+
+ # Get the thread object
+ thread = process.GetThreadAtIndex(0)
+
+ # Continue, the inferior will go into an infinite loop waiting for 'g_test' to change.
+ self.dbg.SetAsync(True)
+ self.runCmd("continue")
+ self.wait_for_running_event()
+
+ # Check the thread state. It should be running.
+ self.assertFalse(thread.IsStopped(), "Thread state is \'stopped\' when it should be running.")
+ self.assertFalse(thread.IsSuspended(), "Thread state is \'suspended\' when it should be running.")
+
+ # Go back to synchronous interactions
+ self.dbg.SetAsync(False)
+
+ # Kill the process
+ self.runCmd("process kill")
+
+ def thread_state_after_expression_test(self):
+ """Test thread state after expression."""
+ 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.break_1, num_expected_locations=1)
+ lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.break_2, num_expected_locations=1)
+
+ # 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',
+ '* thread #1',
+ 'stop reason = breakpoint'])
+
+ # Get the target process
+ target = self.dbg.GetSelectedTarget()
+ process = target.GetProcess()
+
+ # Get the number of threads
+ num_threads = process.GetNumThreads()
+
+ self.assertTrue(num_threads == 1, 'Number of expected threads and actual threads do not match.')
+
+ # Get the thread object
+ thread = process.GetThreadAtIndex(0)
+
+ # Get the inferior out of its loop
+ self.runCmd("expression g_test = 1")
+
+ # Check the thread state
+ self.assertTrue(thread.IsStopped(), "Thread state isn't \'stopped\' after expression evaluation.")
+ self.assertFalse(thread.IsSuspended(), "Thread state is \'suspended\' after expression evaluation.")
+
+ # Let the process run to completion
+ self.runCmd("process continue")
+
+
+ def process_interrupt_test(self):
+ """Test process interrupt and continue."""
+ 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.break_1, num_expected_locations=1)
+
+ # 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',
+ '* thread #1',
+ 'stop reason = breakpoint'])
+
+ # Get the target process
+ target = self.dbg.GetSelectedTarget()
+ process = target.GetProcess()
+
+ # Get the number of threads
+ num_threads = process.GetNumThreads()
+
+ self.assertTrue(num_threads == 1, 'Number of expected threads and actual threads do not match.')
+
+ # Continue, the inferior will go into an infinite loop waiting for 'g_test' to change.
+ self.dbg.SetAsync(True)
+ self.runCmd("continue")
+ self.wait_for_running_event()
+
+ # Go back to synchronous interactions
+ self.dbg.SetAsync(False)
+
+ # Stop the process
+ self.runCmd("process interrupt")
+
+ # The stop reason of the thread should be signal.
+ self.expect("process status", STOPPED_DUE_TO_SIGNAL,
+ substrs = ['stopped',
+ '* thread #1',
+ 'stop reason = signal'])
+
+ # Get the inferior out of its loop
+ self.runCmd("expression g_test = 1")
+
+ # Run to completion
+ self.runCmd("continue")
+
+ def thread_states_test(self):
+ """Test thread states (comprehensive)."""
+ 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.break_1, num_expected_locations=1)
+ lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.break_2, num_expected_locations=1)
+
+ # 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',
+ '* thread #1',
+ 'stop reason = breakpoint'])
+
+ # Get the target process
+ target = self.dbg.GetSelectedTarget()
+ process = target.GetProcess()
+
+ # Get the number of threads
+ num_threads = process.GetNumThreads()
+
+ self.assertTrue(num_threads == 1, 'Number of expected threads and actual threads do not match.')
+
+ # Get the thread object
+ thread = process.GetThreadAtIndex(0)
+
+ # Make sure the thread is in the stopped state.
+ self.assertTrue(thread.IsStopped(), "Thread state isn't \'stopped\' during breakpoint 1.")
+ self.assertFalse(thread.IsSuspended(), "Thread state is \'suspended\' during breakpoint 1.")
+
+ # Continue, the inferior will go into an infinite loop waiting for 'g_test' to change.
+ self.dbg.SetAsync(True)
+ self.runCmd("continue")
+ self.wait_for_running_event()
+
+ # Check the thread state. It should be running.
+ self.assertFalse(thread.IsStopped(), "Thread state is \'stopped\' when it should be running.")
+ self.assertFalse(thread.IsSuspended(), "Thread state is \'suspended\' when it should be running.")
+
+ # Go back to synchronous interactions
+ self.dbg.SetAsync(False)
+
+ # Stop the process
+ self.runCmd("process interrupt")
+
+ # The stop reason of the thread should be signal.
+ self.expect("process status", STOPPED_DUE_TO_SIGNAL,
+ substrs = ['stopped',
+ '* thread #1',
+ 'stop reason = signal'])
+
+ # Check the thread state
+ self.assertTrue(thread.IsStopped(), "Thread state isn't \'stopped\' after process stop.")
+ self.assertFalse(thread.IsSuspended(), "Thread state is \'suspended\' after process stop.")
+
+ # Get the inferior out of its loop
+ self.runCmd("expression g_test = 1")
+
+ # Check the thread state
+ self.assertTrue(thread.IsStopped(), "Thread state isn't \'stopped\' after expression evaluation.")
+ self.assertFalse(thread.IsSuspended(), "Thread state is \'suspended\' after expression evaluation.")
+
+ # The stop reason of the thread should be signal.
+ self.expect("process status", STOPPED_DUE_TO_SIGNAL,
+ substrs = ['stopped',
+ '* thread #1',
+ 'stop reason = signal'])
+
+ # Run to breakpoint 2
+ self.runCmd("continue")
+
+ # The stop reason of the thread should be breakpoint.
+ self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+ substrs = ['stopped',
+ '* thread #1',
+ 'stop reason = breakpoint'])
+
+ # Make sure both threads are stopped
+ self.assertTrue(thread.IsStopped(), "Thread state isn't \'stopped\' during breakpoint 2.")
+ self.assertFalse(thread.IsSuspended(), "Thread state is \'suspended\' during breakpoint 2.")
+
+ # Run to completion
+ self.runCmd("continue")
+
+ # At this point, the inferior process should have exited.
+ self.assertTrue(process.GetState() == lldb.eStateExited, PROCESS_EXITED)
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/state/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/state/main.cpp
new file mode 100644
index 0000000..081203d
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/state/main.cpp
@@ -0,0 +1,45 @@
+//===-- 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 verify that thread states are properly maintained
+// when transitional actions are performed in the debugger. Most of the logic
+// is in the test script. This program merely provides places where the test
+// can create the intended states.
+
+#include <chrono>
+#include <thread>
+
+volatile int g_test = 0;
+
+int addSomething(int a)
+{
+ return a + g_test;
+}
+
+int doNothing()
+{
+ int temp = 0; // Set first breakpoint here
+
+ while (!g_test && temp < 5)
+ {
+ ++temp;
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ }
+
+ return temp; // Set second breakpoint here
+}
+
+int main ()
+{
+ int result = doNothing();
+
+ int i = addSomething(result);
+
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/step_out/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/step_out/Makefile
new file mode 100644
index 0000000..035413f
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/step_out/Makefile
@@ -0,0 +1,6 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/step_out/TestThreadStepOut.py b/packages/Python/lldbsuite/test/functionalities/thread/step_out/TestThreadStepOut.py
new file mode 100644
index 0000000..b2d966c
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/step_out/TestThreadStepOut.py
@@ -0,0 +1,131 @@
+"""
+Test stepping out from a function in a multi-threaded program.
+"""
+
+from __future__ import print_function
+
+
+
+import os, time
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class ThreadStepOutTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfLinux # Test occasionally times out on the Linux build bot
+ @expectedFailureLinux("llvm.org/pr23477") # Test occasionally times out on the Linux build bot
+ @expectedFailureFreeBSD("llvm.org/pr18066") # inferior does not exit
+ @expectedFailureWindows # Test crashes
+ def test_step_single_thread(self):
+ """Test thread step out on one thread via command interpreter. """
+ self.build(dictionary=self.getBuildFlags())
+ self.step_out_test(self.step_out_single_thread_with_cmd)
+
+ @skipIfLinux # Test occasionally times out on the Linux build bot
+ @expectedFailureLinux("llvm.org/pr23477") # Test occasionally times out on the Linux build bot
+ @expectedFailureFreeBSD("llvm.org/pr19347") # 2nd thread stops at breakpoint
+ @expectedFailureWindows # Test crashes
+ def test_step_all_threads(self):
+ """Test thread step out on all threads via command interpreter. """
+ self.build(dictionary=self.getBuildFlags())
+ self.step_out_test(self.step_out_all_threads_with_cmd)
+
+ @skipIfLinux # Test occasionally times out on the Linux build bot
+ @expectedFailureLinux("llvm.org/pr23477") # Test occasionally times out on the Linux build bot
+ @expectedFailureFreeBSD("llvm.org/pr19347")
+ @expectedFailureWindows("llvm.org/pr24681")
+ def test_python(self):
+ """Test thread step out on one thread via Python API (dwarf)."""
+ self.build(dictionary=self.getBuildFlags())
+ self.step_out_test(self.step_out_with_python)
+
+ 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')
+ if "gcc" in self.getCompiler() or self.isIntelCompiler():
+ self.step_out_destination = line_number('main.cpp', '// Expect to stop here after step-out (icc and gcc)')
+ else:
+ self.step_out_destination = line_number('main.cpp', '// Expect to stop here after step-out (clang)')
+
+ def step_out_single_thread_with_cmd(self):
+ self.step_out_with_cmd("this-thread")
+ self.expect("thread backtrace all", "Thread location after step out is correct",
+ substrs = ["main.cpp:%d" % self.step_out_destination,
+ "main.cpp:%d" % self.breakpoint])
+
+ def step_out_all_threads_with_cmd(self):
+ self.step_out_with_cmd("all-threads")
+ self.expect("thread backtrace all", "Thread location after step out is correct",
+ substrs = ["main.cpp:%d" % self.step_out_destination])
+
+ def step_out_with_cmd(self, run_mode):
+ self.runCmd("thread select %d" % self.step_out_thread.GetIndexID())
+ self.runCmd("thread step-out -m %s" % run_mode)
+ self.expect("process status", "Expected stop reason to be step-out",
+ substrs = ["stop reason = step out"])
+
+ self.expect("thread list", "Selected thread did not change during step-out",
+ substrs = ["* thread #%d" % self.step_out_thread.GetIndexID()])
+
+ def step_out_with_python(self):
+ self.step_out_thread.StepOut()
+
+ reason = self.step_out_thread.GetStopReason()
+ self.assertEqual(lldb.eStopReasonPlanComplete, reason,
+ "Expected thread stop reason 'plancomplete', but got '%s'" % lldbutil.stop_reason_to_str(reason))
+
+ # Verify location after stepping out
+ frame = self.step_out_thread.GetFrameAtIndex(0)
+ desc = lldbutil.get_description(frame.GetLineEntry())
+ expect = "main.cpp:%d" % self.step_out_destination
+ self.assertTrue(expect in desc, "Expected %s but thread stopped at %s" % (expect, desc))
+
+ def step_out_test(self, step_out_func):
+ """Test single thread step out of a function."""
+ 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, exact_match = 0, locations = 1" % self.breakpoint])
+
+ # Run the program.
+ self.runCmd("run", RUN_SUCCEEDED)
+
+ # Get the target process
+ self.inferior_target = self.dbg.GetSelectedTarget()
+ self.inferior_process = self.inferior_target.GetProcess()
+
+ # Get the number of threads, ensure we see all three.
+ num_threads = self.inferior_process.GetNumThreads()
+ self.assertEqual(num_threads, 3, 'Number of expected threads and actual threads do not match.')
+
+ (breakpoint_threads, other_threads) = ([], [])
+ lldbutil.sort_stopped_threads(self.inferior_process,
+ breakpoint_threads=breakpoint_threads,
+ other_threads=other_threads)
+
+ while len(breakpoint_threads) < 2:
+ self.runCmd("thread continue %s" % " ".join([str(x.GetIndexID()) for x in other_threads]))
+ lldbutil.sort_stopped_threads(self.inferior_process,
+ breakpoint_threads=breakpoint_threads,
+ other_threads=other_threads)
+
+ self.step_out_thread = breakpoint_threads[0]
+
+ # Step out of thread stopped at breakpoint
+ step_out_func()
+
+ # Run to completion
+ self.runCmd("continue")
+
+ # At this point, the inferior process should have exited.
+ self.assertTrue(self.inferior_process.GetState() == lldb.eStateExited, PROCESS_EXITED)
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/step_out/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/step_out/main.cpp
new file mode 100644
index 0000000..b4c6216
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/step_out/main.cpp
@@ -0,0 +1,63 @@
+//===-- 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 two threads are stopped
+// at a breakpoint and the debugger issues a step-out command.
+
+#include <atomic>
+#include <thread>
+
+// 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 step_out_of_here() {
+ g_test += 5; // Set breakpoint here
+}
+
+void *
+thread_func ()
+{
+ // Wait until both threads are running
+ pseudo_barrier_wait(g_barrier);
+
+ // Do something
+ step_out_of_here(); // Expect to stop here after step-out (clang)
+
+ // Return
+ return NULL; // Expect to stop here after step-out (icc and gcc)
+}
+
+int main ()
+{
+ // Don't let either thread do anything until they're both ready.
+ pseudo_barrier_init(g_barrier, 2);
+
+ // Create two threads
+ std::thread thread_1(thread_func);
+ std::thread thread_2(thread_func);
+
+ // Wait for the threads to finish
+ thread_1.join();
+ thread_2.join();
+
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/thread_exit/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/thread_exit/Makefile
new file mode 100644
index 0000000..d06a7d4
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/thread_exit/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+ENABLE_THREADS := YES
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/thread_exit/TestThreadExit.py b/packages/Python/lldbsuite/test/functionalities/thread/thread_exit/TestThreadExit.py
new file mode 100644
index 0000000..f785401
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/thread_exit/TestThreadExit.py
@@ -0,0 +1,116 @@
+"""
+Test number of threads.
+"""
+
+from __future__ import print_function
+
+
+
+import os, time
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class ThreadExitTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ 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')
+
+ @expectedFailureWindows("llvm.org/pr24681")
+ def test(self):
+ """Test thread exit handling."""
+ self.build(dictionary=self.getBuildFlags())
+ 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, exact_match = 0, locations = 1" % self.break_1,
+ "2: file = 'main.cpp', line = %d, exact_match = 0, locations = 1" % self.break_2,
+ "3: file = 'main.cpp', line = %d, exact_match = 0, locations = 1" % self.break_3,
+ "4: file = 'main.cpp', line = %d, exact_match = 0, 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)
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/thread_exit/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/thread_exit/main.cpp
new file mode 100644
index 0000000..e498db7
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/thread_exit/main.cpp
@@ -0,0 +1,85 @@
+//===-- 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 <atomic>
+#include <thread>
+
+// 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 ()
+{
+ // 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 ()
+{
+ // 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 ()
+{
+ pseudo_barrier_init(g_barrier1, 2);
+ pseudo_barrier_init(g_barrier2, 3);
+ pseudo_barrier_init(g_barrier3, 2);
+
+ // Create a thread.
+ std::thread thread_1(thread1);
+
+ // Wait for thread1 to start.
+ pseudo_barrier_wait(g_barrier1);
+
+ // Create another thread.
+ std::thread thread_2(thread2); // Set first breakpoint here
+
+ // Wait for thread2 to start.
+ pseudo_barrier_wait(g_barrier2);
+
+ // Wait for the first thread to finish
+ thread_1.join();
+
+ // Synchronize with the remaining thread
+ pseudo_barrier_wait(g_barrier3); // Set third breakpoint here
+
+ // Wait for the second thread to finish
+ thread_2.join();
+
+ return 0; // Set fourth breakpoint here
+}
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/Makefile
new file mode 100644
index 0000000..035413f
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/Makefile
@@ -0,0 +1,6 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/TestThreadSpecificBreakpoint.py b/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/TestThreadSpecificBreakpoint.py
new file mode 100644
index 0000000..3c69b66
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/TestThreadSpecificBreakpoint.py
@@ -0,0 +1,63 @@
+"""
+Test that we obey thread conditioned breakpoints.
+"""
+
+from __future__ import print_function
+
+
+
+import os, time
+import re
+import lldb
+import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.lldbtest import *
+
+class ThreadSpecificBreakTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @add_test_categories(['pyapi'])
+ @expectedFailureWindows # Thread specific breakpoints cause the inferior to crash
+ def test_python(self):
+ """Test that we obey thread conditioned breakpoints."""
+ self.build()
+ exe = os.path.join(os.getcwd(), "a.out")
+
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, VALID_TARGET)
+
+ # This test works by setting a breakpoint in a function conditioned to stop only on
+ # the main thread, and then calling this function on a secondary thread, joining,
+ # and then calling again on the main thread. If the thread specific breakpoint works
+ # then it should not be hit on the secondary thread, only on the main thread.
+
+ main_source_spec = lldb.SBFileSpec ("main.cpp")
+
+ main_breakpoint = target.BreakpointCreateBySourceRegex("Set main breakpoint here", main_source_spec);
+ thread_breakpoint = target.BreakpointCreateBySourceRegex("Set thread-specific breakpoint here", main_source_spec)
+
+ self.assertTrue(main_breakpoint.IsValid(), "Failed to set main breakpoint.")
+ self.assertGreater(main_breakpoint.GetNumLocations(), 0, "main breakpoint has no locations associated with it.")
+ self.assertTrue(thread_breakpoint.IsValid(), "Failed to set thread breakpoint.")
+ self.assertGreater(thread_breakpoint.GetNumLocations(), 0, "thread breakpoint has no locations associated with it.")
+
+ process = target.LaunchSimple (None, None, self.get_process_working_directory())
+
+ self.assertTrue(process, PROCESS_IS_VALID)
+
+ stopped_threads = lldbutil.get_threads_stopped_at_breakpoint(process, main_breakpoint)
+ self.assertEqual(len(stopped_threads), 1, "main breakpoint stopped at unexpected number of threads")
+ main_thread = stopped_threads[0]
+ main_thread_id = main_thread.GetThreadID()
+
+ # Set the thread-specific breakpoint to only stop on the main thread. The run the function
+ # on another thread and join on it. If the thread-specific breakpoint works, the next
+ # stop should be on the main thread.
+ thread_breakpoint.SetThreadID(main_thread_id)
+
+ process.Continue()
+ next_stop_state = process.GetState()
+ self.assertEqual(next_stop_state, lldb.eStateStopped, "We should have stopped at the thread breakpoint.")
+ stopped_threads = lldbutil.get_threads_stopped_at_breakpoint(process, thread_breakpoint)
+ self.assertEqual(len(stopped_threads), 1, "thread breakpoint stopped at unexpected number of threads")
+ self.assertEqual(stopped_threads[0].GetThreadID(), main_thread_id, "thread breakpoint stopped at the wrong thread")
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/main.cpp
new file mode 100644
index 0000000..7721b5d
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/main.cpp
@@ -0,0 +1,20 @@
+#include <chrono>
+#include <thread>
+
+void
+thread_function ()
+{
+ // Set thread-specific breakpoint here.
+ std::this_thread::sleep_for(std::chrono::microseconds(100));
+}
+
+int
+main ()
+{
+ // Set main breakpoint here.
+ std::thread t(thread_function);
+ t.join();
+
+ thread_function();
+ return 0;
+}
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/Makefile b/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/Makefile
new file mode 100644
index 0000000..035413f
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/Makefile
@@ -0,0 +1,6 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+ENABLE_THREADS := YES
+
+include $(LEVEL)/Makefile.rules
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/TestThreadSpecificBpPlusCondition.py b/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/TestThreadSpecificBpPlusCondition.py
new file mode 100644
index 0000000..b4a0b7a
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/TestThreadSpecificBpPlusCondition.py
@@ -0,0 +1,65 @@
+"""
+Test that we obey thread conditioned breakpoints and expression
+conditioned breakpoints simultaneously
+"""
+
+from __future__ import print_function
+
+
+
+import os, time
+import re
+import lldb
+import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.lldbtest import *
+
+class ThreadSpecificBreakPlusConditionTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIfFreeBSD # test frequently times out or hangs
+ @expectedFailureFreeBSD('llvm.org/pr18522') # hits break in another thread in testrun
+ @add_test_categories(['pyapi'])
+ @expectedFailureWindows # Thread specific breakpoints cause the inferior to crash.
+ @expectedFlakeyLinux # this test fails 6/100 dosep runs
+ def test_python(self):
+ """Test that we obey thread conditioned breakpoints."""
+ self.build()
+ exe = os.path.join(os.getcwd(), "a.out")
+
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, VALID_TARGET)
+
+ main_source_spec = lldb.SBFileSpec ("main.cpp")
+
+ # Set a breakpoint in the thread body, and make it active for only the first thread.
+ break_thread_body = target.BreakpointCreateBySourceRegex ("Break here in thread body.", main_source_spec)
+ self.assertTrue (break_thread_body.IsValid() and break_thread_body.GetNumLocations() > 0, "Failed to set thread body breakpoint.")
+
+ process = target.LaunchSimple (None, None, self.get_process_working_directory())
+
+ self.assertTrue(process, PROCESS_IS_VALID)
+
+ threads = lldbutil.get_threads_stopped_at_breakpoint (process, break_thread_body)
+
+ victim_thread = threads[0]
+
+ # Pick one of the threads, and change the breakpoint so it ONLY stops for this thread,
+ # but add a condition that it won't stop for this thread's my_value. The other threads
+ # pass the condition, so they should stop, but if the thread-specification is working
+ # they should not stop. So nobody should hit the breakpoint anymore, and we should
+ # just exit cleanly.
+
+ frame = victim_thread.GetFrameAtIndex(0)
+ value = frame.FindVariable("my_value").GetValueAsSigned(0)
+ self.assertTrue (value > 0 and value < 11, "Got a reasonable value for my_value.")
+
+ cond_string = "my_value != %d"%(value)
+
+ break_thread_body.SetThreadID(victim_thread.GetThreadID())
+ break_thread_body.SetCondition (cond_string)
+
+ process.Continue()
+
+ next_stop_state = process.GetState()
+ self.assertTrue (next_stop_state == lldb.eStateExited, "We should have not hit the breakpoint again.")
diff --git a/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/main.cpp b/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/main.cpp
new file mode 100644
index 0000000..af8ab84
--- /dev/null
+++ b/packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/main.cpp
@@ -0,0 +1,39 @@
+#include <chrono>
+#include <thread>
+#include <vector>
+
+void *
+thread_function (void *thread_marker)
+{
+ int keep_going = 1;
+ int my_value = *((int *)thread_marker);
+ int counter = 0;
+
+ while (counter < 20)
+ {
+ counter++; // Break here in thread body.
+ std::this_thread::sleep_for(std::chrono::microseconds(10));
+ }
+ return NULL;
+}
+
+
+int
+main ()
+{
+ std::vector<std::thread> threads;
+
+ int thread_value = 0;
+ int i;
+
+ for (i = 0; i < 10; i++)
+ {
+ thread_value += 1;
+ threads.push_back(std::thread(thread_function, &thread_value));
+ }
+
+ for (i = 0; i < 10; i++)
+ threads[i].join();
+
+ return 0;
+}
OpenPOWER on IntegriCloud