1 //===-- sanitizer_thread_registry_test.cc ---------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is a part of shared sanitizer runtime. 11 // 12 //===----------------------------------------------------------------------===// 13 #include "sanitizer_common/sanitizer_thread_registry.h" 14 #include "gtest/gtest.h" 15 16 #include <vector> 17 18 namespace __sanitizer { 19 20 static BlockingMutex tctx_allocator_lock(LINKER_INITIALIZED); 21 static LowLevelAllocator tctx_allocator; 22 23 template<typename TCTX> 24 static ThreadContextBase *GetThreadContext(u32 tid) { 25 BlockingMutexLock l(&tctx_allocator_lock); 26 void *mem = tctx_allocator.Allocate(sizeof(TCTX)); 27 return new(mem) TCTX(tid); 28 } 29 30 static const u32 kMaxRegistryThreads = 1000; 31 static const u32 kRegistryQuarantine = 2; 32 33 static void CheckThreadQuantity(ThreadRegistry *registry, uptr exp_total, 34 uptr exp_running, uptr exp_alive) { 35 uptr total, running, alive; 36 registry->GetNumberOfThreads(&total, &running, &alive); 37 EXPECT_EQ(exp_total, total); 38 EXPECT_EQ(exp_running, running); 39 EXPECT_EQ(exp_alive, alive); 40 } 41 42 static bool is_detached(u32 tid) { 43 return (tid % 2 == 0); 44 } 45 46 static uptr get_uid(u32 tid) { 47 return tid * 2; 48 } 49 50 static bool HasName(ThreadContextBase *tctx, void *arg) { 51 char *name = (char*)arg; 52 return (tctx->name && 0 == internal_strcmp(tctx->name, name)); 53 } 54 55 static bool HasUid(ThreadContextBase *tctx, void *arg) { 56 uptr uid = (uptr)arg; 57 return (tctx->user_id == uid); 58 } 59 60 static void MarkUidAsPresent(ThreadContextBase *tctx, void *arg) { 61 bool *arr = (bool*)arg; 62 arr[tctx->tid] = true; 63 } 64 65 static void TestRegistry(ThreadRegistry *registry, bool has_quarantine) { 66 // Create and start a main thread. 67 EXPECT_EQ(0U, registry->CreateThread(get_uid(0), true, -1, 0)); 68 registry->StartThread(0, 0, 0); 69 // Create a bunch of threads. 70 for (u32 i = 1; i <= 10; i++) { 71 EXPECT_EQ(i, registry->CreateThread(get_uid(i), is_detached(i), 0, 0)); 72 } 73 CheckThreadQuantity(registry, 11, 1, 11); 74 // Start some of them. 75 for (u32 i = 1; i <= 5; i++) { 76 registry->StartThread(i, 0, 0); 77 } 78 CheckThreadQuantity(registry, 11, 6, 11); 79 // Finish, create and start more threads. 80 for (u32 i = 1; i <= 5; i++) { 81 registry->FinishThread(i); 82 if (!is_detached(i)) 83 registry->JoinThread(i, 0); 84 } 85 for (u32 i = 6; i <= 10; i++) { 86 registry->StartThread(i, 0, 0); 87 } 88 std::vector<u32> new_tids; 89 for (u32 i = 11; i <= 15; i++) { 90 new_tids.push_back( 91 registry->CreateThread(get_uid(i), is_detached(i), 0, 0)); 92 } 93 ASSERT_LE(kRegistryQuarantine, 5U); 94 u32 exp_total = 16 - (has_quarantine ? 5 - kRegistryQuarantine : 0); 95 CheckThreadQuantity(registry, exp_total, 6, 11); 96 // Test SetThreadName and FindThread. 97 registry->SetThreadName(6, "six"); 98 registry->SetThreadName(7, "seven"); 99 EXPECT_EQ(7U, registry->FindThread(HasName, (void*)"seven")); 100 EXPECT_EQ(ThreadRegistry::kUnknownTid, 101 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(ThreadRegistry::kUnknownTid, 105 registry->FindThread(HasUid, (void*)0x1234)); 106 // Detach and finish and join remaining threads. 107 for (u32 i = 6; i <= 10; i++) { 108 registry->DetachThread(i); 109 registry->FinishThread(i); 110 } 111 for (u32 i = 0; i < new_tids.size(); i++) { 112 u32 tid = new_tids[i]; 113 registry->StartThread(tid, 0, 0); 114 registry->DetachThread(tid); 115 registry->FinishThread(tid); 116 } 117 CheckThreadQuantity(registry, exp_total, 1, 1); 118 // Test methods that require the caller to hold a ThreadRegistryLock. 119 bool has_tid[16]; 120 internal_memset(&has_tid[0], 0, sizeof(has_tid)); 121 { 122 ThreadRegistryLock l(registry); 123 registry->RunCallbackForEachThreadLocked(MarkUidAsPresent, &has_tid[0]); 124 } 125 for (u32 i = 0; i < exp_total; i++) { 126 EXPECT_TRUE(has_tid[i]); 127 } 128 { 129 ThreadRegistryLock l(registry); 130 registry->CheckLocked(); 131 ThreadContextBase *main_thread = registry->GetThreadLocked(0); 132 EXPECT_EQ(main_thread, registry->FindThreadContextLocked( 133 HasUid, (void*)get_uid(0))); 134 } 135 EXPECT_EQ(11U, registry->GetMaxAliveThreads()); 136 } 137 138 TEST(SanitizerCommon, ThreadRegistryTest) { 139 ThreadRegistry quarantine_registry(GetThreadContext<ThreadContextBase>, 140 kMaxRegistryThreads, 141 kRegistryQuarantine); 142 TestRegistry(&quarantine_registry, true); 143 144 ThreadRegistry no_quarantine_registry(GetThreadContext<ThreadContextBase>, 145 kMaxRegistryThreads, 146 kMaxRegistryThreads); 147 TestRegistry(&no_quarantine_registry, false); 148 } 149 150 static const int kThreadsPerShard = 20; 151 static const int kNumShards = 25; 152 153 static int num_created[kNumShards + 1]; 154 static int num_started[kNumShards + 1]; 155 static int num_joined[kNumShards + 1]; 156 157 namespace { 158 159 struct RunThreadArgs { 160 ThreadRegistry *registry; 161 uptr shard; // started from 1. 162 }; 163 164 class TestThreadContext : public ThreadContextBase { 165 public: 166 explicit TestThreadContext(int tid) : ThreadContextBase(tid) {} 167 void OnJoined(void *arg) { 168 uptr shard = (uptr)arg; 169 num_joined[shard]++; 170 } 171 void OnStarted(void *arg) { 172 uptr shard = (uptr)arg; 173 num_started[shard]++; 174 } 175 void OnCreated(void *arg) { 176 uptr shard = (uptr)arg; 177 num_created[shard]++; 178 } 179 }; 180 181 } // namespace 182 183 void *RunThread(void *arg) { 184 RunThreadArgs *args = static_cast<RunThreadArgs*>(arg); 185 std::vector<int> tids; 186 for (int i = 0; i < kThreadsPerShard; i++) 187 tids.push_back( 188 args->registry->CreateThread(0, false, 0, (void*)args->shard)); 189 for (int i = 0; i < kThreadsPerShard; i++) 190 args->registry->StartThread(tids[i], 0, (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 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, 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 224 TEST(SanitizerCommon, ThreadRegistryThreadedTest) { 225 ThreadRegistry registry(GetThreadContext<TestThreadContext>, 226 kThreadsPerShard * kNumShards + 1, 10); 227 ThreadedTestRegistry(®istry); 228 } 229 230 } // namespace __sanitizer 231