Home | History | Annotate | Download | only in exit_during_break
      1 //===-- main.cpp ------------------------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 // This test is intended to create a situation in which one thread will exit
     11 // while a breakpoint is being handled in another thread.  This may not always
     12 // happen because it's possible that the exiting thread will exit before the
     13 // breakpoint is hit.  The test case should be flexible enough to treat that
     14 // as success.
     15 
     16 #include <pthread.h>
     17 #include <unistd.h>
     18 #include <atomic>
     19 
     20 volatile int g_test = 0;
     21 
     22 // Note that although hogging the CPU while waiting for a variable to change
     23 // would be terrible in production code, it's great for testing since it
     24 // avoids a lot of messy context switching to get multiple threads synchronized.
     25 #define do_nothing()
     26 
     27 #define pseudo_barrier_wait(bar) \
     28     --bar;                       \
     29     while (bar > 0)              \
     30         do_nothing();
     31 
     32 #define pseudo_barrier_init(bar, count) (bar = count)
     33 
     34 // A barrier to synchronize all the threads except the one that will exit.
     35 std::atomic_int g_barrier1;
     36 
     37 // A barrier to synchronize all the threads including the one that will exit.
     38 std::atomic_int g_barrier2;
     39 
     40 // A barrier to keep the first group of threads from exiting until after the
     41 // breakpoint has been passed.
     42 std::atomic_int g_barrier3;
     43 
     44 void *
     45 break_thread_func (void *input)
     46 {
     47     // Wait until the entire first group of threads is running
     48     pseudo_barrier_wait(g_barrier1);
     49 
     50     // Wait for the exiting thread to start
     51     pseudo_barrier_wait(g_barrier2);
     52 
     53     // Do something
     54     g_test++;       // Set breakpoint here
     55 
     56     // Synchronize after the breakpoint
     57     pseudo_barrier_wait(g_barrier3);
     58 
     59     // Return
     60     return NULL;
     61 }
     62 
     63 void *
     64 wait_thread_func (void *input)
     65 {
     66     // Wait until the entire first group of threads is running
     67     pseudo_barrier_wait(g_barrier1);
     68 
     69     // Wait for the exiting thread to start
     70     pseudo_barrier_wait(g_barrier2);
     71 
     72     // Wait until the breakpoint has been passed
     73     pseudo_barrier_wait(g_barrier3);
     74 
     75     // Return
     76     return NULL;
     77 }
     78 
     79 void *
     80 exit_thread_func (void *input)
     81 {
     82     // Sync up with the rest of the threads.
     83     pseudo_barrier_wait(g_barrier2);
     84 
     85     // Try to make sure this thread doesn't exit until the breakpoint is hit.
     86     usleep(1);
     87 
     88     // Return
     89     return NULL;
     90 }
     91 
     92 int main ()
     93 {
     94     pthread_t thread_1;
     95     pthread_t thread_2;
     96     pthread_t thread_3;
     97     pthread_t thread_4;
     98     pthread_t thread_5;
     99 
    100     // The first barrier waits for the non-exiting threads to start.
    101     // This thread will also participate in that barrier.
    102     // The idea here is to guarantee that the exiting thread will be
    103     // last in the internal list maintained by the debugger.
    104     pseudo_barrier_init(g_barrier1, 5);
    105 
    106     // The second break synchronyizes thread exection with the breakpoint.
    107     pseudo_barrier_init(g_barrier2, 5);
    108 
    109     // The third barrier keeps the waiting threads around until the breakpoint
    110     // has been passed.
    111     pseudo_barrier_init(g_barrier3, 4);
    112 
    113     // Create a thread to hit the breakpoint
    114     pthread_create (&thread_1, NULL, break_thread_func, NULL);
    115 
    116     // Create more threads to slow the debugger down during processing.
    117     pthread_create (&thread_2, NULL, wait_thread_func, NULL);
    118     pthread_create (&thread_3, NULL, wait_thread_func, NULL);
    119     pthread_create (&thread_4, NULL, wait_thread_func, NULL);
    120 
    121     // Wait for all these threads to get started.
    122     pseudo_barrier_wait(g_barrier1);
    123 
    124     // Create a thread to exit during the breakpoint
    125     pthread_create (&thread_5, NULL, exit_thread_func, NULL);
    126 
    127     // Wait for the threads to finish
    128     pthread_join(thread_5, NULL);
    129     pthread_join(thread_4, NULL);
    130     pthread_join(thread_3, NULL);
    131     pthread_join(thread_2, NULL);
    132     pthread_join(thread_1, NULL);
    133 
    134     return 0;
    135 }
    136