1 //===-- CommunicationTest.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/Core/Communication.h" 10 #include "lldb/Host/Config.h" 11 #include "lldb/Host/ConnectionFileDescriptor.h" 12 #include "lldb/Host/Pipe.h" 13 #include "llvm/Testing/Support/Error.h" 14 #include "gtest/gtest.h" 15 16 #include <thread> 17 18 #if LLDB_ENABLE_POSIX 19 #include <fcntl.h> 20 #endif 21 22 using namespace lldb_private; 23 24 #ifndef _WIN32 25 TEST(CommunicationTest, SynchronizeWhileClosing) { 26 // Set up a communication object reading from a pipe. 27 Pipe pipe; 28 ASSERT_THAT_ERROR(pipe.CreateNew(/*child_process_inherit=*/false).ToError(), 29 llvm::Succeeded()); 30 31 Communication comm("test"); 32 comm.SetConnection(std::make_unique<ConnectionFileDescriptor>( 33 pipe.ReleaseReadFileDescriptor(), /*owns_fd=*/true)); 34 comm.SetCloseOnEOF(true); 35 ASSERT_TRUE(comm.StartReadThread()); 36 37 // Ensure that we can safely synchronize with the read thread while it is 38 // closing the read end (in response to us closing the write end). 39 pipe.CloseWriteFileDescriptor(); 40 comm.SynchronizeWithReadThread(); 41 42 ASSERT_TRUE(comm.StopReadThread()); 43 } 44 #endif 45 46 #if LLDB_ENABLE_POSIX 47 TEST(CommunicationTest, WriteAll) { 48 Pipe pipe; 49 ASSERT_THAT_ERROR(pipe.CreateNew(/*child_process_inherit=*/false).ToError(), 50 llvm::Succeeded()); 51 52 // Make the write end non-blocking in order to easily reproduce a partial 53 // write. 54 int write_fd = pipe.ReleaseWriteFileDescriptor(); 55 int flags = fcntl(write_fd, F_GETFL); 56 ASSERT_NE(flags, -1); 57 ASSERT_NE(fcntl(write_fd, F_SETFL, flags | O_NONBLOCK), -1); 58 59 ConnectionFileDescriptor read_conn{pipe.ReleaseReadFileDescriptor(), 60 /*owns_fd=*/true}; 61 Communication write_comm("test"); 62 write_comm.SetConnection( 63 std::make_unique<ConnectionFileDescriptor>(write_fd, /*owns_fd=*/true)); 64 65 std::thread read_thread{[&read_conn]() { 66 // Read using a smaller buffer to increase chances of partial write. 67 char buf[128 * 1024]; 68 lldb::ConnectionStatus conn_status; 69 70 do { 71 read_conn.Read(buf, sizeof(buf), std::chrono::seconds(1), conn_status, 72 nullptr); 73 } while (conn_status != lldb::eConnectionStatusEndOfFile); 74 }}; 75 76 // Write 1 MiB of data into the pipe. 77 lldb::ConnectionStatus conn_status; 78 Status error; 79 std::vector<uint8_t> data(1024 * 1024, 0x80); 80 EXPECT_EQ(write_comm.WriteAll(data.data(), data.size(), conn_status, &error), 81 data.size()); 82 EXPECT_EQ(conn_status, lldb::eConnectionStatusSuccess); 83 EXPECT_FALSE(error.Fail()); 84 85 // Close the write end in order to trigger EOF. 86 write_comm.Disconnect(); 87 read_thread.join(); 88 } 89 #endif 90