1 //===-- MainLoopTest.cpp ----------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Host/MainLoop.h" 11 #include "lldb/Host/ConnectionFileDescriptor.h" 12 #include "lldb/Host/PseudoTerminal.h" 13 #include "lldb/Host/common/TCPSocket.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 #ifdef _MSC_VER 24 WSADATA data; 25 ASSERT_EQ(0, WSAStartup(MAKEWORD(2, 2), &data)); 26 #endif 27 } 28 29 static void TearDownTestCase() { 30 #ifdef _MSC_VER 31 ASSERT_EQ(0, WSACleanup()); 32 #endif 33 } 34 35 void SetUp() override { 36 bool child_processes_inherit = false; 37 Status error; 38 std::unique_ptr<TCPSocket> listen_socket_up( 39 new TCPSocket(true, child_processes_inherit)); 40 ASSERT_TRUE(error.Success()); 41 error = listen_socket_up->Listen("localhost:0", 5); 42 ASSERT_TRUE(error.Success()); 43 44 Socket *accept_socket; 45 std::future<Status> accept_error = std::async(std::launch::async, [&] { 46 return listen_socket_up->Accept(accept_socket); 47 }); 48 49 std::unique_ptr<TCPSocket> connect_socket_up( 50 new TCPSocket(true, child_processes_inherit)); 51 error = connect_socket_up->Connect( 52 llvm::formatv("localhost:{0}", listen_socket_up->GetLocalPortNumber()) 53 .str()); 54 ASSERT_TRUE(error.Success()); 55 ASSERT_TRUE(accept_error.get().Success()); 56 57 callback_count = 0; 58 socketpair[0] = std::move(connect_socket_up); 59 socketpair[1].reset(accept_socket); 60 } 61 62 void TearDown() override { 63 socketpair[0].reset(); 64 socketpair[1].reset(); 65 } 66 67 protected: 68 MainLoop::Callback make_callback() { 69 return [&](MainLoopBase &loop) { 70 ++callback_count; 71 loop.RequestTermination(); 72 }; 73 } 74 std::shared_ptr<Socket> socketpair[2]; 75 unsigned callback_count; 76 }; 77 } // namespace 78 79 TEST_F(MainLoopTest, ReadObject) { 80 char X = 'X'; 81 size_t len = sizeof(X); 82 ASSERT_TRUE(socketpair[0]->Write(&X, len).Success()); 83 84 MainLoop loop; 85 86 Status error; 87 auto handle = loop.RegisterReadObject(socketpair[1], make_callback(), error); 88 ASSERT_TRUE(error.Success()); 89 ASSERT_TRUE(handle); 90 ASSERT_TRUE(loop.Run().Success()); 91 ASSERT_EQ(1u, callback_count); 92 } 93 94 TEST_F(MainLoopTest, TerminatesImmediately) { 95 char X = 'X'; 96 size_t len = sizeof(X); 97 ASSERT_TRUE(socketpair[0]->Write(&X, len).Success()); 98 ASSERT_TRUE(socketpair[1]->Write(&X, len).Success()); 99 100 MainLoop loop; 101 Status error; 102 auto handle0 = loop.RegisterReadObject(socketpair[0], make_callback(), error); 103 ASSERT_TRUE(error.Success()); 104 auto handle1 = loop.RegisterReadObject(socketpair[1], make_callback(), error); 105 ASSERT_TRUE(error.Success()); 106 107 ASSERT_TRUE(loop.Run().Success()); 108 ASSERT_EQ(1u, callback_count); 109 } 110 111 #ifdef LLVM_ON_UNIX 112 TEST_F(MainLoopTest, DetectsEOF) { 113 PseudoTerminal term; 114 ASSERT_TRUE(term.OpenFirstAvailableMaster(O_RDWR, nullptr, 0)); 115 ASSERT_TRUE(term.OpenSlave(O_RDWR | O_NOCTTY, nullptr, 0)); 116 auto conn = llvm::make_unique<ConnectionFileDescriptor>( 117 term.ReleaseMasterFileDescriptor(), true); 118 119 Status error; 120 MainLoop loop; 121 auto handle = 122 loop.RegisterReadObject(conn->GetReadObject(), make_callback(), error); 123 ASSERT_TRUE(error.Success()); 124 term.CloseSlaveFileDescriptor(); 125 126 ASSERT_TRUE(loop.Run().Success()); 127 ASSERT_EQ(1u, callback_count); 128 } 129 130 TEST_F(MainLoopTest, Signal) { 131 MainLoop loop; 132 Status error; 133 134 auto handle = loop.RegisterSignal(SIGUSR1, make_callback(), error); 135 ASSERT_TRUE(error.Success()); 136 kill(getpid(), SIGUSR1); 137 ASSERT_TRUE(loop.Run().Success()); 138 ASSERT_EQ(1u, callback_count); 139 } 140 #endif 141