1 //===-- PipeTest.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/Pipe.h" 10 #include "TestingSupport/SubsystemRAII.h" 11 #include "lldb/Host/FileSystem.h" 12 #include "lldb/Host/HostInfo.h" 13 #include "gtest/gtest.h" 14 #include <fcntl.h> 15 #include <numeric> 16 #include <vector> 17 18 using namespace lldb_private; 19 20 class PipeTest : public testing::Test { 21 public: 22 SubsystemRAII<FileSystem, HostInfo> subsystems; 23 }; 24 25 TEST_F(PipeTest, CreateWithUniqueName) { 26 Pipe pipe; 27 llvm::SmallString<0> name; 28 ASSERT_THAT_ERROR(pipe.CreateWithUniqueName("PipeTest-CreateWithUniqueName", 29 /*child_process_inherit=*/false, 30 name) 31 .ToError(), 32 llvm::Succeeded()); 33 } 34 35 // Test broken 36 #ifndef _WIN32 37 TEST_F(PipeTest, OpenAsReader) { 38 Pipe pipe; 39 llvm::SmallString<0> name; 40 ASSERT_THAT_ERROR(pipe.CreateWithUniqueName("PipeTest-OpenAsReader", 41 /*child_process_inherit=*/false, 42 name) 43 .ToError(), 44 llvm::Succeeded()); 45 46 // Ensure name is not null-terminated 47 size_t name_len = name.size(); 48 name += "foobar"; 49 llvm::StringRef name_ref(name.data(), name_len); 50 ASSERT_THAT_ERROR( 51 pipe.OpenAsReader(name_ref, /*child_process_inherit=*/false).ToError(), 52 llvm::Succeeded()); 53 54 ASSERT_TRUE(pipe.CanRead()); 55 } 56 #endif 57 58 // This test is flaky on Windows on Arm. 59 #ifndef _WIN32 60 TEST_F(PipeTest, WriteWithTimeout) { 61 Pipe pipe; 62 ASSERT_THAT_ERROR(pipe.CreateNew(false).ToError(), llvm::Succeeded()); 63 64 // The pipe buffer is 1024 for PipeWindows and at least 512 on Darwin. 65 // In Linux versions before 2.6.11, the capacity of a pipe was the same as the 66 // system page size (e.g., 4096 bytes on i386). 67 // Since Linux 2.6.11, the pipe capacity is 16 pages (i.e., 65,536 bytes in a 68 // system with a page size of 4096 bytes). 69 // Since Linux 2.6.35, the default pipe capacity is 16 pages, but the capacity 70 // can be queried and set using the fcntl(2) F_GETPIPE_SZ and F_SETPIPE_SZ 71 // operations: 72 73 #if !defined(_WIN32) && defined(F_SETPIPE_SZ) 74 ::fcntl(pipe.GetWriteFileDescriptor(), F_SETPIPE_SZ, 4096); 75 #endif 76 77 const size_t buf_size = 66000; 78 79 // Note write_chunk_size must be less than the pipe buffer. 80 const size_t write_chunk_size = 234; 81 82 std::vector<int32_t> write_buf(buf_size / sizeof(int32_t)); 83 std::iota(write_buf.begin(), write_buf.end(), 0); 84 std::vector<int32_t> read_buf(write_buf.size() + 100, -1); 85 86 char *write_ptr = reinterpret_cast<char *>(write_buf.data()); 87 char *read_ptr = reinterpret_cast<char *>(read_buf.data()); 88 size_t write_bytes = 0; 89 size_t read_bytes = 0; 90 size_t num_bytes = 0; 91 92 // Write to the pipe until it is full. 93 while (write_bytes + write_chunk_size <= buf_size) { 94 Status error = 95 pipe.WriteWithTimeout(write_ptr + write_bytes, write_chunk_size, 96 std::chrono::milliseconds(10), num_bytes); 97 if (error.Fail()) 98 break; // The write buffer is full. 99 write_bytes += num_bytes; 100 } 101 ASSERT_LE(write_bytes + write_chunk_size, buf_size) 102 << "Pipe buffer larger than expected"; 103 104 // Attempt a write with a long timeout. 105 auto start_time = std::chrono::steady_clock::now(); 106 ASSERT_THAT_ERROR(pipe.WriteWithTimeout(write_ptr + write_bytes, 107 write_chunk_size, 108 std::chrono::seconds(2), num_bytes) 109 .ToError(), 110 llvm::Failed()); 111 auto dur = std::chrono::steady_clock::now() - start_time; 112 ASSERT_GE(dur, std::chrono::seconds(2)); 113 114 // Attempt a write with a short timeout. 115 start_time = std::chrono::steady_clock::now(); 116 ASSERT_THAT_ERROR( 117 pipe.WriteWithTimeout(write_ptr + write_bytes, write_chunk_size, 118 std::chrono::milliseconds(200), num_bytes) 119 .ToError(), 120 llvm::Failed()); 121 dur = std::chrono::steady_clock::now() - start_time; 122 ASSERT_GE(dur, std::chrono::milliseconds(200)); 123 ASSERT_LT(dur, std::chrono::seconds(2)); 124 125 // Drain the pipe. 126 while (read_bytes < write_bytes) { 127 ASSERT_THAT_ERROR( 128 pipe.ReadWithTimeout(read_ptr + read_bytes, write_bytes - read_bytes, 129 std::chrono::milliseconds(10), num_bytes) 130 .ToError(), 131 llvm::Succeeded()); 132 read_bytes += num_bytes; 133 } 134 135 // Be sure the pipe is empty. 136 ASSERT_THAT_ERROR(pipe.ReadWithTimeout(read_ptr + read_bytes, 100, 137 std::chrono::milliseconds(10), 138 num_bytes) 139 .ToError(), 140 llvm::Failed()); 141 142 // Check that we got what we wrote. 143 ASSERT_EQ(write_bytes, read_bytes); 144 ASSERT_TRUE(std::equal(write_buf.begin(), 145 write_buf.begin() + write_bytes / sizeof(uint32_t), 146 read_buf.begin())); 147 148 // Write to the pipe again and check that it succeeds. 149 ASSERT_THAT_ERROR(pipe.WriteWithTimeout(write_ptr, write_chunk_size, 150 std::chrono::milliseconds(10), 151 num_bytes) 152 .ToError(), 153 llvm::Succeeded()); 154 } 155 #endif /*ifndef _WIN32*/ 156