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