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 // C includes
10*99451b44SJordan Rupprecht #include <stdio.h>
11*99451b44SJordan Rupprecht #include <stdint.h>
12*99451b44SJordan Rupprecht #include <stdlib.h>
13*99451b44SJordan Rupprecht 
14*99451b44SJordan Rupprecht // C++ includes
15*99451b44SJordan Rupprecht #include <chrono>
16*99451b44SJordan Rupprecht #include <mutex>
17*99451b44SJordan Rupprecht #include <random>
18*99451b44SJordan Rupprecht #include <thread>
19*99451b44SJordan Rupprecht 
20*99451b44SJordan Rupprecht std::thread g_thread_1;
21*99451b44SJordan Rupprecht std::thread g_thread_2;
22*99451b44SJordan Rupprecht std::thread g_thread_3;
23*99451b44SJordan Rupprecht std::mutex g_mask_mutex;
24*99451b44SJordan Rupprecht 
25*99451b44SJordan Rupprecht enum MaskAction {
26*99451b44SJordan Rupprecht     eGet,
27*99451b44SJordan Rupprecht     eAssign,
28*99451b44SJordan Rupprecht     eClearBits
29*99451b44SJordan Rupprecht };
30*99451b44SJordan Rupprecht 
31*99451b44SJordan Rupprecht uint32_t mask_access (MaskAction action, uint32_t mask = 0);
32*99451b44SJordan Rupprecht 
33*99451b44SJordan Rupprecht uint32_t
34*99451b44SJordan Rupprecht mask_access (MaskAction action, uint32_t mask)
35*99451b44SJordan Rupprecht {
36*99451b44SJordan Rupprecht     static uint32_t g_mask = 0;
37*99451b44SJordan Rupprecht 
38*99451b44SJordan Rupprecht     std::lock_guard<std::mutex> lock(g_mask_mutex);
39*99451b44SJordan Rupprecht     switch (action)
40*99451b44SJordan Rupprecht     {
41*99451b44SJordan Rupprecht     case eGet:
42*99451b44SJordan Rupprecht         break;
43*99451b44SJordan Rupprecht 
44*99451b44SJordan Rupprecht     case eAssign:
45*99451b44SJordan Rupprecht         g_mask |= mask;
46*99451b44SJordan Rupprecht         break;
47*99451b44SJordan Rupprecht 
48*99451b44SJordan Rupprecht     case eClearBits:
49*99451b44SJordan Rupprecht         g_mask &= ~mask;
50*99451b44SJordan Rupprecht         break;
51*99451b44SJordan Rupprecht     }
52*99451b44SJordan Rupprecht     return g_mask;
53*99451b44SJordan Rupprecht }
54*99451b44SJordan Rupprecht 
55*99451b44SJordan Rupprecht void *
56*99451b44SJordan Rupprecht thread_func (void *arg)
57*99451b44SJordan Rupprecht {
58*99451b44SJordan Rupprecht     uint32_t thread_index = *((uint32_t *)arg);
59*99451b44SJordan Rupprecht     uint32_t thread_mask = (1u << (thread_index));
60*99451b44SJordan Rupprecht     printf ("%s (thread index = %u) startng...\n", __FUNCTION__, thread_index);
61*99451b44SJordan Rupprecht 
62*99451b44SJordan Rupprecht     std::default_random_engine generator;
63*99451b44SJordan Rupprecht     std::uniform_int_distribution<int> distribution(0, 3000000);
64*99451b44SJordan Rupprecht 
65*99451b44SJordan Rupprecht     while (mask_access(eGet) & thread_mask)
66*99451b44SJordan Rupprecht     {
67*99451b44SJordan Rupprecht         // random micro second sleep from zero to 3 seconds
68*99451b44SJordan Rupprecht         int usec = distribution(generator);
69*99451b44SJordan Rupprecht         printf ("%s (thread = %u) doing a usleep (%d)...\n", __FUNCTION__, thread_index, usec);
70*99451b44SJordan Rupprecht 
71*99451b44SJordan Rupprecht         std::chrono::microseconds duration(usec);
72*99451b44SJordan Rupprecht         std::this_thread::sleep_for(duration);
73*99451b44SJordan Rupprecht         printf ("%s (thread = %u) after usleep ...\n", __FUNCTION__, thread_index); // Set break point at this line.
74*99451b44SJordan Rupprecht     }
75*99451b44SJordan Rupprecht     printf ("%s (thread index = %u) exiting...\n", __FUNCTION__, thread_index);
76*99451b44SJordan Rupprecht     return NULL;
77*99451b44SJordan Rupprecht }
78*99451b44SJordan Rupprecht 
79*99451b44SJordan Rupprecht 
80*99451b44SJordan Rupprecht int main (int argc, char const *argv[])
81*99451b44SJordan Rupprecht {
82*99451b44SJordan Rupprecht     uint32_t thread_index_1 = 1;
83*99451b44SJordan Rupprecht     uint32_t thread_index_2 = 2;
84*99451b44SJordan Rupprecht     uint32_t thread_index_3 = 3;
85*99451b44SJordan Rupprecht     uint32_t thread_mask_1 = (1u << thread_index_1);
86*99451b44SJordan Rupprecht     uint32_t thread_mask_2 = (1u << thread_index_2);
87*99451b44SJordan Rupprecht     uint32_t thread_mask_3 = (1u << thread_index_3);
88*99451b44SJordan Rupprecht 
89*99451b44SJordan Rupprecht     // Make a mask that will keep all threads alive
90*99451b44SJordan Rupprecht     mask_access (eAssign, thread_mask_1 | thread_mask_2 | thread_mask_3); // And that line.
91*99451b44SJordan Rupprecht 
92*99451b44SJordan Rupprecht     // Create 3 threads
93*99451b44SJordan Rupprecht     g_thread_1 = std::thread(thread_func, (void*)&thread_index_1);
94*99451b44SJordan Rupprecht     g_thread_2 = std::thread(thread_func, (void*)&thread_index_2);
95*99451b44SJordan Rupprecht     g_thread_3 = std::thread(thread_func, (void*)&thread_index_3);
96*99451b44SJordan Rupprecht 
97*99451b44SJordan Rupprecht     char line[64];
98*99451b44SJordan Rupprecht     while (mask_access(eGet) != 0)
99*99451b44SJordan Rupprecht     {
100*99451b44SJordan Rupprecht         printf ("Enter thread index to kill or ENTER for all:\n");
101*99451b44SJordan Rupprecht         fflush (stdout);
102*99451b44SJordan Rupprecht         // Kill threads by index, or ENTER for all threads
103*99451b44SJordan Rupprecht 
104*99451b44SJordan Rupprecht         if (fgets (line, sizeof(line), stdin))
105*99451b44SJordan Rupprecht         {
106*99451b44SJordan Rupprecht             if (line[0] == '\n' || line[0] == '\r' || line[0] == '\0')
107*99451b44SJordan Rupprecht             {
108*99451b44SJordan Rupprecht                 printf ("Exiting all threads...\n");
109*99451b44SJordan Rupprecht                 break;
110*99451b44SJordan Rupprecht             }
111*99451b44SJordan Rupprecht             int32_t index = strtoul (line, NULL, 0);
112*99451b44SJordan Rupprecht             switch (index)
113*99451b44SJordan Rupprecht             {
114*99451b44SJordan Rupprecht                 case 1: mask_access (eClearBits, thread_mask_1); break;
115*99451b44SJordan Rupprecht                 case 2: mask_access (eClearBits, thread_mask_2); break;
116*99451b44SJordan Rupprecht                 case 3: mask_access (eClearBits, thread_mask_3); break;
117*99451b44SJordan Rupprecht             }
118*99451b44SJordan Rupprecht             continue;
119*99451b44SJordan Rupprecht         }
120*99451b44SJordan Rupprecht 
121*99451b44SJordan Rupprecht         break;
122*99451b44SJordan Rupprecht     }
123*99451b44SJordan Rupprecht 
124*99451b44SJordan Rupprecht     // Clear all thread bits to they all exit
125*99451b44SJordan Rupprecht     mask_access (eClearBits, UINT32_MAX);
126*99451b44SJordan Rupprecht 
127*99451b44SJordan Rupprecht     // Join all of our threads
128*99451b44SJordan Rupprecht     g_thread_1.join();
129*99451b44SJordan Rupprecht     g_thread_2.join();
130*99451b44SJordan Rupprecht     g_thread_3.join();
131*99451b44SJordan Rupprecht 
132*99451b44SJordan Rupprecht     return 0;
133*99451b44SJordan Rupprecht }
134