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