Home | History | Annotate | Download | only in tests
      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>
     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 
     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 
     44 static bool is_detached(u32 tid) {
     45   return (tid % 2 == 0);
     46 }
     47 
     48 static uptr get_uid(u32 tid) {
     49   return tid * 2;
     50 }
     51 
     52 static bool HasName(ThreadContextBase *tctx, void *arg) {
     53   char *name = (char*)arg;
     54   return (0 == internal_strcmp(tctx->name, name));
     55 }
     56 
     57 static bool HasUid(ThreadContextBase *tctx, void *arg) {
     58   uptr uid = (uptr)arg;
     59   return (tctx->user_id == uid);
     60 }
     61 
     62 static void MarkUidAsPresent(ThreadContextBase *tctx, void *arg) {
     63   bool *arr = (bool*)arg;
     64   arr[tctx->tid] = true;
     65 }
     66 
     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 
    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:
    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 
    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 
    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 
    226 TEST(SanitizerCommon, ThreadRegistryThreadedTest) {
    227   ThreadRegistry registry(GetThreadContext<TestThreadContext>,
    228                           kThreadsPerShard * kNumShards + 1, 10);
    229   ThreadedTestRegistry(&registry);
    230 }
    231 
    232 }  // namespace __sanitizer
    233