diff options
| author | Michael Kruse <llvm-project@meinersbur.de> | 2025-01-03 10:22:51 +0100 |
|---|---|---|
| committer | Michael Kruse <llvm-project@meinersbur.de> | 2025-01-03 10:22:51 +0100 |
| commit | 38500d63e14ce340236840f60d356cdefb56a52c (patch) | |
| tree | 17edbec446ce9b50d2f215a483b83afb293a635d /lldb/test/API/api | |
| parent | 1a3d5daaef7a6a63448a497da3eff7fc9e23df26 (diff) | |
| parent | 27f30029741ecf023baece7b3dde1ff9011ffefc (diff) | |
Merge branch 'main' into users/meinersbur/flang_runtime_split-headersusers/meinersbur/flang_runtime_split-headers
Diffstat (limited to 'lldb/test/API/api')
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"); +} |
