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 #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(&registry);
    228 }
    229 
    230 }  // namespace __sanitizer
    231