• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
GetThreadContext(u32 tid)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 
CheckThreadQuantity(ThreadRegistry * registry,uptr exp_total,uptr exp_running,uptr exp_alive)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 
is_detached(u32 tid)42 static bool is_detached(u32 tid) {
43   return (tid % 2 == 0);
44 }
45 
get_uid(u32 tid)46 static uptr get_uid(u32 tid) {
47   return tid * 2;
48 }
49 
HasName(ThreadContextBase * tctx,void * arg)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 
HasUid(ThreadContextBase * tctx,void * arg)55 static bool HasUid(ThreadContextBase *tctx, void *arg) {
56   uptr uid = (uptr)arg;
57   return (tctx->user_id == uid);
58 }
59 
MarkUidAsPresent(ThreadContextBase * tctx,void * arg)60 static void MarkUidAsPresent(ThreadContextBase *tctx, void *arg) {
61   bool *arr = (bool*)arg;
62   arr[tctx->tid] = true;
63 }
64 
TestRegistry(ThreadRegistry * registry,bool has_quarantine)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 
TEST(SanitizerCommon,ThreadRegistryTest)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:
TestThreadContext(int tid)166   explicit TestThreadContext(int tid) : ThreadContextBase(tid) {}
OnJoined(void * arg)167   void OnJoined(void *arg) {
168     uptr shard = (uptr)arg;
169     num_joined[shard]++;
170   }
OnStarted(void * arg)171   void OnStarted(void *arg) {
172     uptr shard = (uptr)arg;
173     num_started[shard]++;
174   }
OnCreated(void * arg)175   void OnCreated(void *arg) {
176     uptr shard = (uptr)arg;
177     num_created[shard]++;
178   }
179 };
180 
181 }  // namespace
182 
RunThread(void * arg)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 
ThreadedTestRegistry(ThreadRegistry * registry)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 
TEST(SanitizerCommon,ThreadRegistryThreadedTest)224 TEST(SanitizerCommon, ThreadRegistryThreadedTest) {
225   ThreadRegistry registry(GetThreadContext<TestThreadContext>,
226                           kThreadsPerShard * kNumShards + 1, 10);
227   ThreadedTestRegistry(&registry);
228 }
229 
230 }  // namespace __sanitizer
231