summaryrefslogtreecommitdiff
path: root/lldb/test/API/api
diff options
context:
space:
mode:
authorMichael Kruse <llvm-project@meinersbur.de>2025-01-03 10:22:51 +0100
committerMichael Kruse <llvm-project@meinersbur.de>2025-01-03 10:22:51 +0100
commit38500d63e14ce340236840f60d356cdefb56a52c (patch)
tree17edbec446ce9b50d2f215a483b83afb293a635d /lldb/test/API/api
parent1a3d5daaef7a6a63448a497da3eff7fc9e23df26 (diff)
parent27f30029741ecf023baece7b3dde1ff9011ffefc (diff)
Merge branch 'main' into users/meinersbur/flang_runtime_split-headersusers/meinersbur/flang_runtime_split-headers
Diffstat (limited to 'lldb/test/API/api')
-rw-r--r--lldb/test/API/api/multithreaded/TestMultithreaded.py17
-rw-r--r--lldb/test/API/api/multithreaded/deep_stack.cpp17
-rw-r--r--lldb/test/API/api/multithreaded/test_concurrent_unwind.cpp.template91
3 files changed, 123 insertions, 2 deletions
diff --git a/lldb/test/API/api/multithreaded/TestMultithreaded.py b/lldb/test/API/api/multithreaded/TestMultithreaded.py
index 07c9f5b9bbcc..d5b29ec7af18 100644
--- a/lldb/test/API/api/multithreaded/TestMultithreaded.py
+++ b/lldb/test/API/api/multithreaded/TestMultithreaded.py
@@ -22,6 +22,7 @@ class SBBreakpointCallbackCase(TestBase):
self.generateSource("test_listener_event_process_state.cpp")
self.generateSource("test_listener_resume.cpp")
self.generateSource("test_stop-hook.cpp")
+ self.generateSource("test_concurrent_unwind.cpp")
@skipIfRemote
# clang-cl does not support throw or catch (llvm.org/pr24538)
@@ -91,7 +92,19 @@ class SBBreakpointCallbackCase(TestBase):
"test_listener_resume",
)
- def build_and_test(self, sources, test_name, args=None):
+ @skipIfRemote
+ # clang-cl does not support throw or catch (llvm.org/pr24538)
+ @skipIfWindows
+ @skipIfHostIncompatibleWithTarget
+ def test_concurrent_unwind(self):
+ """Test that you can run a python command in a stop-hook when stdin is File based."""
+ self.build_and_test(
+ "driver.cpp test_concurrent_unwind.cpp",
+ "test_concurrent_unwind",
+ inferior_source="deep_stack.cpp",
+ )
+
+ def build_and_test(self, sources, test_name, inferior_source="inferior.cpp"):
"""Build LLDB test from sources, and run expecting 0 exit code"""
# These tests link against host lldb API.
@@ -104,7 +117,7 @@ class SBBreakpointCallbackCase(TestBase):
)
self.inferior = "inferior_program"
- self.buildProgram("inferior.cpp", self.inferior)
+ self.buildProgram(inferior_source, self.inferior)
self.addTearDownHook(lambda: os.remove(self.getBuildArtifact(self.inferior)))
self.buildDriver(sources, test_name)
diff --git a/lldb/test/API/api/multithreaded/deep_stack.cpp b/lldb/test/API/api/multithreaded/deep_stack.cpp
new file mode 100644
index 000000000000..da89228766e4
--- /dev/null
+++ b/lldb/test/API/api/multithreaded/deep_stack.cpp
@@ -0,0 +1,17 @@
+// This is a test program that makes a deep stack
+// so we can test unwinding from multiple threads.
+
+void call_me(int input) {
+ if (input > 1000) {
+ input += 1; // Set a breakpoint here
+ if (input > 1001)
+ input += 1;
+ return;
+ } else
+ call_me(++input);
+}
+
+int main() {
+ call_me(0);
+ return 0;
+}
diff --git a/lldb/test/API/api/multithreaded/test_concurrent_unwind.cpp.template b/lldb/test/API/api/multithreaded/test_concurrent_unwind.cpp.template
new file mode 100644
index 000000000000..e5101dde7961
--- /dev/null
+++ b/lldb/test/API/api/multithreaded/test_concurrent_unwind.cpp.template
@@ -0,0 +1,91 @@
+#include "pseudo_barrier.h"
+
+#include <atomic>
+#include <thread>
+
+%include_SB_APIs%
+
+#include "common.h"
+
+using namespace lldb;
+
+void test (SBDebugger &dbg, std::vector<std::string> args) {
+
+SBError error;
+ dbg.SetAsync(false);
+ SBTarget target = dbg.CreateTarget(args.at(0).c_str());
+ if (!target.IsValid())
+ throw Exception("Invalid target");
+
+ // Now set our breakpoint and launch:
+ SBFileSpec main_sourcefile("deep_stack.cpp");
+ SBBreakpoint bkpt = target.BreakpointCreateBySourceRegex("Set a breakpoint here",
+ main_sourcefile);
+ if (bkpt.GetNumLocations() == 0)
+ throw Exception("Main breakpoint got no locations");
+
+ SBLaunchInfo launch_info = target.GetLaunchInfo();
+ SBProcess process = target.Launch(launch_info, error);
+ if (error.Fail())
+ throw Exception("Failed to launch process");
+ if (!process.IsValid())
+ throw Exception("Process is not valid");
+ if (process.GetState() != lldb::eStateStopped)
+ throw Exception("Process was not stopped");
+
+ size_t num_threads = process.GetNumThreads();
+ if (num_threads != 1)
+ throw Exception("Unexpected number of threads.");
+ SBThread cur_thread = process.GetThreadAtIndex(0);
+ if (!cur_thread.IsValid())
+ throw Exception("Didn't get a valid thread");
+
+ // Record the number of frames at the point where we stopped:
+ const size_t num_frames = cur_thread.GetNumFrames();
+ // Now step once to clear the frame cache:
+ cur_thread.StepOver();
+
+ // Create three threads and set them to getting frames simultaneously,
+ // and make sure we don't deadlock.
+ pseudo_barrier_t rendevous;
+ pseudo_barrier_init(rendevous, 5);
+ std::atomic_size_t success(true);
+ std::atomic_size_t largest(0);
+
+ auto lambda = [&](size_t stride){
+ pseudo_barrier_wait(rendevous);
+ bool younger = true;
+ while (1) {
+ size_t cursor = largest;
+ if (cursor > stride && !younger) {
+ cursor -= stride;
+ younger = true;
+ } else {
+ cursor += stride;
+ largest += stride;
+ younger = false;
+ }
+ SBFrame frame = cur_thread.GetFrameAtIndex(cursor);
+ if (!frame.IsValid()) {
+ if (cursor < num_frames)
+ success = false;
+ break;
+ }
+ }
+
+ };
+
+ std::thread thread1(lambda, 1);
+ std::thread thread2(lambda, 3);
+ std::thread thread3(lambda, 5);
+ std::thread thread4(lambda, 7);
+ std::thread thread5(lambda, 11);
+ thread1.join();
+ thread2.join();
+ thread3.join();
+ thread4.join();
+ thread5.join();
+
+ if (!success)
+ throw Exception("One thread stopped before 1000");
+}