summaryrefslogtreecommitdiffstats
path: root/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all
diff options
context:
space:
mode:
Diffstat (limited to 'packages/Python/lldbsuite/test/functionalities/thread/backtrace_all')
-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
3 files changed, 214 insertions, 0 deletions
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()
OpenPOWER on IntegriCloud