[NFC][Coroutines] Use structured binding with llvm::enumerate in CoroSplit (#116879)
[llvm-project.git] / lldb / unittests / Host / PipeTest.cpp
blob506f3d225a21ea5d63b9571d219e448290e9c8ee
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 //===----------------------------------------------------------------------===//
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>
18 using namespace lldb_private;
20 class PipeTest : public testing::Test {
21 public:
22 SubsystemRAII<FileSystem, HostInfo> subsystems;
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());
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());
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());
54 ASSERT_TRUE(pipe.CanRead());
56 #endif
58 TEST_F(PipeTest, WriteWithTimeout) {
59 Pipe pipe;
60 ASSERT_THAT_ERROR(pipe.CreateNew(false).ToError(), llvm::Succeeded());
62 // The pipe buffer is 1024 for PipeWindows and at least 512 on Darwin.
63 // In Linux versions before 2.6.11, the capacity of a pipe was the same as the
64 // system page size (e.g., 4096 bytes on i386).
65 // Since Linux 2.6.11, the pipe capacity is 16 pages (i.e., 65,536 bytes in a
66 // system with a page size of 4096 bytes).
67 // Since Linux 2.6.35, the default pipe capacity is 16 pages, but the capacity
68 // can be queried and set using the fcntl(2) F_GETPIPE_SZ and F_SETPIPE_SZ
69 // operations:
71 #if !defined(_WIN32) && defined(F_SETPIPE_SZ)
72 ::fcntl(pipe.GetWriteFileDescriptor(), F_SETPIPE_SZ, 4096);
73 #endif
75 const size_t buf_size = 66000;
77 // Note write_chunk_size must be less than the pipe buffer.
78 const size_t write_chunk_size = 234;
80 std::vector<int32_t> write_buf(buf_size / sizeof(int32_t));
81 std::iota(write_buf.begin(), write_buf.end(), 0);
82 std::vector<int32_t> read_buf(write_buf.size() + 100, -1);
84 char *write_ptr = reinterpret_cast<char *>(write_buf.data());
85 char *read_ptr = reinterpret_cast<char *>(read_buf.data());
86 size_t write_bytes = 0;
87 size_t read_bytes = 0;
88 size_t num_bytes = 0;
90 // Write to the pipe until it is full.
91 while (write_bytes + write_chunk_size <= buf_size) {
92 Status error =
93 pipe.WriteWithTimeout(write_ptr + write_bytes, write_chunk_size,
94 std::chrono::milliseconds(10), num_bytes);
95 if (error.Fail())
96 break; // The write buffer is full.
97 write_bytes += num_bytes;
99 ASSERT_LE(write_bytes + write_chunk_size, buf_size)
100 << "Pipe buffer larger than expected";
102 // Attempt a write with a long timeout.
103 auto start_time = std::chrono::steady_clock::now();
104 ASSERT_THAT_ERROR(pipe.WriteWithTimeout(write_ptr + write_bytes,
105 write_chunk_size,
106 std::chrono::seconds(2), num_bytes)
107 .ToError(),
108 llvm::Failed());
109 auto dur = std::chrono::steady_clock::now() - start_time;
110 ASSERT_GE(dur, std::chrono::seconds(2));
112 // Attempt a write with a short timeout.
113 start_time = std::chrono::steady_clock::now();
114 ASSERT_THAT_ERROR(
115 pipe.WriteWithTimeout(write_ptr + write_bytes, write_chunk_size,
116 std::chrono::milliseconds(200), num_bytes)
117 .ToError(),
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));
123 // Drain the pipe.
124 while (read_bytes < write_bytes) {
125 ASSERT_THAT_ERROR(
126 pipe.ReadWithTimeout(read_ptr + read_bytes, write_bytes - read_bytes,
127 std::chrono::milliseconds(10), num_bytes)
128 .ToError(),
129 llvm::Succeeded());
130 read_bytes += num_bytes;
133 // Be sure the pipe is empty.
134 ASSERT_THAT_ERROR(pipe.ReadWithTimeout(read_ptr + read_bytes, 100,
135 std::chrono::milliseconds(10),
136 num_bytes)
137 .ToError(),
138 llvm::Failed());
140 // Check that we got what we wrote.
141 ASSERT_EQ(write_bytes, read_bytes);
142 ASSERT_TRUE(std::equal(write_buf.begin(),
143 write_buf.begin() + write_bytes / sizeof(uint32_t),
144 read_buf.begin()));
146 // Write to the pipe again and check that it succeeds.
147 ASSERT_THAT_ERROR(pipe.WriteWithTimeout(write_ptr, write_chunk_size,
148 std::chrono::milliseconds(10),
149 num_bytes)
150 .ToError(),
151 llvm::Succeeded());