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