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