sanitizer_linux_test.cc revision 827d4ef8b76760ef8c58612d916b8f53081bf368
1//===-- sanitizer_linux_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// Tests for sanitizer_linux.h
11//
12//===----------------------------------------------------------------------===//
13
14#ifdef __linux__
15
16#include "sanitizer_common/sanitizer_linux.h"
17#include "gtest/gtest.h"
18
19#include "sanitizer_common/sanitizer_common.h"
20
21#include <pthread.h>
22#include <sched.h>
23
24#include <algorithm>
25#include <vector>
26
27namespace __sanitizer {
28
29struct TidReporterArgument {
30  TidReporterArgument() {
31    pthread_mutex_init(&terminate_thread_mutex, NULL);
32    pthread_mutex_init(&tid_reported_mutex, NULL);
33    pthread_cond_init(&terminate_thread_cond, NULL);
34    pthread_cond_init(&tid_reported_cond, NULL);
35    terminate_thread = false;
36  }
37
38  ~TidReporterArgument() {
39    pthread_mutex_destroy(&terminate_thread_mutex);
40    pthread_mutex_destroy(&tid_reported_mutex);
41    pthread_cond_destroy(&terminate_thread_cond);
42    pthread_cond_destroy(&tid_reported_cond);
43  }
44
45  pid_t reported_tid;
46  // For signaling to spawned threads that they should terminate.
47  pthread_cond_t terminate_thread_cond;
48  pthread_mutex_t terminate_thread_mutex;
49  bool terminate_thread;
50  // For signaling to main thread that a child thread has reported its tid.
51  pthread_cond_t tid_reported_cond;
52  pthread_mutex_t tid_reported_mutex;
53
54 private:
55  // Disallow evil constructors
56  TidReporterArgument(const TidReporterArgument &);
57  void operator=(const TidReporterArgument &);
58};
59
60class ThreadListerTest : public ::testing::Test {
61 protected:
62  virtual void SetUp() {
63    pthread_t pthread_id;
64    pid_t tid;
65    for (uptr i = 0; i < kThreadCount; i++) {
66      SpawnTidReporter(&pthread_id, &tid);
67      pthread_ids_.push_back(pthread_id);
68      tids_.push_back(tid);
69    }
70  }
71
72  virtual void TearDown() {
73    pthread_mutex_lock(&thread_arg.terminate_thread_mutex);
74    thread_arg.terminate_thread = true;
75    pthread_cond_broadcast(&thread_arg.terminate_thread_cond);
76    pthread_mutex_unlock(&thread_arg.terminate_thread_mutex);
77    for (uptr i = 0; i < pthread_ids_.size(); i++)
78      pthread_join(pthread_ids_[i], NULL);
79  }
80
81  void SpawnTidReporter(pthread_t *pthread_id, pid_t *tid);
82
83  static const uptr kThreadCount = 20;
84
85  std::vector<pthread_t> pthread_ids_;
86  std::vector<pid_t> tids_;
87
88  TidReporterArgument thread_arg;
89};
90
91// Writes its TID once to reported_tid and waits until signaled to terminate.
92void *TidReporterThread(void *argument) {
93  TidReporterArgument *arg = reinterpret_cast<TidReporterArgument *>(argument);
94  pthread_mutex_lock(&arg->tid_reported_mutex);
95  arg->reported_tid = GetTid();
96  pthread_cond_broadcast(&arg->tid_reported_cond);
97  pthread_mutex_unlock(&arg->tid_reported_mutex);
98
99  pthread_mutex_lock(&arg->terminate_thread_mutex);
100  while (!arg->terminate_thread)
101    pthread_cond_wait(&arg->terminate_thread_cond,
102                      &arg->terminate_thread_mutex);
103  pthread_mutex_unlock(&arg->terminate_thread_mutex);
104  return NULL;
105}
106
107void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id,
108                                        pid_t *tid) {
109  pthread_mutex_lock(&thread_arg.tid_reported_mutex);
110  thread_arg.reported_tid = -1;
111  ASSERT_EQ(0, pthread_create(pthread_id, NULL,
112                              TidReporterThread,
113                              &thread_arg));
114  while (thread_arg.reported_tid == -1)
115    pthread_cond_wait(&thread_arg.tid_reported_cond,
116                      &thread_arg.tid_reported_mutex);
117  pthread_mutex_unlock(&thread_arg.tid_reported_mutex);
118  *tid = thread_arg.reported_tid;
119}
120
121static std::vector<pid_t> ReadTidsToVector(ThreadLister *thread_lister) {
122  std::vector<pid_t> listed_tids;
123  pid_t tid;
124  while ((tid = thread_lister->GetNextTID()) >= 0)
125    listed_tids.push_back(tid);
126  EXPECT_FALSE(thread_lister->error());
127  return listed_tids;
128}
129
130static bool Includes(std::vector<pid_t> first, std::vector<pid_t> second) {
131  std::sort(first.begin(), first.end());
132  std::sort(second.begin(), second.end());
133  return std::includes(first.begin(), first.end(),
134                       second.begin(), second.end());
135}
136
137static bool HasElement(std::vector<pid_t> vector, pid_t element) {
138  return std::find(vector.begin(), vector.end(), element) != vector.end();
139}
140
141// ThreadLister's output should include the current thread's TID and the TID of
142// every thread we spawned.
143TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) {
144  pid_t self_tid = GetTid();
145  ThreadLister thread_lister(getpid());
146  std::vector<pid_t> listed_tids = ReadTidsToVector(&thread_lister);
147  ASSERT_TRUE(HasElement(listed_tids, self_tid));
148  ASSERT_TRUE(Includes(listed_tids, tids_));
149}
150
151// Calling Reset() should not cause ThreadLister to forget any threads it's
152// supposed to know about.
153TEST_F(ThreadListerTest, ResetDoesNotForgetThreads) {
154  ThreadLister thread_lister(getpid());
155
156  // Run the loop body twice, because Reset() might behave differently if called
157  // on a freshly created object.
158  for (uptr i = 0; i < 2; i++) {
159    thread_lister.Reset();
160    std::vector<pid_t> listed_tids = ReadTidsToVector(&thread_lister);
161    ASSERT_TRUE(Includes(listed_tids, tids_));
162  }
163}
164
165// If new threads have spawned during ThreadLister object's lifetime, calling
166// Reset() should cause ThreadLister to recognize their existence.
167TEST_F(ThreadListerTest, ResetMakesNewThreadsKnown) {
168  ThreadLister thread_lister(getpid());
169  std::vector<pid_t> threads_before_extra = ReadTidsToVector(&thread_lister);
170
171  pthread_t extra_pthread_id;
172  pid_t extra_tid;
173  SpawnTidReporter(&extra_pthread_id, &extra_tid);
174  // Register the new thread so it gets terminated in TearDown().
175  pthread_ids_.push_back(extra_pthread_id);
176
177  // It would be very bizarre if the new TID had been listed before we even
178  // spawned that thread, but it would also cause a false success in this test,
179  // so better check for that.
180  ASSERT_FALSE(HasElement(threads_before_extra, extra_tid));
181
182  thread_lister.Reset();
183
184  std::vector<pid_t> threads_after_extra = ReadTidsToVector(&thread_lister);
185  ASSERT_TRUE(HasElement(threads_after_extra, extra_tid));
186}
187
188}  // namespace __sanitizer
189
190#endif  // __linux__
191