diff options
author | Steven Laver <lavers@google.com> | 2019-12-12 15:29:36 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2019-12-12 15:29:36 +0000 |
commit | a239544c7b06814b70fd970de7eaac234682fa52 (patch) | |
tree | a4298d61f9b73642f350799b1157e49b65f4e1e8 /libmemunreachable/tests/ThreadCapture_test.cpp | |
parent | 63de1e1c8d7824c241f22de67edf54f4f1eaeea5 (diff) | |
parent | 5319412e5305a3b4bcecf251a2955c09a6e9837e (diff) |
Merge "Merge RP1A.191203.001" into r-keystone-qcom-dev
Diffstat (limited to 'libmemunreachable/tests/ThreadCapture_test.cpp')
-rw-r--r-- | libmemunreachable/tests/ThreadCapture_test.cpp | 351 |
1 files changed, 0 insertions, 351 deletions
diff --git a/libmemunreachable/tests/ThreadCapture_test.cpp b/libmemunreachable/tests/ThreadCapture_test.cpp deleted file mode 100644 index 933d65ab5..000000000 --- a/libmemunreachable/tests/ThreadCapture_test.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "ThreadCapture.h" - -#include <fcntl.h> -#include <pthread.h> -#include <sys/syscall.h> -#include <sys/types.h> - -#include <algorithm> -#include <functional> -#include <memory> -#include <thread> - -#include <gtest/gtest.h> - -#include "Allocator.h" -#include "ScopedDisableMalloc.h" -#include "ScopedPipe.h" - -#include <android-base/threads.h> - -using namespace std::chrono_literals; - -namespace android { - -class ThreadListTest : public ::testing::TestWithParam<int> { - public: - ThreadListTest() : stop_(false) {} - - ~ThreadListTest() { - // pthread_join may return before the entry in /proc/pid/task/ is gone, - // loop until ListThreads only finds the main thread so the next test - // doesn't fail. - WaitForThreads(); - } - - virtual void TearDown() { ASSERT_TRUE(heap.empty()); } - - protected: - template <class Function> - void StartThreads(unsigned int threads, Function&& func) { - threads_.reserve(threads); - tids_.reserve(threads); - for (unsigned int i = 0; i < threads; i++) { - threads_.emplace_back([&, threads, this]() { - { - std::lock_guard<std::mutex> lk(m_); - tids_.push_back(gettid()); - if (tids_.size() == threads) { - cv_start_.notify_one(); - } - } - - func(); - - { - std::unique_lock<std::mutex> lk(m_); - cv_stop_.wait(lk, [&] { return stop_; }); - } - }); - } - - { - std::unique_lock<std::mutex> lk(m_); - cv_start_.wait(lk, [&] { return tids_.size() == threads; }); - } - } - - void StopThreads() { - { - std::lock_guard<std::mutex> lk(m_); - stop_ = true; - } - cv_stop_.notify_all(); - - for (auto i = threads_.begin(); i != threads_.end(); i++) { - i->join(); - } - threads_.clear(); - tids_.clear(); - } - - std::vector<pid_t>& tids() { return tids_; } - - Heap heap; - - private: - void WaitForThreads() { - auto tids = TidList{heap}; - ThreadCapture thread_capture{getpid(), heap}; - - for (unsigned int i = 0; i < 100; i++) { - EXPECT_TRUE(thread_capture.ListThreads(tids)); - if (tids.size() == 1) { - break; - } - std::this_thread::sleep_for(10ms); - } - EXPECT_EQ(1U, tids.size()); - } - - std::mutex m_; - std::condition_variable cv_start_; - std::condition_variable cv_stop_; - bool stop_; - std::vector<pid_t> tids_; - - std::vector<std::thread> threads_; -}; - -TEST_F(ThreadListTest, list_one) { - ScopedDisableMallocTimeout disable_malloc; - - ThreadCapture thread_capture(getpid(), heap); - - auto expected_tids = allocator::vector<pid_t>(1, getpid(), heap); - auto list_tids = allocator::vector<pid_t>(heap); - - ASSERT_TRUE(thread_capture.ListThreads(list_tids)); - - ASSERT_EQ(expected_tids, list_tids); - - if (!HasFailure()) { - ASSERT_FALSE(disable_malloc.timed_out()); - } -} - -TEST_P(ThreadListTest, list_some) { - const unsigned int threads = GetParam() - 1; - - StartThreads(threads, []() {}); - std::vector<pid_t> expected_tids = tids(); - expected_tids.push_back(getpid()); - - auto list_tids = allocator::vector<pid_t>(heap); - - { - ScopedDisableMallocTimeout disable_malloc; - - ThreadCapture thread_capture(getpid(), heap); - - ASSERT_TRUE(thread_capture.ListThreads(list_tids)); - - if (!HasFailure()) { - ASSERT_FALSE(disable_malloc.timed_out()); - } - } - - StopThreads(); - - std::sort(list_tids.begin(), list_tids.end()); - std::sort(expected_tids.begin(), expected_tids.end()); - - ASSERT_EQ(expected_tids.size(), list_tids.size()); - EXPECT_TRUE(std::equal(expected_tids.begin(), expected_tids.end(), list_tids.begin())); -} - -INSTANTIATE_TEST_CASE_P(ThreadListTest, ThreadListTest, ::testing::Values(1, 2, 10, 1024)); - -class ThreadCaptureTest : public ThreadListTest { - public: - ThreadCaptureTest() {} - ~ThreadCaptureTest() {} - void Fork(std::function<void()>&& child_init, std::function<void()>&& child_cleanup, - std::function<void(pid_t)>&& parent) { - ScopedPipe start_pipe; - ScopedPipe stop_pipe; - - int pid = fork(); - - if (pid == 0) { - // child - child_init(); - EXPECT_EQ(1, TEMP_FAILURE_RETRY(write(start_pipe.Sender(), "+", 1))) << strerror(errno); - char buf; - EXPECT_EQ(1, TEMP_FAILURE_RETRY(read(stop_pipe.Receiver(), &buf, 1))) << strerror(errno); - child_cleanup(); - _exit(0); - } else { - // parent - ASSERT_GT(pid, 0); - char buf; - ASSERT_EQ(1, TEMP_FAILURE_RETRY(read(start_pipe.Receiver(), &buf, 1))) << strerror(errno); - - parent(pid); - - ASSERT_EQ(1, TEMP_FAILURE_RETRY(write(stop_pipe.Sender(), "+", 1))) << strerror(errno); - siginfo_t info{}; - ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED))) << strerror(errno); - } - } -}; - -TEST_P(ThreadCaptureTest, capture_some) { - const unsigned int threads = GetParam(); - - Fork( - [&]() { - // child init - StartThreads(threads - 1, []() {}); - }, - [&]() { - // child cleanup - StopThreads(); - }, - [&](pid_t child) { - // parent - ASSERT_GT(child, 0); - - { - ScopedDisableMallocTimeout disable_malloc; - - ThreadCapture thread_capture(child, heap); - auto list_tids = allocator::vector<pid_t>(heap); - - ASSERT_TRUE(thread_capture.ListThreads(list_tids)); - ASSERT_EQ(threads, list_tids.size()); - - ASSERT_TRUE(thread_capture.CaptureThreads()); - - auto thread_info = allocator::vector<ThreadInfo>(heap); - ASSERT_TRUE(thread_capture.CapturedThreadInfo(thread_info)); - ASSERT_EQ(threads, thread_info.size()); - ASSERT_TRUE(thread_capture.ReleaseThreads()); - - if (!HasFailure()) { - ASSERT_FALSE(disable_malloc.timed_out()); - } - } - }); -} - -INSTANTIATE_TEST_CASE_P(ThreadCaptureTest, ThreadCaptureTest, ::testing::Values(1, 2, 10, 1024)); - -TEST_F(ThreadCaptureTest, capture_kill) { - int ret = fork(); - - if (ret == 0) { - // child - sleep(10); - } else { - // parent - ASSERT_GT(ret, 0); - - { - ScopedDisableMallocTimeout disable_malloc; - - ThreadCapture thread_capture(ret, heap); - thread_capture.InjectTestFunc([&](pid_t tid) { - tgkill(ret, tid, SIGKILL); - usleep(10000); - }); - auto list_tids = allocator::vector<pid_t>(heap); - - ASSERT_TRUE(thread_capture.ListThreads(list_tids)); - ASSERT_EQ(1U, list_tids.size()); - - ASSERT_FALSE(thread_capture.CaptureThreads()); - - if (!HasFailure()) { - ASSERT_FALSE(disable_malloc.timed_out()); - } - } - } -} - -TEST_F(ThreadCaptureTest, capture_signal) { - const int sig = SIGUSR1; - - ScopedPipe pipe; - - // For signal handler - static ScopedPipe* g_pipe; - - Fork( - [&]() { - // child init - pipe.CloseReceiver(); - - g_pipe = &pipe; - - struct sigaction act {}; - act.sa_handler = [](int) { - char buf = '+'; - write(g_pipe->Sender(), &buf, 1); - g_pipe->CloseSender(); - }; - sigaction(sig, &act, NULL); - sigset_t set; - sigemptyset(&set); - sigaddset(&set, sig); - pthread_sigmask(SIG_UNBLOCK, &set, NULL); - }, - [&]() { - // child cleanup - g_pipe = nullptr; - pipe.Close(); - }, - [&](pid_t child) { - // parent - ASSERT_GT(child, 0); - pipe.CloseSender(); - - { - ScopedDisableMallocTimeout disable_malloc; - - ThreadCapture thread_capture(child, heap); - thread_capture.InjectTestFunc([&](pid_t tid) { - tgkill(child, tid, sig); - usleep(10000); - }); - auto list_tids = allocator::vector<pid_t>(heap); - - ASSERT_TRUE(thread_capture.ListThreads(list_tids)); - ASSERT_EQ(1U, list_tids.size()); - - ASSERT_TRUE(thread_capture.CaptureThreads()); - - auto thread_info = allocator::vector<ThreadInfo>(heap); - ASSERT_TRUE(thread_capture.CapturedThreadInfo(thread_info)); - ASSERT_EQ(1U, thread_info.size()); - ASSERT_TRUE(thread_capture.ReleaseThreads()); - - usleep(100000); - char buf; - ASSERT_EQ(1, TEMP_FAILURE_RETRY(read(pipe.Receiver(), &buf, 1))); - ASSERT_EQ(buf, '+'); - - if (!HasFailure()) { - ASSERT_FALSE(disable_malloc.timed_out()); - } - } - }); -} - -} // namespace android |