xref: /aosp_15_r20/external/perfetto/src/base/threading/channel_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "perfetto/ext/base/threading/channel.h"
18 
19 #include <array>
20 #include <memory>
21 #include <optional>
22 
23 #include "perfetto/base/platform_handle.h"
24 #include "perfetto/ext/base/file_utils.h"
25 #include "perfetto/ext/base/utils.h"
26 #include "test/gtest_and_gmock.h"
27 
28 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
29 #include <Windows.h>
30 #include <synchapi.h>
31 #else
32 #include <poll.h>
33 #endif
34 
35 namespace perfetto {
36 namespace base {
37 namespace {
38 
39 using ReadResult = Channel<int>::ReadResult;
40 using WriteResult = Channel<int>::WriteResult;
41 
IsReady(base::PlatformHandle fd)42 bool IsReady(base::PlatformHandle fd) {
43 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
44   std::array<base::PlatformHandle, 1> poll_fds{fd};
45   DWORD ret =
46       WaitForMultipleObjects(static_cast<DWORD>(poll_fds.size()), &poll_fds[0],
47                              /*bWaitAll=*/false, 0);
48   PERFETTO_CHECK(ret == WAIT_TIMEOUT || ret == 0);
49   return ret == 0;
50 #else
51   std::array<struct pollfd, 1> poll_fds;
52   poll_fds[0].fd = fd;
53   poll_fds[0].events = POLLIN | POLLHUP;
54   poll_fds[0].revents = 0;
55 
56   int ret = PERFETTO_EINTR(
57       poll(&poll_fds[0], static_cast<nfds_t>(poll_fds.size()), 0));
58   PERFETTO_CHECK(ret == 0 || ret == 1);
59   return ret == 1;
60 #endif
61 }
62 
TEST(ChannelUnittest,SingleElementBuffer)63 TEST(ChannelUnittest, SingleElementBuffer) {
64   Channel<int> channel(1);
65   ASSERT_TRUE(IsReady(channel.write_fd()));
66   ASSERT_FALSE(IsReady(channel.read_fd()));
67 
68   ASSERT_EQ(channel.WriteNonBlocking(100), WriteResult(true, false));
69   ASSERT_EQ(channel.WriteNonBlocking(101), WriteResult(false, false));
70 
71   ASSERT_FALSE(IsReady(channel.write_fd()));
72   ASSERT_TRUE(IsReady(channel.read_fd()));
73 
74   ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(100, false));
75   ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(std::nullopt, false));
76 
77   ASSERT_TRUE(IsReady(channel.write_fd()));
78   ASSERT_FALSE(IsReady(channel.read_fd()));
79 }
80 
TEST(ChannelUnittest,MultiElementBuffer)81 TEST(ChannelUnittest, MultiElementBuffer) {
82   Channel<int> channel(2);
83   ASSERT_TRUE(IsReady(channel.write_fd()));
84   ASSERT_FALSE(IsReady(channel.read_fd()));
85 
86   ASSERT_EQ(channel.WriteNonBlocking(100), WriteResult(true, false));
87   ASSERT_TRUE(IsReady(channel.write_fd()));
88   ASSERT_TRUE(IsReady(channel.read_fd()));
89 
90   ASSERT_EQ(channel.WriteNonBlocking(101), WriteResult(true, false));
91   ASSERT_FALSE(IsReady(channel.write_fd()));
92   ASSERT_TRUE(IsReady(channel.read_fd()));
93 
94   ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(100, false));
95   ASSERT_TRUE(IsReady(channel.write_fd()));
96   ASSERT_TRUE(IsReady(channel.read_fd()));
97 
98   ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(101, false));
99   ASSERT_TRUE(IsReady(channel.write_fd()));
100   ASSERT_FALSE(IsReady(channel.read_fd()));
101 
102   ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(std::nullopt, false));
103   ASSERT_TRUE(IsReady(channel.write_fd()));
104   ASSERT_FALSE(IsReady(channel.read_fd()));
105 }
106 
TEST(ChannelUnittest,CloseEmptyChannel)107 TEST(ChannelUnittest, CloseEmptyChannel) {
108   Channel<int> channel(1);
109 
110   ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(std::nullopt, false));
111   ASSERT_FALSE(IsReady(channel.read_fd()));
112 
113   channel.Close();
114 
115   ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(std::nullopt, true));
116   ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(std::nullopt, true));
117 
118   ASSERT_TRUE(IsReady(channel.read_fd()));
119   ASSERT_TRUE(IsReady(channel.read_fd()));
120 }
121 
TEST(ChannelUnittest,WriteDoesNotMoveIfFalse)122 TEST(ChannelUnittest, WriteDoesNotMoveIfFalse) {
123   Channel<std::unique_ptr<int>> channel(1);
124 
125   std::unique_ptr<int> first(new int(100));
126   int* first_ptr = first.get();
127   ASSERT_EQ(channel.WriteNonBlocking(std::move(first)),
128             Channel<std::unique_ptr<int>>::WriteResult(true, false));
129   ASSERT_EQ(first.get(), nullptr);
130 
131   std::unique_ptr<int> second(new int(101));
132   ASSERT_EQ(channel.WriteNonBlocking(std::move(second)),
133             Channel<std::unique_ptr<int>>::WriteResult(false, false));
134   ASSERT_NE(second.get(), nullptr);
135   ASSERT_EQ(*second, 101);
136 
137   auto res = channel.ReadNonBlocking();
138   ASSERT_EQ(res.item->get(), first_ptr);
139 }
140 
TEST(ChannelUnittest,ReadAfterClose)141 TEST(ChannelUnittest, ReadAfterClose) {
142   Channel<int> channel(1);
143   ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(std::nullopt, false));
144   ASSERT_EQ(channel.WriteNonBlocking(100), WriteResult(true, false));
145   channel.Close();
146 
147   ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(100, true));
148   ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(std::nullopt, true));
149 }
150 
TEST(ChannelUnittest,WriteAfterClose)151 TEST(ChannelUnittest, WriteAfterClose) {
152   Channel<int> channel(1);
153   ASSERT_EQ(channel.WriteNonBlocking(100), WriteResult(true, false));
154   ASSERT_EQ(channel.WriteNonBlocking(101), WriteResult(false, false));
155   ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(100, false));
156   channel.Close();
157 
158   ASSERT_EQ(channel.WriteNonBlocking(101), WriteResult(false, true));
159 }
160 
TEST(ChannelUnittest,EmptyClosedChannel)161 TEST(ChannelUnittest, EmptyClosedChannel) {
162   Channel<int> channel(1);
163   ASSERT_FALSE(IsReady(channel.read_fd()));
164   ASSERT_TRUE(IsReady(channel.write_fd()));
165   channel.Close();
166   ASSERT_TRUE(IsReady(channel.write_fd()));
167   ASSERT_TRUE(IsReady(channel.write_fd()));
168   ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(std::nullopt, true));
169   ASSERT_TRUE(IsReady(channel.write_fd()));
170   ASSERT_TRUE(IsReady(channel.read_fd()));
171 }
172 
TEST(ChannelUnittest,FullClosedChannel)173 TEST(ChannelUnittest, FullClosedChannel) {
174   Channel<int> channel(1);
175   ASSERT_FALSE(IsReady(channel.read_fd()));
176   ASSERT_EQ(channel.WriteNonBlocking(100), WriteResult(true, false));
177   ASSERT_TRUE(IsReady(channel.read_fd()));
178   ASSERT_FALSE(IsReady(channel.write_fd()));
179   channel.Close();
180   ASSERT_TRUE(IsReady(channel.write_fd()));
181 
182   ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(100, true));
183   ASSERT_TRUE(IsReady(channel.write_fd()));
184   ASSERT_TRUE(IsReady(channel.read_fd()));
185 }
186 
187 }  // namespace
188 }  // namespace base
189 }  // namespace perfetto
190