16d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//===-- sanitizer_thread_registry_test.cc ---------------------------------===//
26d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//
36d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//                     The LLVM Compiler Infrastructure
46d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//
56d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// This file is distributed under the University of Illinois Open Source
66d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// License. See LICENSE.TXT for details.
76d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//
86d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//===----------------------------------------------------------------------===//
96d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//
106d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov// This file is a part of shared sanitizer runtime.
116d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//
126d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov//===----------------------------------------------------------------------===//
136d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov#include "sanitizer_common/sanitizer_thread_registry.h"
142d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
152d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "sanitizer_pthread_wrappers.h"
162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
176d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov#include "gtest/gtest.h"
186d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
196d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov#include <vector>
206d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
216d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovnamespace __sanitizer {
226d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
236d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic BlockingMutex tctx_allocator_lock(LINKER_INITIALIZED);
246d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic LowLevelAllocator tctx_allocator;
256d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
266d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovtemplate<typename TCTX>
276d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic ThreadContextBase *GetThreadContext(u32 tid) {
286d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  BlockingMutexLock l(&tctx_allocator_lock);
2953177247698bfba075f2d5b255a447fc3ced6976Peter Collingbourne  return new(tctx_allocator) TCTX(tid);
306d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
316d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
326d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic const u32 kMaxRegistryThreads = 1000;
336d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic const u32 kRegistryQuarantine = 2;
346d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
356d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic void CheckThreadQuantity(ThreadRegistry *registry, uptr exp_total,
366d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                                uptr exp_running, uptr exp_alive) {
376d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  uptr total, running, alive;
386d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  registry->GetNumberOfThreads(&total, &running, &alive);
396d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  EXPECT_EQ(exp_total, total);
406d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  EXPECT_EQ(exp_running, running);
416d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  EXPECT_EQ(exp_alive, alive);
426d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
436d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
44827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonovstatic bool is_detached(u32 tid) {
456d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  return (tid % 2 == 0);
466d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
476d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
48827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonovstatic uptr get_uid(u32 tid) {
496d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  return tid * 2;
506d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
516d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
526d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic bool HasName(ThreadContextBase *tctx, void *arg) {
536d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  char *name = (char*)arg;
542d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  return (0 == internal_strcmp(tctx->name, name));
556d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
566d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
576d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic bool HasUid(ThreadContextBase *tctx, void *arg) {
586d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  uptr uid = (uptr)arg;
596d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  return (tctx->user_id == uid);
606d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
616d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
626d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic void MarkUidAsPresent(ThreadContextBase *tctx, void *arg) {
636d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  bool *arr = (bool*)arg;
646d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  arr[tctx->tid] = true;
656d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
666d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
676d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic void TestRegistry(ThreadRegistry *registry, bool has_quarantine) {
686d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  // Create and start a main thread.
69827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  EXPECT_EQ(0U, registry->CreateThread(get_uid(0), true, -1, 0));
706d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  registry->StartThread(0, 0, 0);
716d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  // Create a bunch of threads.
72827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  for (u32 i = 1; i <= 10; i++) {
736d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    EXPECT_EQ(i, registry->CreateThread(get_uid(i), is_detached(i), 0, 0));
746d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
756d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CheckThreadQuantity(registry, 11, 1, 11);
766d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  // Start some of them.
77827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  for (u32 i = 1; i <= 5; i++) {
786d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    registry->StartThread(i, 0, 0);
796d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
806d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CheckThreadQuantity(registry, 11, 6, 11);
816d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  // Finish, create and start more threads.
82827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  for (u32 i = 1; i <= 5; i++) {
836d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    registry->FinishThread(i);
846d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    if (!is_detached(i))
856d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov      registry->JoinThread(i, 0);
866d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
87827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  for (u32 i = 6; i <= 10; i++) {
886d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    registry->StartThread(i, 0, 0);
896d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
90827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  std::vector<u32> new_tids;
91827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  for (u32 i = 11; i <= 15; i++) {
926d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    new_tids.push_back(
936d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov        registry->CreateThread(get_uid(i), is_detached(i), 0, 0));
946d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
95827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  ASSERT_LE(kRegistryQuarantine, 5U);
96827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  u32 exp_total = 16 - (has_quarantine ? 5 - kRegistryQuarantine  : 0);
976d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CheckThreadQuantity(registry, exp_total, 6, 11);
986d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  // Test SetThreadName and FindThread.
996d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  registry->SetThreadName(6, "six");
1006d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  registry->SetThreadName(7, "seven");
101827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  EXPECT_EQ(7U, registry->FindThread(HasName, (void*)"seven"));
102827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  EXPECT_EQ(ThreadRegistry::kUnknownTid,
103827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov            registry->FindThread(HasName, (void*)"none"));
104827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  EXPECT_EQ(0U, registry->FindThread(HasUid, (void*)get_uid(0)));
105827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  EXPECT_EQ(10U, registry->FindThread(HasUid, (void*)get_uid(10)));
106827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  EXPECT_EQ(ThreadRegistry::kUnknownTid,
107827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov            registry->FindThread(HasUid, (void*)0x1234));
1086d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  // Detach and finish and join remaining threads.
109827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  for (u32 i = 6; i <= 10; i++) {
1106d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    registry->DetachThread(i);
1116d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    registry->FinishThread(i);
1126d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
113827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  for (u32 i = 0; i < new_tids.size(); i++) {
114827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov    u32 tid = new_tids[i];
1156d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    registry->StartThread(tid, 0, 0);
1166d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    registry->DetachThread(tid);
1176d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    registry->FinishThread(tid);
1186d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
1196d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  CheckThreadQuantity(registry, exp_total, 1, 1);
1206d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  // Test methods that require the caller to hold a ThreadRegistryLock.
1216d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  bool has_tid[16];
1226d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  internal_memset(&has_tid[0], 0, sizeof(has_tid));
1236d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  {
1246d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    ThreadRegistryLock l(registry);
1256d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    registry->RunCallbackForEachThreadLocked(MarkUidAsPresent, &has_tid[0]);
1266d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
127827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  for (u32 i = 0; i < exp_total; i++) {
1286d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    EXPECT_TRUE(has_tid[i]);
1296d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
1306d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  {
1316d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    ThreadRegistryLock l(registry);
1326d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    registry->CheckLocked();
1336d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    ThreadContextBase *main_thread = registry->GetThreadLocked(0);
1346d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    EXPECT_EQ(main_thread, registry->FindThreadContextLocked(
1356d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov        HasUid, (void*)get_uid(0)));
1366d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
137827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  EXPECT_EQ(11U, registry->GetMaxAliveThreads());
1386d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1396d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1406d429cda69b7ccc007ee368a73a6040c6b125afbAlexey SamsonovTEST(SanitizerCommon, ThreadRegistryTest) {
1416d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  ThreadRegistry quarantine_registry(GetThreadContext<ThreadContextBase>,
1426d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                                     kMaxRegistryThreads,
1436d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                                     kRegistryQuarantine);
1446d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  TestRegistry(&quarantine_registry, true);
1456d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1466d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  ThreadRegistry no_quarantine_registry(GetThreadContext<ThreadContextBase>,
1476d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                                        kMaxRegistryThreads,
1486d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                                        kMaxRegistryThreads);
1496d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  TestRegistry(&no_quarantine_registry, false);
1506d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1516d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1526d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic const int kThreadsPerShard = 20;
1536d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic const int kNumShards = 25;
1546d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1556d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic int num_created[kNumShards + 1];
1566d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic int num_started[kNumShards + 1];
1576d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic int num_joined[kNumShards + 1];
1586d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1596d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovnamespace {
1606d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1616d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstruct RunThreadArgs {
1626d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  ThreadRegistry *registry;
1636d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  uptr shard;  // started from 1.
1646d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov};
1656d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1666d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovclass TestThreadContext : public ThreadContextBase {
1676d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov public:
1686d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  explicit TestThreadContext(int tid) : ThreadContextBase(tid) {}
1696d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  void OnJoined(void *arg) {
1706d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    uptr shard = (uptr)arg;
1716d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    num_joined[shard]++;
1726d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
1736d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  void OnStarted(void *arg) {
1746d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    uptr shard = (uptr)arg;
1756d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    num_started[shard]++;
1766d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
1776d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  void OnCreated(void *arg) {
1786d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    uptr shard = (uptr)arg;
1796d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    num_created[shard]++;
1806d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
1816d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov};
1826d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1836d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}  // namespace
1846d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
1856d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovvoid *RunThread(void *arg) {
1866d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  RunThreadArgs *args = static_cast<RunThreadArgs*>(arg);
1876d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  std::vector<int> tids;
1886d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  for (int i = 0; i < kThreadsPerShard; i++)
1896d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    tids.push_back(
1906d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov        args->registry->CreateThread(0, false, 0, (void*)args->shard));
1916d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  for (int i = 0; i < kThreadsPerShard; i++)
1926d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    args->registry->StartThread(tids[i], 0, (void*)args->shard);
1936d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  for (int i = 0; i < kThreadsPerShard; i++)
1946d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    args->registry->FinishThread(tids[i]);
1956d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  for (int i = 0; i < kThreadsPerShard; i++)
1966d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    args->registry->JoinThread(tids[i], (void*)args->shard);
1976d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  return 0;
1986d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
1996d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
2006d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonovstatic void ThreadedTestRegistry(ThreadRegistry *registry) {
2016d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  // Create and start a main thread.
202827d4ef8b76760ef8c58612d916b8f53081bf368Alexey Samsonov  EXPECT_EQ(0U, registry->CreateThread(0, true, -1, 0));
2036d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  registry->StartThread(0, 0, 0);
2046d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  pthread_t threads[kNumShards];
2056d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  RunThreadArgs args[kNumShards];
2066d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  for (int i = 0; i < kNumShards; i++) {
2076d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    args[i].registry = registry;
2086d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    args[i].shard = i + 1;
2092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    PTHREAD_CREATE(&threads[i], 0, RunThread, &args[i]);
2106d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
2116d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  for (int i = 0; i < kNumShards; i++) {
2122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    PTHREAD_JOIN(threads[i], 0);
2136d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
2146d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  // Check that each thread created/started/joined correct amount
2156d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  // of "threads" in thread_registry.
2166d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  EXPECT_EQ(1, num_created[0]);
2176d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  EXPECT_EQ(1, num_started[0]);
2186d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  EXPECT_EQ(0, num_joined[0]);
2196d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  for (int i = 1; i <= kNumShards; i++) {
2206d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    EXPECT_EQ(kThreadsPerShard, num_created[i]);
2216d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    EXPECT_EQ(kThreadsPerShard, num_started[i]);
2226d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov    EXPECT_EQ(kThreadsPerShard, num_joined[i]);
2236d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  }
2246d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
2256d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
2266d429cda69b7ccc007ee368a73a6040c6b125afbAlexey SamsonovTEST(SanitizerCommon, ThreadRegistryThreadedTest) {
2276d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  ThreadRegistry registry(GetThreadContext<TestThreadContext>,
2286d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov                          kThreadsPerShard * kNumShards + 1, 10);
2296d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov  ThreadedTestRegistry(&registry);
2306d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}
2316d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov
2326d429cda69b7ccc007ee368a73a6040c6b125afbAlexey Samsonov}  // namespace __sanitizer
233