brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.2 KiB · 4ee3b53 Raw
198 lines · cpp
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-exception6//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 "llvm/Testing/Support/Error.h"14#include "gtest/gtest.h"15#include <chrono>16#include <fcntl.h>17#include <future>18#include <numeric>19#include <thread>20#include <vector>21 22using namespace lldb_private;23 24class PipeTest : public testing::Test {25public:26  SubsystemRAII<FileSystem, HostInfo> subsystems;27};28 29TEST_F(PipeTest, CreateWithUniqueName) {30  Pipe pipe;31  llvm::SmallString<0> name;32  ASSERT_THAT_ERROR(33      pipe.CreateWithUniqueName("PipeTest-CreateWithUniqueName", name)34          .ToError(),35      llvm::Succeeded());36}37 38// Test broken39#ifndef _WIN3240TEST_F(PipeTest, OpenAsReader) {41  Pipe pipe;42  llvm::SmallString<0> name;43  ASSERT_THAT_ERROR(44      pipe.CreateWithUniqueName("PipeTest-OpenAsReader", name).ToError(),45      llvm::Succeeded());46 47  // Ensure name is not null-terminated48  size_t name_len = name.size();49  name += "foobar";50  llvm::StringRef name_ref(name.data(), name_len);51  ASSERT_THAT_ERROR(pipe.OpenAsReader(name_ref).ToError(), llvm::Succeeded());52 53  ASSERT_TRUE(pipe.CanRead());54}55#endif56 57// Tests flaky on Windows58#ifndef _WIN3259TEST_F(PipeTest, WriteWithTimeout) {60  Pipe pipe;61  ASSERT_THAT_ERROR(pipe.CreateNew().ToError(), llvm::Succeeded());62 63  // The pipe buffer is 1024 for PipeWindows and at least 512 on Darwin.64  // In Linux versions before 2.6.11, the capacity of a pipe was the same as the65  // system page size (e.g., 4096 bytes on i386).66  // Since Linux 2.6.11, the pipe capacity is 16 pages (i.e., 65,536 bytes in a67  // system with a page size of 4096 bytes).68  // Since Linux 2.6.35, the default pipe capacity is 16 pages, but the capacity69  // can be queried and set using the fcntl(2) F_GETPIPE_SZ and F_SETPIPE_SZ70  // operations:71 72#if !defined(_WIN32) && defined(F_SETPIPE_SZ)73  ::fcntl(pipe.GetWriteFileDescriptor(), F_SETPIPE_SZ, 4096);74#endif75 76  const size_t buf_size = 66000;77 78  // Note write_chunk_size must be less than the pipe buffer.79  const size_t write_chunk_size = 234;80 81  std::vector<int32_t> write_buf(buf_size / sizeof(int32_t));82  std::iota(write_buf.begin(), write_buf.end(), 0);83  std::vector<int32_t> read_buf(write_buf.size() + 100, -1);84 85  char *write_ptr = reinterpret_cast<char *>(write_buf.data());86  char *read_ptr = reinterpret_cast<char *>(read_buf.data());87  size_t write_bytes = 0;88  size_t read_bytes = 0;89 90  // Write to the pipe until it is full.91  while (write_bytes + write_chunk_size <= buf_size) {92    llvm::Expected<size_t> num_bytes =93        pipe.Write(write_ptr + write_bytes, write_chunk_size,94                   std::chrono::milliseconds(10));95    if (num_bytes) {96      write_bytes += *num_bytes;97    } else {98      ASSERT_THAT_ERROR(num_bytes.takeError(), llvm::Failed());99      break; // The write buffer is full.100    }101  }102  ASSERT_LE(write_bytes + write_chunk_size, buf_size)103      << "Pipe buffer larger than expected";104 105  // Attempt a write with a long timeout.106  auto start_time = std::chrono::steady_clock::now();107  // TODO: Assert a specific error (EAGAIN?) here.108  ASSERT_THAT_EXPECTED(pipe.Write(write_ptr + write_bytes, write_chunk_size,109                                  std::chrono::seconds(2)),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_EXPECTED(pipe.Write(write_ptr + write_bytes, write_chunk_size,117                                  std::chrono::milliseconds(200)),118                       llvm::Failed());119  dur = std::chrono::steady_clock::now() - start_time;120  ASSERT_GE(dur, std::chrono::milliseconds(200));121  ASSERT_LT(dur, std::chrono::seconds(2));122 123  // Drain the pipe.124  while (read_bytes < write_bytes) {125    llvm::Expected<size_t> num_bytes =126        pipe.Read(read_ptr + read_bytes, write_bytes - read_bytes,127                  std::chrono::milliseconds(10));128    ASSERT_THAT_EXPECTED(num_bytes, llvm::Succeeded());129    read_bytes += *num_bytes;130  }131 132  // Be sure the pipe is empty.133  ASSERT_THAT_EXPECTED(134      pipe.Read(read_ptr + read_bytes, 100, std::chrono::milliseconds(10)),135      llvm::Failed());136 137  // Check that we got what we wrote.138  ASSERT_EQ(write_bytes, read_bytes);139  ASSERT_TRUE(std::equal(write_buf.begin(),140                         write_buf.begin() + write_bytes / sizeof(uint32_t),141                         read_buf.begin()));142 143  // Write to the pipe again and check that it succeeds.144  ASSERT_THAT_EXPECTED(145      pipe.Write(write_ptr, write_chunk_size, std::chrono::milliseconds(10)),146      llvm::Succeeded());147}148 149TEST_F(PipeTest, ReadWithTimeout) {150  Pipe pipe;151  ASSERT_THAT_ERROR(pipe.CreateNew().ToError(), llvm::Succeeded());152 153  char buf[100];154  // The pipe is initially empty. A polling read returns immediately.155  ASSERT_THAT_EXPECTED(pipe.Read(buf, sizeof(buf), std::chrono::seconds(0)),156                       llvm::Failed());157 158  // With a timeout, we should wait for at least this amount of time (but not159  // too much).160  auto start = std::chrono::steady_clock::now();161  ASSERT_THAT_EXPECTED(162      pipe.Read(buf, sizeof(buf), std::chrono::milliseconds(200)),163      llvm::Failed());164  auto dur = std::chrono::steady_clock::now() - start;165  EXPECT_GT(dur, std::chrono::milliseconds(200));166  EXPECT_LT(dur, std::chrono::seconds(2));167 168  // Write something into the pipe, and read it back. The blocking read call169  // should return even though it hasn't filled the buffer.170  llvm::StringRef hello_world("Hello world!");171  ASSERT_THAT_EXPECTED(pipe.Write(hello_world.data(), hello_world.size()),172                       llvm::HasValue(hello_world.size()));173  ASSERT_THAT_EXPECTED(pipe.Read(buf, sizeof(buf)),174                       llvm::HasValue(hello_world.size()));175  EXPECT_EQ(llvm::StringRef(buf, hello_world.size()), hello_world);176 177  // Now write something and try to read it in chunks.178  memset(buf, 0, sizeof(buf));179  ASSERT_THAT_EXPECTED(pipe.Write(hello_world.data(), hello_world.size()),180                       llvm::HasValue(hello_world.size()));181  ASSERT_THAT_EXPECTED(pipe.Read(buf, 4), llvm::HasValue(4));182  ASSERT_THAT_EXPECTED(pipe.Read(buf + 4, sizeof(buf) - 4),183                       llvm::HasValue(hello_world.size() - 4));184  EXPECT_EQ(llvm::StringRef(buf, hello_world.size()), hello_world);185 186  // A blocking read should wait until the data arrives.187  memset(buf, 0, sizeof(buf));188  std::future<llvm::Expected<size_t>> future_num_bytes = std::async(189      std::launch::async, [&] { return pipe.Read(buf, sizeof(buf)); });190  std::this_thread::sleep_for(std::chrono::milliseconds(10));191  ASSERT_THAT_EXPECTED(pipe.Write(hello_world.data(), hello_world.size()),192                       llvm::HasValue(hello_world.size()));193  ASSERT_THAT_EXPECTED(future_num_bytes.get(),194                       llvm::HasValue(hello_world.size()));195  EXPECT_EQ(llvm::StringRef(buf, hello_world.size()), hello_world);196}197#endif /*ifndef _WIN32*/198