diff options
Diffstat (limited to 'packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/main.cpp')
-rw-r--r-- | packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/main.cpp | 130 |
1 files changed, 130 insertions, 0 deletions
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 000000000000..3570637207d2 --- /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; +} |