sanitizer_thread_registry_test.cpp revision 1.1.1.3
1112158Sdas//===-- sanitizer_thread_registry_test.cpp --------------------------------===// 2112158Sdas// 3112158Sdas// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4112158Sdas// See https://llvm.org/LICENSE.txt for license information. 5112158Sdas// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6112158Sdas// 7112158Sdas//===----------------------------------------------------------------------===// 8112158Sdas// 9112158Sdas// This file is a part of shared sanitizer runtime. 10112158Sdas// 11112158Sdas//===----------------------------------------------------------------------===// 12112158Sdas#include "sanitizer_common/sanitizer_thread_registry.h" 13112158Sdas 14112158Sdas#include "sanitizer_pthread_wrappers.h" 15112158Sdas 16112158Sdas#include "gtest/gtest.h" 17112158Sdas 18112158Sdas#include <vector> 19112158Sdas 20112158Sdasnamespace __sanitizer { 21112158Sdas 22112158Sdasstatic Mutex tctx_allocator_lock; 23112158Sdasstatic LowLevelAllocator tctx_allocator; 24112158Sdas 25112158Sdastemplate<typename TCTX> 26112158Sdasstatic ThreadContextBase *GetThreadContext(u32 tid) { 27112158Sdas Lock l(&tctx_allocator_lock); 28112158Sdas return new(tctx_allocator) TCTX(tid); 29165743Sdas} 30165743Sdas 31112158Sdasstatic const u32 kMaxRegistryThreads = 1000; 32112158Sdasstatic const u32 kRegistryQuarantine = 2; 33112158Sdas 34112158Sdasstatic void CheckThreadQuantity(ThreadRegistry *registry, uptr exp_total, 35112158Sdas uptr exp_running, uptr exp_alive) { 36112158Sdas uptr total, running, alive; 37112158Sdas registry->GetNumberOfThreads(&total, &running, &alive); 38112158Sdas EXPECT_EQ(exp_total, total); 39112158Sdas EXPECT_EQ(exp_running, running); 40112158Sdas EXPECT_EQ(exp_alive, alive); 41112158Sdas} 42112158Sdas 43112158Sdasstatic bool is_detached(u32 tid) { 44112158Sdas return (tid % 2 == 0); 45112158Sdas} 46112158Sdas 47112158Sdasstatic uptr get_uid(u32 tid) { 48112158Sdas return tid * 2; 49112158Sdas} 50112158Sdas 51112158Sdasstatic bool HasName(ThreadContextBase *tctx, void *arg) { 52112158Sdas char *name = (char*)arg; 53112158Sdas return (0 == internal_strcmp(tctx->name, name)); 54112158Sdas} 55112158Sdas 56112158Sdasstatic bool HasUid(ThreadContextBase *tctx, void *arg) { 57165743Sdas uptr uid = (uptr)arg; 58112158Sdas return (tctx->user_id == uid); 59112158Sdas} 60112158Sdas 61112158Sdasstatic void MarkUidAsPresent(ThreadContextBase *tctx, void *arg) { 62112158Sdas bool *arr = (bool*)arg; 63112158Sdas arr[tctx->tid] = true; 64112158Sdas} 65112158Sdas 66112158Sdasstatic void TestRegistry(ThreadRegistry *registry, bool has_quarantine) { 67112158Sdas // Create and start a main thread. 68112158Sdas EXPECT_EQ(0U, registry->CreateThread(get_uid(0), true, -1, 0)); 69112158Sdas registry->StartThread(0, 0, ThreadType::Regular, 0); 70112158Sdas // Create a bunch of threads. 71112158Sdas for (u32 i = 1; i <= 10; i++) { 72112158Sdas EXPECT_EQ(i, registry->CreateThread(get_uid(i), is_detached(i), 0, 0)); 73112158Sdas } 74112158Sdas CheckThreadQuantity(registry, 11, 1, 11); 75112158Sdas // Start some of them. 76112158Sdas for (u32 i = 1; i <= 5; i++) { 77112158Sdas registry->StartThread(i, 0, ThreadType::Regular, 0); 78112158Sdas } 79112158Sdas CheckThreadQuantity(registry, 11, 6, 11); 80112158Sdas // Finish, create and start more threads. 81112158Sdas for (u32 i = 1; i <= 5; i++) { 82112158Sdas registry->FinishThread(i); 83112158Sdas if (!is_detached(i)) 84165743Sdas registry->JoinThread(i, 0); 85165743Sdas } 86165743Sdas for (u32 i = 6; i <= 10; i++) { 87112158Sdas registry->StartThread(i, 0, ThreadType::Regular, 0); 88112158Sdas } 89112158Sdas std::vector<u32> new_tids; 90112158Sdas for (u32 i = 11; i <= 15; i++) { 91112158Sdas new_tids.push_back( 92 registry->CreateThread(get_uid(i), is_detached(i), 0, 0)); 93 } 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); 109 } 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); 115 } 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)); 120 { 121 ThreadRegistryLock l(registry); 122 registry->RunCallbackForEachThreadLocked(MarkUidAsPresent, &has_tid[0]); 123 } 124 for (u32 i = 0; i < exp_total; i++) { 125 EXPECT_TRUE(has_tid[i]); 126 } 127 { 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))); 133 } 134 EXPECT_EQ(11U, registry->GetMaxAliveThreads()); 135} 136 137TEST(SanitizerCommon, ThreadRegistryTest) { 138 ThreadRegistry quarantine_registry(GetThreadContext<ThreadContextBase>, 139 kMaxRegistryThreads, kRegistryQuarantine, 140 0); 141 TestRegistry(&quarantine_registry, true); 142 143 ThreadRegistry no_quarantine_registry(GetThreadContext<ThreadContextBase>, 144 kMaxRegistryThreads, 145 kMaxRegistryThreads, 0); 146 TestRegistry(&no_quarantine_registry, false); 147} 148 149static const int kThreadsPerShard = 20; 150static const int kNumShards = 25; 151 152static int num_created[kNumShards + 1]; 153static int num_started[kNumShards + 1]; 154static int num_joined[kNumShards + 1]; 155 156namespace { 157 158struct RunThreadArgs { 159 ThreadRegistry *registry; 160 uptr shard; // started from 1. 161}; 162 163class 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]++; 169 } 170 void OnStarted(void *arg) { 171 uptr shard = (uptr)arg; 172 num_started[shard]++; 173 } 174 void OnCreated(void *arg) { 175 uptr shard = (uptr)arg; 176 num_created[shard]++; 177 } 178}; 179 180} // namespace 181 182void *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; 196} 197 198static 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]); 208 } 209 for (int i = 0; i < kNumShards; i++) { 210 PTHREAD_JOIN(threads[i], 0); 211 } 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]); 221 } 222} 223 224TEST(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)); 228 229 ThreadRegistry registry(GetThreadContext<TestThreadContext>, 230 kThreadsPerShard * kNumShards + 1, 10, 0); 231 ThreadedTestRegistry(®istry); 232} 233 234} // namespace __sanitizer 235