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/common/TCPSocket.h"
12 #include "gtest/gtest.h"
13 #include <future>
14 
15 using namespace lldb_private;
16 
17 namespace {
18 class MainLoopTest : public testing::Test {
19 public:
20   static void SetUpTestCase() {
21 #ifdef _MSC_VER
22     WSADATA data;
23     ASSERT_EQ(0, WSAStartup(MAKEWORD(2, 2), &data));
24 #endif
25   }
26 
27   static void TearDownTestCase() {
28 #ifdef _MSC_VER
29     ASSERT_EQ(0, WSACleanup());
30 #endif
31   }
32 
33   void SetUp() override {
34     bool child_processes_inherit = false;
35     Status error;
36     std::unique_ptr<TCPSocket> listen_socket_up(
37         new TCPSocket(true, child_processes_inherit));
38     ASSERT_TRUE(error.Success());
39     error = listen_socket_up->Listen("localhost:0", 5);
40     ASSERT_TRUE(error.Success());
41 
42     Socket *accept_socket;
43     std::future<Status> accept_error = std::async(std::launch::async, [&] {
44       return listen_socket_up->Accept(accept_socket);
45     });
46 
47     std::unique_ptr<TCPSocket> connect_socket_up(
48         new TCPSocket(true, child_processes_inherit));
49     error = connect_socket_up->Connect(
50         llvm::formatv("localhost:{0}", listen_socket_up->GetLocalPortNumber())
51             .str());
52     ASSERT_TRUE(error.Success());
53     ASSERT_TRUE(accept_error.get().Success());
54 
55     callback_count = 0;
56     socketpair[0] = std::move(connect_socket_up);
57     socketpair[1].reset(accept_socket);
58   }
59 
60   void TearDown() override {
61     socketpair[0].reset();
62     socketpair[1].reset();
63   }
64 
65 protected:
66   MainLoop::Callback make_callback() {
67     return [&](MainLoopBase &loop) {
68       ++callback_count;
69       loop.RequestTermination();
70     };
71   }
72   std::shared_ptr<Socket> socketpair[2];
73   unsigned callback_count;
74 };
75 } // namespace
76 
77 TEST_F(MainLoopTest, ReadObject) {
78   char X = 'X';
79   size_t len = sizeof(X);
80   ASSERT_TRUE(socketpair[0]->Write(&X, len).Success());
81 
82   MainLoop loop;
83 
84   Status error;
85   auto handle = loop.RegisterReadObject(socketpair[1], make_callback(), error);
86   ASSERT_TRUE(error.Success());
87   ASSERT_TRUE(handle);
88   ASSERT_TRUE(loop.Run().Success());
89   ASSERT_EQ(1u, callback_count);
90 }
91 
92 TEST_F(MainLoopTest, TerminatesImmediately) {
93   char X = 'X';
94   size_t len = sizeof(X);
95   ASSERT_TRUE(socketpair[0]->Write(&X, len).Success());
96   ASSERT_TRUE(socketpair[1]->Write(&X, len).Success());
97 
98   MainLoop loop;
99   Status error;
100   auto handle0 = loop.RegisterReadObject(socketpair[0], make_callback(), error);
101   ASSERT_TRUE(error.Success());
102   auto handle1 = loop.RegisterReadObject(socketpair[1], make_callback(), error);
103   ASSERT_TRUE(error.Success());
104 
105   ASSERT_TRUE(loop.Run().Success());
106   ASSERT_EQ(1u, callback_count);
107 }
108 
109 #ifdef LLVM_ON_UNIX
110 TEST_F(MainLoopTest, Signal) {
111   MainLoop loop;
112   Status error;
113 
114   auto handle = loop.RegisterSignal(SIGUSR1, make_callback(), error);
115   ASSERT_TRUE(error.Success());
116   kill(getpid(), SIGUSR1);
117   ASSERT_TRUE(loop.Run().Success());
118   ASSERT_EQ(1u, callback_count);
119 }
120 #endif
121