Revert "[InstCombine] Support gep nuw in icmp folds" (#118698)
[llvm-project.git] / compiler-rt / lib / sanitizer_common / tests / sanitizer_thread_registry_test.cpp
blob6e84ecdfeba683f63cb659de15c07f051cb1b813
1 //===-- sanitizer_thread_registry_test.cpp --------------------------------===//
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 // This file is a part of shared sanitizer runtime.
11 //===----------------------------------------------------------------------===//
12 #include "sanitizer_common/sanitizer_thread_registry.h"
14 #include <iostream>
15 #include <vector>
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
19 #include "sanitizer_common/sanitizer_common.h"
20 #include "sanitizer_common/sanitizer_stackdepot.h"
21 #include "sanitizer_common/sanitizer_stacktrace.h"
22 #include "sanitizer_common/sanitizer_thread_history.h"
23 #include "sanitizer_pthread_wrappers.h"
25 using testing::HasSubstr;
27 namespace __sanitizer {
29 static Mutex tctx_allocator_lock;
30 static LowLevelAllocator tctx_allocator;
32 template<typename TCTX>
33 static ThreadContextBase *GetThreadContext(u32 tid) {
34 Lock l(&tctx_allocator_lock);
35 return new(tctx_allocator) TCTX(tid);
38 static const u32 kMaxRegistryThreads = 1000;
39 static const u32 kRegistryQuarantine = 2;
41 static void CheckThreadQuantity(ThreadRegistry *registry, uptr exp_total,
42 uptr exp_running, uptr exp_alive) {
43 uptr total, running, alive;
44 registry->GetNumberOfThreads(&total, &running, &alive);
45 EXPECT_EQ(exp_total, total);
46 EXPECT_EQ(exp_running, running);
47 EXPECT_EQ(exp_alive, alive);
50 static bool is_detached(u32 tid) {
51 return (tid % 2 == 0);
54 static uptr get_uid(u32 tid) {
55 return tid * 2;
58 static bool HasName(ThreadContextBase *tctx, void *arg) {
59 char *name = (char*)arg;
60 return (0 == internal_strcmp(tctx->name, name));
63 static bool HasUid(ThreadContextBase *tctx, void *arg) {
64 uptr uid = (uptr)arg;
65 return (tctx->user_id == uid);
68 static void MarkUidAsPresent(ThreadContextBase *tctx, void *arg) {
69 bool *arr = (bool*)arg;
70 arr[tctx->tid] = true;
73 static void TestRegistry(ThreadRegistry *registry, bool has_quarantine) {
74 // Create and start a main thread.
75 EXPECT_EQ(0U, registry->CreateThread(get_uid(0), true, -1, 0, nullptr));
76 registry->StartThread(0, 0, ThreadType::Regular, 0);
77 // Create a bunch of threads.
78 for (u32 i = 1; i <= 10; i++) {
79 EXPECT_EQ(i, registry->CreateThread(get_uid(i), is_detached(i), 100 + i,
80 200 + i, nullptr));
82 CheckThreadQuantity(registry, 11, 1, 11);
83 // Start some of them.
84 for (u32 i = 1; i <= 5; i++) {
85 registry->StartThread(i, 0, ThreadType::Regular, 0);
87 CheckThreadQuantity(registry, 11, 6, 11);
88 // Finish, create and start more threads.
89 for (u32 i = 1; i <= 5; i++) {
90 registry->FinishThread(i);
91 if (!is_detached(i))
92 registry->JoinThread(i, 0);
94 for (u32 i = 6; i <= 10; i++) {
95 registry->StartThread(i, 0, ThreadType::Regular, 0);
97 std::vector<u32> new_tids;
98 for (u32 i = 11; i <= 15; i++) {
99 new_tids.push_back(
100 registry->CreateThread(get_uid(i), is_detached(i), 0, 0, nullptr));
102 ASSERT_LE(kRegistryQuarantine, 5U);
103 u32 exp_total = 16 - (has_quarantine ? 5 - kRegistryQuarantine : 0);
104 CheckThreadQuantity(registry, exp_total, 6, 11);
105 // Test SetThreadName and FindThread.
106 registry->SetThreadName(6, "six");
107 registry->SetThreadName(7, "seven");
108 EXPECT_EQ(7U, registry->FindThread(HasName, (void *)"seven"));
109 EXPECT_EQ(kInvalidTid, registry->FindThread(HasName, (void *)"none"));
110 EXPECT_EQ(0U, registry->FindThread(HasUid, (void *)get_uid(0)));
111 EXPECT_EQ(10U, registry->FindThread(HasUid, (void *)get_uid(10)));
112 EXPECT_EQ(kInvalidTid, registry->FindThread(HasUid, (void *)0x1234));
113 EXPECT_EQ(7U,
114 registry->FindThread([](ThreadContextBase *tctx,
115 void *) { return tctx->parent_tid == 107; },
116 nullptr));
117 EXPECT_EQ(8U,
118 registry->FindThread([](ThreadContextBase *tctx,
119 void *) { return tctx->stack_id == 208; },
120 nullptr));
121 // Detach and finish and join remaining threads.
122 for (u32 i = 6; i <= 10; i++) {
123 registry->DetachThread(i, 0);
124 registry->FinishThread(i);
126 for (u32 i = 0; i < new_tids.size(); i++) {
127 u32 tid = new_tids[i];
128 registry->StartThread(tid, 0, ThreadType::Regular, 0);
129 registry->DetachThread(tid, 0);
130 registry->FinishThread(tid);
132 CheckThreadQuantity(registry, exp_total, 1, 1);
133 // Test methods that require the caller to hold a ThreadRegistryLock.
134 bool has_tid[16];
135 internal_memset(&has_tid[0], 0, sizeof(has_tid));
137 ThreadRegistryLock l(registry);
138 registry->RunCallbackForEachThreadLocked(MarkUidAsPresent, &has_tid[0]);
140 for (u32 i = 0; i < exp_total; i++) {
141 EXPECT_TRUE(has_tid[i]);
144 ThreadRegistryLock l(registry);
145 registry->CheckLocked();
146 ThreadContextBase *main_thread = registry->GetThreadLocked(0);
147 EXPECT_EQ(main_thread, registry->FindThreadContextLocked(
148 HasUid, (void*)get_uid(0)));
150 EXPECT_EQ(11U, registry->GetMaxAliveThreads());
153 TEST(SanitizerCommon, ThreadRegistryTest) {
154 ThreadRegistry quarantine_registry(GetThreadContext<ThreadContextBase>,
155 kMaxRegistryThreads, kRegistryQuarantine,
157 TestRegistry(&quarantine_registry, true);
159 ThreadRegistry no_quarantine_registry(GetThreadContext<ThreadContextBase>,
160 kMaxRegistryThreads,
161 kMaxRegistryThreads, 0);
162 TestRegistry(&no_quarantine_registry, false);
165 static const int kThreadsPerShard = 20;
166 static const int kNumShards = 25;
168 static int num_created[kNumShards + 1];
169 static int num_started[kNumShards + 1];
170 static int num_joined[kNumShards + 1];
172 namespace {
174 struct RunThreadArgs {
175 ThreadRegistry *registry;
176 uptr shard; // started from 1.
179 class TestThreadContext final : public ThreadContextBase {
180 public:
181 explicit TestThreadContext(int tid) : ThreadContextBase(tid) {}
182 void OnJoined(void *arg) {
183 uptr shard = (uptr)arg;
184 num_joined[shard]++;
186 void OnStarted(void *arg) {
187 uptr shard = (uptr)arg;
188 num_started[shard]++;
190 void OnCreated(void *arg) {
191 uptr shard = (uptr)arg;
192 num_created[shard]++;
196 } // namespace
198 void *RunThread(void *arg) {
199 RunThreadArgs *args = static_cast<RunThreadArgs*>(arg);
200 std::vector<int> tids;
201 for (int i = 0; i < kThreadsPerShard; i++)
202 tids.push_back(
203 args->registry->CreateThread(0, false, 0, (void*)args->shard));
204 for (int i = 0; i < kThreadsPerShard; i++)
205 args->registry->StartThread(tids[i], 0, ThreadType::Regular,
206 (void*)args->shard);
207 for (int i = 0; i < kThreadsPerShard; i++)
208 args->registry->FinishThread(tids[i]);
209 for (int i = 0; i < kThreadsPerShard; i++)
210 args->registry->JoinThread(tids[i], (void*)args->shard);
211 return 0;
214 static void ThreadedTestRegistry(ThreadRegistry *registry) {
215 // Create and start a main thread.
216 EXPECT_EQ(0U, registry->CreateThread(0, true, -1, 0));
217 registry->StartThread(0, 0, ThreadType::Regular, 0);
218 pthread_t threads[kNumShards];
219 RunThreadArgs args[kNumShards];
220 for (int i = 0; i < kNumShards; i++) {
221 args[i].registry = registry;
222 args[i].shard = i + 1;
223 PTHREAD_CREATE(&threads[i], 0, RunThread, &args[i]);
225 for (int i = 0; i < kNumShards; i++) {
226 PTHREAD_JOIN(threads[i], 0);
228 // Check that each thread created/started/joined correct amount
229 // of "threads" in thread_registry.
230 EXPECT_EQ(1, num_created[0]);
231 EXPECT_EQ(1, num_started[0]);
232 EXPECT_EQ(0, num_joined[0]);
233 for (int i = 1; i <= kNumShards; i++) {
234 EXPECT_EQ(kThreadsPerShard, num_created[i]);
235 EXPECT_EQ(kThreadsPerShard, num_started[i]);
236 EXPECT_EQ(kThreadsPerShard, num_joined[i]);
240 TEST(SanitizerCommon, ThreadRegistryThreadedTest) {
241 memset(&num_created, 0, sizeof(num_created));
242 memset(&num_started, 0, sizeof(num_created));
243 memset(&num_joined, 0, sizeof(num_created));
245 ThreadRegistry registry(GetThreadContext<TestThreadContext>,
246 kThreadsPerShard * kNumShards + 1, 10, 0);
247 ThreadedTestRegistry(&registry);
250 TEST(SanitizerCommon, PrintThreadHistory) {
251 ThreadRegistry registry(GetThreadContext<TestThreadContext>,
252 kThreadsPerShard * kNumShards + 1, 10, 0);
254 UNINITIALIZED BufferedStackTrace stack1;
255 stack1.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), nullptr, false,
256 /*max_depth=*/1);
258 UNINITIALIZED BufferedStackTrace stack2;
259 stack2.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), nullptr, false,
260 /*max_depth=*/1);
262 EXPECT_EQ(0U, registry.CreateThread(0, true, -1, 0, nullptr));
263 for (int i = 0; i < 5; i++) {
264 registry.CreateThread(0, true, 0, StackDepotPut(stack1), nullptr);
265 registry.CreateThread(0, true, 0, StackDepotPut(stack2), nullptr);
268 InternalScopedString out;
269 PrintThreadHistory(registry, out);
271 std::string substrings[] = {
272 "Thread T0/0 was created by T-1",
273 "<empty stack>",
275 "Thread T1/0 was created by T0/0",
276 "Thread T3/0 was created by T0/0",
277 "Thread T5/0 was created by T0/0",
278 "Thread T7/0 was created by T0/0",
279 "Thread T9/0 was created by T0/0",
280 "#0 0x",
282 "Thread T2/0 was created by T0/0",
283 "Thread T4/0 was created by T0/0",
284 "Thread T6/0 was created by T0/0",
285 "Thread T8/0 was created by T0/0",
286 "Thread T10/0 was created by T0/0",
287 "#0 0x",
291 std::stringstream ss(out.data());
292 std::string line;
294 for (auto substr : substrings) {
295 std::getline(ss, line);
296 EXPECT_THAT(line, HasSubstr(substr)) << line;
299 EXPECT_FALSE(std::getline(ss, line)) << "Unmatched line: " << line;
302 } // namespace __sanitizer