• 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 
15 #include "sanitizer_pthread_wrappers.h"
16 
17 #include "gtest/gtest.h"
18 
19 #include <vector>
20 
21 namespace __sanitizer {
22 
23 static BlockingMutex tctx_allocator_lock(LINKER_INITIALIZED);
24 static LowLevelAllocator tctx_allocator;
25 
26 template<typename TCTX>
GetThreadContext(u32 tid)27 static ThreadContextBase *GetThreadContext(u32 tid) {
28   BlockingMutexLock l(&tctx_allocator_lock);
29   return new(tctx_allocator) TCTX(tid);
30 }
31 
32 static const u32 kMaxRegistryThreads = 1000;
33 static const u32 kRegistryQuarantine = 2;
34 
CheckThreadQuantity(ThreadRegistry * registry,uptr exp_total,uptr exp_running,uptr exp_alive)35 static 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 
is_detached(u32 tid)44 static bool is_detached(u32 tid) {
45   return (tid % 2 == 0);
46 }
47 
get_uid(u32 tid)48 static uptr get_uid(u32 tid) {
49   return tid * 2;
50 }
51 
HasName(ThreadContextBase * tctx,void * arg)52 static bool HasName(ThreadContextBase *tctx, void *arg) {
53   char *name = (char*)arg;
54   return (0 == internal_strcmp(tctx->name, name));
55 }
56 
HasUid(ThreadContextBase * tctx,void * arg)57 static bool HasUid(ThreadContextBase *tctx, void *arg) {
58   uptr uid = (uptr)arg;
59   return (tctx->user_id == uid);
60 }
61 
MarkUidAsPresent(ThreadContextBase * tctx,void * arg)62 static void MarkUidAsPresent(ThreadContextBase *tctx, void *arg) {
63   bool *arr = (bool*)arg;
64   arr[tctx->tid] = true;
65 }
66 
TestRegistry(ThreadRegistry * registry,bool has_quarantine)67 static 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, 0);
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, 0);
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 
TEST(SanitizerCommon,ThreadRegistryTest)140 TEST(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 
152 static const int kThreadsPerShard = 20;
153 static const int kNumShards = 25;
154 
155 static int num_created[kNumShards + 1];
156 static int num_started[kNumShards + 1];
157 static int num_joined[kNumShards + 1];
158 
159 namespace {
160 
161 struct RunThreadArgs {
162   ThreadRegistry *registry;
163   uptr shard;  // started from 1.
164 };
165 
166 class TestThreadContext : public ThreadContextBase {
167  public:
TestThreadContext(int tid)168   explicit TestThreadContext(int tid) : ThreadContextBase(tid) {}
OnJoined(void * arg)169   void OnJoined(void *arg) {
170     uptr shard = (uptr)arg;
171     num_joined[shard]++;
172   }
OnStarted(void * arg)173   void OnStarted(void *arg) {
174     uptr shard = (uptr)arg;
175     num_started[shard]++;
176   }
OnCreated(void * arg)177   void OnCreated(void *arg) {
178     uptr shard = (uptr)arg;
179     num_created[shard]++;
180   }
181 };
182 
183 }  // namespace
184 
RunThread(void * arg)185 void *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 
ThreadedTestRegistry(ThreadRegistry * registry)200 static 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 
TEST(SanitizerCommon,ThreadRegistryThreadedTest)226 TEST(SanitizerCommon, ThreadRegistryThreadedTest) {
227   memset(&num_created, 0, sizeof(num_created));
228   memset(&num_started, 0, sizeof(num_created));
229   memset(&num_joined, 0, sizeof(num_created));
230 
231   ThreadRegistry registry(GetThreadContext<TestThreadContext>,
232                           kThreadsPerShard * kNumShards + 1, 10);
233   ThreadedTestRegistry(&registry);
234 }
235 
236 }  // namespace __sanitizer
237