File: main.cpp

package info (click to toggle)
llvm-toolchain-3.8 1%3A3.8.1-24
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 379,280 kB
  • ctags: 388,501
  • sloc: cpp: 2,309,705; ansic: 477,070; objc: 100,918; asm: 97,974; python: 95,911; sh: 18,634; makefile: 7,294; perl: 5,584; ml: 5,460; pascal: 4,661; lisp: 2,548; xml: 686; cs: 350; php: 212; csh: 117
file content (130 lines) | stat: -rw-r--r-- 3,760 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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;
}