• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
27 namespace __sanitizer {
28 
29 struct TidReporterArgument {
TidReporterArgument__sanitizer::TidReporterArgument30   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 
~TidReporterArgument__sanitizer::TidReporterArgument38   ~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 
60 class ThreadListerTest : public ::testing::Test {
61  protected:
SetUp()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 
TearDown()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.
TidReporterThread(void * argument)92 void *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 
SpawnTidReporter(pthread_t * pthread_id,pid_t * tid)107 void 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 
ReadTidsToVector(ThreadLister * thread_lister)121 static 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 
Includes(std::vector<pid_t> first,std::vector<pid_t> second)130 static 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 
HasElement(std::vector<pid_t> vector,pid_t element)137 static 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.
TEST_F(ThreadListerTest,ThreadListerSeesAllSpawnedThreads)143 TEST_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.
TEST_F(ThreadListerTest,ResetDoesNotForgetThreads)153 TEST_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.
TEST_F(ThreadListerTest,ResetMakesNewThreadsKnown)167 TEST_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