1 //===-- MainLoopTest.cpp ----------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Host/MainLoop.h" 10 #include "lldb/Host/ConnectionFileDescriptor.h" 11 #include "lldb/Host/PseudoTerminal.h" 12 #include "lldb/Host/common/TCPSocket.h" 13 #include "llvm/Testing/Support/Error.h" 14 #include "gtest/gtest.h" 15 #include <future> 16 17 using namespace lldb_private; 18 19 namespace { 20 class MainLoopTest : public testing::Test { 21 public: 22 static void SetUpTestCase() { 23 ASSERT_THAT_ERROR(Socket::Initialize(), llvm::Succeeded()); 24 } 25 26 static void TearDownTestCase() { Socket::Terminate(); } 27 28 void SetUp() override { 29 bool child_processes_inherit = false; 30 Status error; 31 std::unique_ptr<TCPSocket> listen_socket_up( 32 new TCPSocket(true, child_processes_inherit)); 33 ASSERT_TRUE(error.Success()); 34 error = listen_socket_up->Listen("localhost:0", 5); 35 ASSERT_TRUE(error.Success()); 36 37 Socket *accept_socket; 38 std::future<Status> accept_error = std::async(std::launch::async, [&] { 39 return listen_socket_up->Accept(accept_socket); 40 }); 41 42 std::unique_ptr<TCPSocket> connect_socket_up( 43 new TCPSocket(true, child_processes_inherit)); 44 error = connect_socket_up->Connect( 45 llvm::formatv("localhost:{0}", listen_socket_up->GetLocalPortNumber()) 46 .str()); 47 ASSERT_TRUE(error.Success()); 48 ASSERT_TRUE(accept_error.get().Success()); 49 50 callback_count = 0; 51 socketpair[0] = std::move(connect_socket_up); 52 socketpair[1].reset(accept_socket); 53 } 54 55 void TearDown() override { 56 socketpair[0].reset(); 57 socketpair[1].reset(); 58 } 59 60 protected: 61 MainLoop::Callback make_callback() { 62 return [&](MainLoopBase &loop) { 63 ++callback_count; 64 loop.RequestTermination(); 65 }; 66 } 67 std::shared_ptr<Socket> socketpair[2]; 68 unsigned callback_count; 69 }; 70 } // namespace 71 72 TEST_F(MainLoopTest, ReadObject) { 73 char X = 'X'; 74 size_t len = sizeof(X); 75 ASSERT_TRUE(socketpair[0]->Write(&X, len).Success()); 76 77 MainLoop loop; 78 79 Status error; 80 auto handle = loop.RegisterReadObject(socketpair[1], make_callback(), error); 81 ASSERT_TRUE(error.Success()); 82 ASSERT_TRUE(handle); 83 ASSERT_TRUE(loop.Run().Success()); 84 ASSERT_EQ(1u, callback_count); 85 } 86 87 TEST_F(MainLoopTest, TerminatesImmediately) { 88 char X = 'X'; 89 size_t len = sizeof(X); 90 ASSERT_TRUE(socketpair[0]->Write(&X, len).Success()); 91 ASSERT_TRUE(socketpair[1]->Write(&X, len).Success()); 92 93 MainLoop loop; 94 Status error; 95 auto handle0 = loop.RegisterReadObject(socketpair[0], make_callback(), error); 96 ASSERT_TRUE(error.Success()); 97 auto handle1 = loop.RegisterReadObject(socketpair[1], make_callback(), error); 98 ASSERT_TRUE(error.Success()); 99 100 ASSERT_TRUE(loop.Run().Success()); 101 ASSERT_EQ(1u, callback_count); 102 } 103 104 #ifdef LLVM_ON_UNIX 105 // NetBSD currently does not report slave pty EOF via kevent 106 // causing this test to hang forever. 107 #ifndef __NetBSD__ 108 TEST_F(MainLoopTest, DetectsEOF) { 109 110 PseudoTerminal term; 111 ASSERT_TRUE(term.OpenFirstAvailableMaster(O_RDWR, nullptr, 0)); 112 ASSERT_TRUE(term.OpenSlave(O_RDWR | O_NOCTTY, nullptr, 0)); 113 auto conn = llvm::make_unique<ConnectionFileDescriptor>( 114 term.ReleaseMasterFileDescriptor(), true); 115 116 Status error; 117 MainLoop loop; 118 auto handle = 119 loop.RegisterReadObject(conn->GetReadObject(), make_callback(), error); 120 ASSERT_TRUE(error.Success()); 121 term.CloseSlaveFileDescriptor(); 122 123 ASSERT_TRUE(loop.Run().Success()); 124 ASSERT_EQ(1u, callback_count); 125 } 126 #endif 127 128 TEST_F(MainLoopTest, Signal) { 129 MainLoop loop; 130 Status error; 131 132 auto handle = loop.RegisterSignal(SIGUSR1, make_callback(), error); 133 ASSERT_TRUE(error.Success()); 134 kill(getpid(), SIGUSR1); 135 ASSERT_TRUE(loop.Run().Success()); 136 ASSERT_EQ(1u, callback_count); 137 } 138 139 // Test that a signal which is not monitored by the MainLoop does not 140 // cause a premature exit. 141 TEST_F(MainLoopTest, UnmonitoredSignal) { 142 MainLoop loop; 143 Status error; 144 struct sigaction sa; 145 sa.sa_sigaction = [](int, siginfo_t *, void *) { }; 146 sa.sa_flags = SA_SIGINFO; // important: no SA_RESTART 147 sigemptyset(&sa.sa_mask); 148 ASSERT_EQ(0, sigaction(SIGUSR2, &sa, nullptr)); 149 150 auto handle = loop.RegisterSignal(SIGUSR1, make_callback(), error); 151 ASSERT_TRUE(error.Success()); 152 std::thread killer([]() { 153 sleep(1); 154 kill(getpid(), SIGUSR2); 155 sleep(1); 156 kill(getpid(), SIGUSR1); 157 }); 158 ASSERT_TRUE(loop.Run().Success()); 159 killer.join(); 160 ASSERT_EQ(1u, callback_count); 161 } 162 #endif 163