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