Home | History | Annotate | Download | only in tests
      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