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