[clang][extract-api] Emit "navigator" property of "name" in SymbolGraph
[llvm-project.git] / compiler-rt / lib / sanitizer_common / tests / sanitizer_thread_registry_test.cpp
blob8ecf916ca5a9f6b3520395dd28350efb394e1201
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 "sanitizer_pthread_wrappers.h"
16 #include "gtest/gtest.h"
18 #include <vector>
20 namespace __sanitizer {
22 static Mutex tctx_allocator_lock;
23 static LowLevelAllocator tctx_allocator;
25 template<typename TCTX>
26 static ThreadContextBase *GetThreadContext(u32 tid) {
27 Lock l(&tctx_allocator_lock);
28 return new(tctx_allocator) TCTX(tid);
31 static const u32 kMaxRegistryThreads = 1000;
32 static const u32 kRegistryQuarantine = 2;
34 static void CheckThreadQuantity(ThreadRegistry *registry, uptr exp_total,
35 uptr exp_running, uptr exp_alive) {
36 uptr total, running, alive;
37 registry->GetNumberOfThreads(&total, &running, &alive);
38 EXPECT_EQ(exp_total, total);
39 EXPECT_EQ(exp_running, running);
40 EXPECT_EQ(exp_alive, alive);
43 static bool is_detached(u32 tid) {
44 return (tid % 2 == 0);
47 static uptr get_uid(u32 tid) {
48 return tid * 2;
51 static bool HasName(ThreadContextBase *tctx, void *arg) {
52 char *name = (char*)arg;
53 return (0 == internal_strcmp(tctx->name, name));
56 static bool HasUid(ThreadContextBase *tctx, void *arg) {
57 uptr uid = (uptr)arg;
58 return (tctx->user_id == uid);
61 static void MarkUidAsPresent(ThreadContextBase *tctx, void *arg) {
62 bool *arr = (bool*)arg;
63 arr[tctx->tid] = true;
66 static void TestRegistry(ThreadRegistry *registry, bool has_quarantine) {
67 // Create and start a main thread.
68 EXPECT_EQ(0U, registry->CreateThread(get_uid(0), true, -1, 0));
69 registry->StartThread(0, 0, ThreadType::Regular, 0);
70 // Create a bunch of threads.
71 for (u32 i = 1; i <= 10; i++) {
72 EXPECT_EQ(i, registry->CreateThread(get_uid(i), is_detached(i), 0, 0));
74 CheckThreadQuantity(registry, 11, 1, 11);
75 // Start some of them.
76 for (u32 i = 1; i <= 5; i++) {
77 registry->StartThread(i, 0, ThreadType::Regular, 0);
79 CheckThreadQuantity(registry, 11, 6, 11);
80 // Finish, create and start more threads.
81 for (u32 i = 1; i <= 5; i++) {
82 registry->FinishThread(i);
83 if (!is_detached(i))
84 registry->JoinThread(i, 0);
86 for (u32 i = 6; i <= 10; i++) {
87 registry->StartThread(i, 0, ThreadType::Regular, 0);
89 std::vector<u32> new_tids;
90 for (u32 i = 11; i <= 15; i++) {
91 new_tids.push_back(
92 registry->CreateThread(get_uid(i), is_detached(i), 0, 0));
94 ASSERT_LE(kRegistryQuarantine, 5U);
95 u32 exp_total = 16 - (has_quarantine ? 5 - kRegistryQuarantine : 0);
96 CheckThreadQuantity(registry, exp_total, 6, 11);
97 // Test SetThreadName and FindThread.
98 registry->SetThreadName(6, "six");
99 registry->SetThreadName(7, "seven");
100 EXPECT_EQ(7U, registry->FindThread(HasName, (void*)"seven"));
101 EXPECT_EQ(kInvalidTid, registry->FindThread(HasName, (void *)"none"));
102 EXPECT_EQ(0U, registry->FindThread(HasUid, (void*)get_uid(0)));
103 EXPECT_EQ(10U, registry->FindThread(HasUid, (void*)get_uid(10)));
104 EXPECT_EQ(kInvalidTid, registry->FindThread(HasUid, (void *)0x1234));
105 // Detach and finish and join remaining threads.
106 for (u32 i = 6; i <= 10; i++) {
107 registry->DetachThread(i, 0);
108 registry->FinishThread(i);
110 for (u32 i = 0; i < new_tids.size(); i++) {
111 u32 tid = new_tids[i];
112 registry->StartThread(tid, 0, ThreadType::Regular, 0);
113 registry->DetachThread(tid, 0);
114 registry->FinishThread(tid);
116 CheckThreadQuantity(registry, exp_total, 1, 1);
117 // Test methods that require the caller to hold a ThreadRegistryLock.
118 bool has_tid[16];
119 internal_memset(&has_tid[0], 0, sizeof(has_tid));
121 ThreadRegistryLock l(registry);
122 registry->RunCallbackForEachThreadLocked(MarkUidAsPresent, &has_tid[0]);
124 for (u32 i = 0; i < exp_total; i++) {
125 EXPECT_TRUE(has_tid[i]);
128 ThreadRegistryLock l(registry);
129 registry->CheckLocked();
130 ThreadContextBase *main_thread = registry->GetThreadLocked(0);
131 EXPECT_EQ(main_thread, registry->FindThreadContextLocked(
132 HasUid, (void*)get_uid(0)));
134 EXPECT_EQ(11U, registry->GetMaxAliveThreads());
137 TEST(SanitizerCommon, ThreadRegistryTest) {
138 ThreadRegistry quarantine_registry(GetThreadContext<ThreadContextBase>,
139 kMaxRegistryThreads, kRegistryQuarantine,
141 TestRegistry(&quarantine_registry, true);
143 ThreadRegistry no_quarantine_registry(GetThreadContext<ThreadContextBase>,
144 kMaxRegistryThreads,
145 kMaxRegistryThreads, 0);
146 TestRegistry(&no_quarantine_registry, false);
149 static const int kThreadsPerShard = 20;
150 static const int kNumShards = 25;
152 static int num_created[kNumShards + 1];
153 static int num_started[kNumShards + 1];
154 static int num_joined[kNumShards + 1];
156 namespace {
158 struct RunThreadArgs {
159 ThreadRegistry *registry;
160 uptr shard; // started from 1.
163 class TestThreadContext final : public ThreadContextBase {
164 public:
165 explicit TestThreadContext(int tid) : ThreadContextBase(tid) {}
166 void OnJoined(void *arg) {
167 uptr shard = (uptr)arg;
168 num_joined[shard]++;
170 void OnStarted(void *arg) {
171 uptr shard = (uptr)arg;
172 num_started[shard]++;
174 void OnCreated(void *arg) {
175 uptr shard = (uptr)arg;
176 num_created[shard]++;
180 } // namespace
182 void *RunThread(void *arg) {
183 RunThreadArgs *args = static_cast<RunThreadArgs*>(arg);
184 std::vector<int> tids;
185 for (int i = 0; i < kThreadsPerShard; i++)
186 tids.push_back(
187 args->registry->CreateThread(0, false, 0, (void*)args->shard));
188 for (int i = 0; i < kThreadsPerShard; i++)
189 args->registry->StartThread(tids[i], 0, ThreadType::Regular,
190 (void*)args->shard);
191 for (int i = 0; i < kThreadsPerShard; i++)
192 args->registry->FinishThread(tids[i]);
193 for (int i = 0; i < kThreadsPerShard; i++)
194 args->registry->JoinThread(tids[i], (void*)args->shard);
195 return 0;
198 static void ThreadedTestRegistry(ThreadRegistry *registry) {
199 // Create and start a main thread.
200 EXPECT_EQ(0U, registry->CreateThread(0, true, -1, 0));
201 registry->StartThread(0, 0, ThreadType::Regular, 0);
202 pthread_t threads[kNumShards];
203 RunThreadArgs args[kNumShards];
204 for (int i = 0; i < kNumShards; i++) {
205 args[i].registry = registry;
206 args[i].shard = i + 1;
207 PTHREAD_CREATE(&threads[i], 0, RunThread, &args[i]);
209 for (int i = 0; i < kNumShards; i++) {
210 PTHREAD_JOIN(threads[i], 0);
212 // Check that each thread created/started/joined correct amount
213 // of "threads" in thread_registry.
214 EXPECT_EQ(1, num_created[0]);
215 EXPECT_EQ(1, num_started[0]);
216 EXPECT_EQ(0, num_joined[0]);
217 for (int i = 1; i <= kNumShards; i++) {
218 EXPECT_EQ(kThreadsPerShard, num_created[i]);
219 EXPECT_EQ(kThreadsPerShard, num_started[i]);
220 EXPECT_EQ(kThreadsPerShard, num_joined[i]);
224 TEST(SanitizerCommon, ThreadRegistryThreadedTest) {
225 memset(&num_created, 0, sizeof(num_created));
226 memset(&num_started, 0, sizeof(num_created));
227 memset(&num_joined, 0, sizeof(num_created));
229 ThreadRegistry registry(GetThreadContext<TestThreadContext>,
230 kThreadsPerShard * kNumShards + 1, 10, 0);
231 ThreadedTestRegistry(&registry);
234 } // namespace __sanitizer