1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <err.h> 18 #include <inttypes.h> 19 #include <pthread.h> 20 #include <stdio.h> 21 #include <string.h> 22 #include <sys/mman.h> 23 #include <sys/user.h> 24 #include <unistd.h> 25 26 #include <gtest/gtest.h> 27 28 #include <chrono> 29 #include <thread> 30 #include <vector> 31 32 #include <android-base/macros.h> 33 34 #include "utils.h" 35 36 using namespace std::chrono_literals; 37 38 static void WaitUntilAllExited(pid_t* pids, size_t pid_count) { 39 // Wait until all children have exited. 40 bool alive = true; 41 while (alive) { 42 alive = false; 43 for (size_t i = 0; i < pid_count; ++i) { 44 if (pids[i] != 0) { 45 if (kill(pids[i], 0) == 0) { 46 alive = true; 47 } else { 48 EXPECT_EQ(errno, ESRCH); 49 pids[i] = 0; // Skip in next loop. 50 } 51 } 52 } 53 } 54 } 55 56 class LeakChecker { 57 public: 58 LeakChecker() { 59 // Avoid resizing and using memory later. 60 // 64Ki is the default limit on VMAs per process. 61 maps_.reserve(64*1024); 62 Reset(); 63 } 64 65 ~LeakChecker() { 66 Check(); 67 } 68 69 void Reset() { 70 previous_size_ = GetMappingSize(); 71 } 72 73 void DumpTo(std::ostream& os) const { 74 os << previous_size_; 75 } 76 77 private: 78 size_t previous_size_; 79 std::vector<map_record> maps_; 80 81 void Check() { 82 auto current_size = GetMappingSize(); 83 if (current_size > previous_size_) { 84 FAIL() << "increase in process map size: " << previous_size_ << " -> " << current_size; 85 } 86 } 87 88 size_t GetMappingSize() { 89 if (!Maps::parse_maps(&maps_)) { 90 err(1, "failed to parse maps"); 91 } 92 93 size_t result = 0; 94 for (const map_record& map : maps_) { 95 result += map.addr_end - map.addr_start; 96 } 97 98 return result; 99 } 100 }; 101 102 std::ostream& operator<<(std::ostream& os, const LeakChecker& lc) { 103 lc.DumpTo(os); 104 return os; 105 } 106 107 // http://b/36045112 108 TEST(pthread_leak, join) { 109 LeakChecker lc; 110 111 for (size_t pass = 0; pass < 2; ++pass) { 112 for (int i = 0; i < 100; ++i) { 113 pthread_t thread; 114 ASSERT_EQ(0, pthread_create(&thread, nullptr, [](void*) -> void* { return nullptr; }, nullptr)); 115 ASSERT_EQ(0, pthread_join(thread, nullptr)); 116 } 117 118 // A native bridge implementation might need a warm up pass to reach a steady state. 119 // http://b/37920774. 120 if (pass == 0) lc.Reset(); 121 } 122 } 123 124 // http://b/36045112 125 TEST(pthread_leak, detach) { 126 LeakChecker lc; 127 128 for (size_t pass = 0; pass < 2; ++pass) { 129 constexpr int kThreadCount = 100; 130 struct thread_data { pthread_barrier_t* barrier; pid_t* tid; } threads[kThreadCount] = {}; 131 132 pthread_barrier_t barrier; 133 ASSERT_EQ(pthread_barrier_init(&barrier, nullptr, kThreadCount + 1), 0); 134 135 // Start child threads. 136 pid_t tids[kThreadCount]; 137 for (int i = 0; i < kThreadCount; ++i) { 138 threads[i] = {&barrier, &tids[i]}; 139 const auto thread_function = +[](void* ptr) -> void* { 140 thread_data* data = static_cast<thread_data*>(ptr); 141 *data->tid = gettid(); 142 pthread_barrier_wait(data->barrier); 143 return nullptr; 144 }; 145 pthread_t thread; 146 ASSERT_EQ(0, pthread_create(&thread, nullptr, thread_function, &threads[i])); 147 ASSERT_EQ(0, pthread_detach(thread)); 148 } 149 150 pthread_barrier_wait(&barrier); 151 ASSERT_EQ(pthread_barrier_destroy(&barrier), 0); 152 153 WaitUntilAllExited(tids, arraysize(tids)); 154 155 // A native bridge implementation might need a warm up pass to reach a steady state. 156 // http://b/37920774. 157 if (pass == 0) lc.Reset(); 158 } 159 } 160