summaryrefslogtreecommitdiff
path: root/libmemunreachable/tests/ThreadCapture_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libmemunreachable/tests/ThreadCapture_test.cpp')
-rw-r--r--libmemunreachable/tests/ThreadCapture_test.cpp351
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