136 lines
3.9 KiB
C++
136 lines
3.9 KiB
C++
//===-- 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 <pthread.h>
|
|
#include <unistd.h>
|
|
#include <atomic>
|
|
|
|
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 (void *input)
|
|
{
|
|
// 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 (void *input)
|
|
{
|
|
// 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 (void *input)
|
|
{
|
|
// 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.
|
|
usleep(1);
|
|
|
|
// Return
|
|
return NULL;
|
|
}
|
|
|
|
int main ()
|
|
{
|
|
pthread_t thread_1;
|
|
pthread_t thread_2;
|
|
pthread_t thread_3;
|
|
pthread_t thread_4;
|
|
pthread_t thread_5;
|
|
|
|
// 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
|
|
pthread_create (&thread_1, NULL, break_thread_func, NULL);
|
|
|
|
// Create more threads to slow the debugger down during processing.
|
|
pthread_create (&thread_2, NULL, wait_thread_func, NULL);
|
|
pthread_create (&thread_3, NULL, wait_thread_func, NULL);
|
|
pthread_create (&thread_4, NULL, wait_thread_func, NULL);
|
|
|
|
// Wait for all these threads to get started.
|
|
pseudo_barrier_wait(g_barrier1);
|
|
|
|
// Create a thread to exit during the breakpoint
|
|
pthread_create (&thread_5, NULL, exit_thread_func, NULL);
|
|
|
|
// Wait for the threads to finish
|
|
pthread_join(thread_5, NULL);
|
|
pthread_join(thread_4, NULL);
|
|
pthread_join(thread_3, NULL);
|
|
pthread_join(thread_2, NULL);
|
|
pthread_join(thread_1, NULL);
|
|
|
|
return 0;
|
|
}
|