brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.8 KiB · 6e84ecd Raw
303 lines · cpp
1//===-- sanitizer_thread_registry_test.cpp --------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of shared sanitizer runtime.10//11//===----------------------------------------------------------------------===//12#include "sanitizer_common/sanitizer_thread_registry.h"13 14#include <iostream>15#include <vector>16 17#include "gmock/gmock.h"18#include "gtest/gtest.h"19#include "sanitizer_common/sanitizer_common.h"20#include "sanitizer_common/sanitizer_stackdepot.h"21#include "sanitizer_common/sanitizer_stacktrace.h"22#include "sanitizer_common/sanitizer_thread_history.h"23#include "sanitizer_pthread_wrappers.h"24 25using testing::HasSubstr;26 27namespace __sanitizer {28 29static Mutex tctx_allocator_lock;30static LowLevelAllocator tctx_allocator;31 32template<typename TCTX>33static ThreadContextBase *GetThreadContext(u32 tid) {34  Lock l(&tctx_allocator_lock);35  return new(tctx_allocator) TCTX(tid);36}37 38static const u32 kMaxRegistryThreads = 1000;39static const u32 kRegistryQuarantine = 2;40 41static void CheckThreadQuantity(ThreadRegistry *registry, uptr exp_total,42                                uptr exp_running, uptr exp_alive) {43  uptr total, running, alive;44  registry->GetNumberOfThreads(&total, &running, &alive);45  EXPECT_EQ(exp_total, total);46  EXPECT_EQ(exp_running, running);47  EXPECT_EQ(exp_alive, alive);48}49 50static bool is_detached(u32 tid) {51  return (tid % 2 == 0);52}53 54static uptr get_uid(u32 tid) {55  return tid * 2;56}57 58static bool HasName(ThreadContextBase *tctx, void *arg) {59  char *name = (char*)arg;60  return (0 == internal_strcmp(tctx->name, name));61}62 63static bool HasUid(ThreadContextBase *tctx, void *arg) {64  uptr uid = (uptr)arg;65  return (tctx->user_id == uid);66}67 68static void MarkUidAsPresent(ThreadContextBase *tctx, void *arg) {69  bool *arr = (bool*)arg;70  arr[tctx->tid] = true;71}72 73static void TestRegistry(ThreadRegistry *registry, bool has_quarantine) {74  // Create and start a main thread.75  EXPECT_EQ(0U, registry->CreateThread(get_uid(0), true, -1, 0, nullptr));76  registry->StartThread(0, 0, ThreadType::Regular, 0);77  // Create a bunch of threads.78  for (u32 i = 1; i <= 10; i++) {79    EXPECT_EQ(i, registry->CreateThread(get_uid(i), is_detached(i), 100 + i,80                                        200 + i, nullptr));81  }82  CheckThreadQuantity(registry, 11, 1, 11);83  // Start some of them.84  for (u32 i = 1; i <= 5; i++) {85    registry->StartThread(i, 0, ThreadType::Regular, 0);86  }87  CheckThreadQuantity(registry, 11, 6, 11);88  // Finish, create and start more threads.89  for (u32 i = 1; i <= 5; i++) {90    registry->FinishThread(i);91    if (!is_detached(i))92      registry->JoinThread(i, 0);93  }94  for (u32 i = 6; i <= 10; i++) {95    registry->StartThread(i, 0, ThreadType::Regular, 0);96  }97  std::vector<u32> new_tids;98  for (u32 i = 11; i <= 15; i++) {99    new_tids.push_back(100        registry->CreateThread(get_uid(i), is_detached(i), 0, 0, nullptr));101  }102  ASSERT_LE(kRegistryQuarantine, 5U);103  u32 exp_total = 16 - (has_quarantine ? 5 - kRegistryQuarantine : 0);104  CheckThreadQuantity(registry, exp_total, 6, 11);105  // Test SetThreadName and FindThread.106  registry->SetThreadName(6, "six");107  registry->SetThreadName(7, "seven");108  EXPECT_EQ(7U, registry->FindThread(HasName, (void *)"seven"));109  EXPECT_EQ(kInvalidTid, registry->FindThread(HasName, (void *)"none"));110  EXPECT_EQ(0U, registry->FindThread(HasUid, (void *)get_uid(0)));111  EXPECT_EQ(10U, registry->FindThread(HasUid, (void *)get_uid(10)));112  EXPECT_EQ(kInvalidTid, registry->FindThread(HasUid, (void *)0x1234));113  EXPECT_EQ(7U,114            registry->FindThread([](ThreadContextBase *tctx,115                                    void *) { return tctx->parent_tid == 107; },116                                 nullptr));117  EXPECT_EQ(8U,118            registry->FindThread([](ThreadContextBase *tctx,119                                    void *) { return tctx->stack_id == 208; },120                                 nullptr));121  // Detach and finish and join remaining threads.122  for (u32 i = 6; i <= 10; i++) {123    registry->DetachThread(i, 0);124    registry->FinishThread(i);125  }126  for (u32 i = 0; i < new_tids.size(); i++) {127    u32 tid = new_tids[i];128    registry->StartThread(tid, 0, ThreadType::Regular, 0);129    registry->DetachThread(tid, 0);130    registry->FinishThread(tid);131  }132  CheckThreadQuantity(registry, exp_total, 1, 1);133  // Test methods that require the caller to hold a ThreadRegistryLock.134  bool has_tid[16];135  internal_memset(&has_tid[0], 0, sizeof(has_tid));136  {137    ThreadRegistryLock l(registry);138    registry->RunCallbackForEachThreadLocked(MarkUidAsPresent, &has_tid[0]);139  }140  for (u32 i = 0; i < exp_total; i++) {141    EXPECT_TRUE(has_tid[i]);142  }143  {144    ThreadRegistryLock l(registry);145    registry->CheckLocked();146    ThreadContextBase *main_thread = registry->GetThreadLocked(0);147    EXPECT_EQ(main_thread, registry->FindThreadContextLocked(148        HasUid, (void*)get_uid(0)));149  }150  EXPECT_EQ(11U, registry->GetMaxAliveThreads());151}152 153TEST(SanitizerCommon, ThreadRegistryTest) {154  ThreadRegistry quarantine_registry(GetThreadContext<ThreadContextBase>,155                                     kMaxRegistryThreads, kRegistryQuarantine,156                                     0);157  TestRegistry(&quarantine_registry, true);158 159  ThreadRegistry no_quarantine_registry(GetThreadContext<ThreadContextBase>,160                                        kMaxRegistryThreads,161                                        kMaxRegistryThreads, 0);162  TestRegistry(&no_quarantine_registry, false);163}164 165static const int kThreadsPerShard = 20;166static const int kNumShards = 25;167 168static int num_created[kNumShards + 1];169static int num_started[kNumShards + 1];170static int num_joined[kNumShards + 1];171 172namespace {173 174struct RunThreadArgs {175  ThreadRegistry *registry;176  uptr shard;  // started from 1.177};178 179class TestThreadContext final : public ThreadContextBase {180 public:181  explicit TestThreadContext(int tid) : ThreadContextBase(tid) {}182  void OnJoined(void *arg) {183    uptr shard = (uptr)arg;184    num_joined[shard]++;185  }186  void OnStarted(void *arg) {187    uptr shard = (uptr)arg;188    num_started[shard]++;189  }190  void OnCreated(void *arg) {191    uptr shard = (uptr)arg;192    num_created[shard]++;193  }194};195 196}  // namespace197 198void *RunThread(void *arg) {199  RunThreadArgs *args = static_cast<RunThreadArgs*>(arg);200  std::vector<int> tids;201  for (int i = 0; i < kThreadsPerShard; i++)202    tids.push_back(203        args->registry->CreateThread(0, false, 0, (void*)args->shard));204  for (int i = 0; i < kThreadsPerShard; i++)205    args->registry->StartThread(tids[i], 0, ThreadType::Regular,206        (void*)args->shard);207  for (int i = 0; i < kThreadsPerShard; i++)208    args->registry->FinishThread(tids[i]);209  for (int i = 0; i < kThreadsPerShard; i++)210    args->registry->JoinThread(tids[i], (void*)args->shard);211  return 0;212}213 214static void ThreadedTestRegistry(ThreadRegistry *registry) {215  // Create and start a main thread.216  EXPECT_EQ(0U, registry->CreateThread(0, true, -1, 0));217  registry->StartThread(0, 0, ThreadType::Regular, 0);218  pthread_t threads[kNumShards];219  RunThreadArgs args[kNumShards];220  for (int i = 0; i < kNumShards; i++) {221    args[i].registry = registry;222    args[i].shard = i + 1;223    PTHREAD_CREATE(&threads[i], 0, RunThread, &args[i]);224  }225  for (int i = 0; i < kNumShards; i++) {226    PTHREAD_JOIN(threads[i], 0);227  }228  // Check that each thread created/started/joined correct amount229  // of "threads" in thread_registry.230  EXPECT_EQ(1, num_created[0]);231  EXPECT_EQ(1, num_started[0]);232  EXPECT_EQ(0, num_joined[0]);233  for (int i = 1; i <= kNumShards; i++) {234    EXPECT_EQ(kThreadsPerShard, num_created[i]);235    EXPECT_EQ(kThreadsPerShard, num_started[i]);236    EXPECT_EQ(kThreadsPerShard, num_joined[i]);237  }238}239 240TEST(SanitizerCommon, ThreadRegistryThreadedTest) {241  memset(&num_created, 0, sizeof(num_created));242  memset(&num_started, 0, sizeof(num_created));243  memset(&num_joined, 0, sizeof(num_created));244 245  ThreadRegistry registry(GetThreadContext<TestThreadContext>,246                          kThreadsPerShard * kNumShards + 1, 10, 0);247  ThreadedTestRegistry(&registry);248}249 250TEST(SanitizerCommon, PrintThreadHistory) {251  ThreadRegistry registry(GetThreadContext<TestThreadContext>,252                          kThreadsPerShard * kNumShards + 1, 10, 0);253 254  UNINITIALIZED BufferedStackTrace stack1;255  stack1.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), nullptr, false,256                /*max_depth=*/1);257 258  UNINITIALIZED BufferedStackTrace stack2;259  stack2.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), nullptr, false,260                /*max_depth=*/1);261 262  EXPECT_EQ(0U, registry.CreateThread(0, true, -1, 0, nullptr));263  for (int i = 0; i < 5; i++) {264    registry.CreateThread(0, true, 0, StackDepotPut(stack1), nullptr);265    registry.CreateThread(0, true, 0, StackDepotPut(stack2), nullptr);266  }267 268  InternalScopedString out;269  PrintThreadHistory(registry, out);270 271  std::string substrings[] = {272      "Thread T0/0 was created by T-1",273      "<empty stack>",274      "",275      "Thread T1/0 was created by T0/0",276      "Thread T3/0 was created by T0/0",277      "Thread T5/0 was created by T0/0",278      "Thread T7/0 was created by T0/0",279      "Thread T9/0 was created by T0/0",280      "#0 0x",281      "",282      "Thread T2/0 was created by T0/0",283      "Thread T4/0 was created by T0/0",284      "Thread T6/0 was created by T0/0",285      "Thread T8/0 was created by T0/0",286      "Thread T10/0 was created by T0/0",287      "#0 0x",288      "",289  };290 291  std::stringstream ss(out.data());292  std::string line;293 294  for (auto substr : substrings) {295    std::getline(ss, line);296    EXPECT_THAT(line, HasSubstr(substr)) << line;297  }298 299  EXPECT_FALSE(std::getline(ss, line)) << "Unmatched line: " << line;300}301 302}  // namespace __sanitizer303