1 //===-- main.cpp ------------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include <chrono>
10 #include <condition_variable>
11 #include <cstdio>
12 #include <thread>
13 
14 std::condition_variable g_condition_variable;
15 std::mutex g_mutex;
16 int g_count;
17 
18 char *g_char_ptr = nullptr;
19 
20 void
21 barrier_wait()
22 {
23     std::unique_lock<std::mutex> lock{g_mutex};
24     if (--g_count > 0)
25         g_condition_variable.wait(lock);
26     else
27         g_condition_variable.notify_all();
28 }
29 
30 void
31 do_bad_thing_with_location(unsigned index, char *char_ptr, char new_val)
32 {
33     unsigned what = new_val;
34     printf("new value written to array(%p) and index(%u) = %u\n", char_ptr, index, what);
35     char_ptr[index] = new_val;
36 }
37 
38 uint32_t
39 access_pool (bool flag = false)
40 {
41     static std::mutex g_access_mutex;
42     static unsigned idx = 0; // Well-behaving thread only writes into indexs from 0..6.
43     if (!flag)
44         g_access_mutex.lock();
45 
46     // idx valid range is [0, 6].
47     if (idx > 6)
48         idx = 0;
49 
50     if (flag)
51     {
52         // Write into a forbidden area.
53         do_bad_thing_with_location(7, g_char_ptr, 99);
54     }
55 
56     unsigned index = idx++;
57 
58     if (!flag)
59         g_access_mutex.unlock();
60     return g_char_ptr[index];
61 }
62 
63 void
64 thread_func (uint32_t thread_index)
65 {
66     printf ("%s (thread index = %u) startng...\n", __FUNCTION__, thread_index);
67 
68     barrier_wait();
69 
70     uint32_t count = 0;
71     uint32_t val;
72     while (count++ < 15)
73     {
74         printf ("%s (thread = %u) sleeping for 1 second...\n", __FUNCTION__, thread_index);
75         std::this_thread::sleep_for(std::chrono::seconds(1));
76 
77         if (count < 7)
78             val = access_pool ();
79         else
80             val = access_pool (true);
81 
82         printf ("%s (thread = %u) after sleep access_pool returns %d (count=%d)...\n", __FUNCTION__, thread_index, val, count);
83     }
84     printf ("%s (thread index = %u) exiting...\n", __FUNCTION__, thread_index);
85 }
86 
87 
88 int main (int argc, char const *argv[])
89 {
90     g_count = 4;
91     std::thread threads[3];
92 
93     g_char_ptr = new char[10]{};
94 
95     // Create 3 threads
96     for (auto &thread : threads)
97         thread = std::thread{thread_func, std::distance(threads, &thread)};
98 
99     struct {
100         int a;
101         int b;
102         int c;
103     } MyAggregateDataType;
104 
105     printf ("Before turning all three threads loose...\n"); // Set break point at this line.
106     barrier_wait();
107 
108     // Join all of our threads
109     for (auto &thread : threads)
110         thread.join();
111 
112     delete[] g_char_ptr;
113 
114     return 0;
115 }
116