1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2023 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker *
4*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker *
8*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker *
10*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker */
16*6dbdd20aSAndroid Build Coastguard Worker
17*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/threading/util.h"
18*6dbdd20aSAndroid Build Coastguard Worker
19*6dbdd20aSAndroid Build Coastguard Worker #include <optional>
20*6dbdd20aSAndroid Build Coastguard Worker
21*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/flat_set.h"
22*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/platform_handle.h"
23*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/time.h"
24*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/event_fd.h"
25*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/threading/channel.h"
26*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/threading/poll.h"
27*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/threading/stream.h"
28*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/threading/thread_pool.h"
29*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/unix_task_runner.h"
30*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/waitable_event.h"
31*6dbdd20aSAndroid Build Coastguard Worker #include "test/gtest_and_gmock.h"
32*6dbdd20aSAndroid Build Coastguard Worker
33*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
34*6dbdd20aSAndroid Build Coastguard Worker namespace base {
35*6dbdd20aSAndroid Build Coastguard Worker namespace {
36*6dbdd20aSAndroid Build Coastguard Worker
WaitForFutureReady(base::Future<int> & stream,base::FlatSet<base::PlatformHandle> & interested,PollContext & ctx)37*6dbdd20aSAndroid Build Coastguard Worker int WaitForFutureReady(base::Future<int>& stream,
38*6dbdd20aSAndroid Build Coastguard Worker base::FlatSet<base::PlatformHandle>& interested,
39*6dbdd20aSAndroid Build Coastguard Worker PollContext& ctx) {
40*6dbdd20aSAndroid Build Coastguard Worker auto res = stream.Poll(&ctx);
41*6dbdd20aSAndroid Build Coastguard Worker for (; res.IsPending(); res = stream.Poll(&ctx)) {
42*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(interested.size() == 1);
43*6dbdd20aSAndroid Build Coastguard Worker base::BlockUntilReadableFd(*interested.begin());
44*6dbdd20aSAndroid Build Coastguard Worker interested = {};
45*6dbdd20aSAndroid Build Coastguard Worker }
46*6dbdd20aSAndroid Build Coastguard Worker return res.item();
47*6dbdd20aSAndroid Build Coastguard Worker }
48*6dbdd20aSAndroid Build Coastguard Worker
WaitForStreamReady(base::Stream<int> & stream,base::FlatSet<base::PlatformHandle> & interested,PollContext & ctx)49*6dbdd20aSAndroid Build Coastguard Worker std::optional<int> WaitForStreamReady(
50*6dbdd20aSAndroid Build Coastguard Worker base::Stream<int>& stream,
51*6dbdd20aSAndroid Build Coastguard Worker base::FlatSet<base::PlatformHandle>& interested,
52*6dbdd20aSAndroid Build Coastguard Worker PollContext& ctx) {
53*6dbdd20aSAndroid Build Coastguard Worker auto res = stream.PollNext(&ctx);
54*6dbdd20aSAndroid Build Coastguard Worker for (; res.IsPending(); res = stream.PollNext(&ctx)) {
55*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(interested.size() == 1);
56*6dbdd20aSAndroid Build Coastguard Worker base::BlockUntilReadableFd(*interested.begin());
57*6dbdd20aSAndroid Build Coastguard Worker interested = {};
58*6dbdd20aSAndroid Build Coastguard Worker }
59*6dbdd20aSAndroid Build Coastguard Worker return res.IsDone() ? std::nullopt : std::make_optional(res.item());
60*6dbdd20aSAndroid Build Coastguard Worker }
61*6dbdd20aSAndroid Build Coastguard Worker
TEST(UtilUnittest,BlockUntilReadableFd)62*6dbdd20aSAndroid Build Coastguard Worker TEST(UtilUnittest, BlockUntilReadableFd) {
63*6dbdd20aSAndroid Build Coastguard Worker base::WaitableEvent evt;
64*6dbdd20aSAndroid Build Coastguard Worker base::EventFd main_to_background;
65*6dbdd20aSAndroid Build Coastguard Worker base::EventFd background_to_main;
66*6dbdd20aSAndroid Build Coastguard Worker std::thread thread([&main_to_background, &background_to_main] {
67*6dbdd20aSAndroid Build Coastguard Worker base::BlockUntilReadableFd(main_to_background.fd());
68*6dbdd20aSAndroid Build Coastguard Worker background_to_main.Notify();
69*6dbdd20aSAndroid Build Coastguard Worker });
70*6dbdd20aSAndroid Build Coastguard Worker main_to_background.Notify();
71*6dbdd20aSAndroid Build Coastguard Worker base::BlockUntilReadableFd(background_to_main.fd());
72*6dbdd20aSAndroid Build Coastguard Worker thread.join();
73*6dbdd20aSAndroid Build Coastguard Worker }
74*6dbdd20aSAndroid Build Coastguard Worker
TEST(UtilUnittest,ReadChannelStream)75*6dbdd20aSAndroid Build Coastguard Worker TEST(UtilUnittest, ReadChannelStream) {
76*6dbdd20aSAndroid Build Coastguard Worker base::Channel<int> channel(1);
77*6dbdd20aSAndroid Build Coastguard Worker auto stream = base::ReadChannelStream(&channel);
78*6dbdd20aSAndroid Build Coastguard Worker
79*6dbdd20aSAndroid Build Coastguard Worker base::FlatSet<base::PlatformHandle> interested;
80*6dbdd20aSAndroid Build Coastguard Worker base::FlatSet<base::PlatformHandle> ready;
81*6dbdd20aSAndroid Build Coastguard Worker PollContext ctx(&interested, &ready);
82*6dbdd20aSAndroid Build Coastguard Worker
83*6dbdd20aSAndroid Build Coastguard Worker ASSERT_TRUE(stream.PollNext(&ctx).IsPending());
84*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(interested.count(channel.read_fd()), 1u);
85*6dbdd20aSAndroid Build Coastguard Worker interested = {};
86*6dbdd20aSAndroid Build Coastguard Worker
87*6dbdd20aSAndroid Build Coastguard Worker ASSERT_TRUE(channel.WriteNonBlocking(1).success);
88*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(stream.PollNext(&ctx).item(), 1);
89*6dbdd20aSAndroid Build Coastguard Worker
90*6dbdd20aSAndroid Build Coastguard Worker ASSERT_TRUE(stream.PollNext(&ctx).IsPending());
91*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(interested.count(channel.read_fd()), 1u);
92*6dbdd20aSAndroid Build Coastguard Worker interested = {};
93*6dbdd20aSAndroid Build Coastguard Worker
94*6dbdd20aSAndroid Build Coastguard Worker ASSERT_TRUE(channel.WriteNonBlocking(2).success);
95*6dbdd20aSAndroid Build Coastguard Worker channel.Close();
96*6dbdd20aSAndroid Build Coastguard Worker
97*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(stream.PollNext(&ctx).item(), 2);
98*6dbdd20aSAndroid Build Coastguard Worker ASSERT_TRUE(stream.PollNext(&ctx).IsDone());
99*6dbdd20aSAndroid Build Coastguard Worker }
100*6dbdd20aSAndroid Build Coastguard Worker
TEST(UtilUnittest,WriteChannelFuture)101*6dbdd20aSAndroid Build Coastguard Worker TEST(UtilUnittest, WriteChannelFuture) {
102*6dbdd20aSAndroid Build Coastguard Worker base::Channel<int> channel(1);
103*6dbdd20aSAndroid Build Coastguard Worker
104*6dbdd20aSAndroid Build Coastguard Worker base::FlatSet<base::PlatformHandle> interested;
105*6dbdd20aSAndroid Build Coastguard Worker base::FlatSet<base::PlatformHandle> ready;
106*6dbdd20aSAndroid Build Coastguard Worker PollContext ctx(&interested, &ready);
107*6dbdd20aSAndroid Build Coastguard Worker
108*6dbdd20aSAndroid Build Coastguard Worker ASSERT_TRUE(channel.WriteNonBlocking(1).success);
109*6dbdd20aSAndroid Build Coastguard Worker ASSERT_FALSE(channel.WriteNonBlocking(2).success);
110*6dbdd20aSAndroid Build Coastguard Worker
111*6dbdd20aSAndroid Build Coastguard Worker auto future = base::WriteChannelFuture(&channel, 3);
112*6dbdd20aSAndroid Build Coastguard Worker ASSERT_TRUE(future.Poll(&ctx).IsPending());
113*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(interested.count(channel.write_fd()), 1u);
114*6dbdd20aSAndroid Build Coastguard Worker interested = {};
115*6dbdd20aSAndroid Build Coastguard Worker
116*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(channel.ReadNonBlocking().item, 1);
117*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(channel.ReadNonBlocking().item, std::nullopt);
118*6dbdd20aSAndroid Build Coastguard Worker
119*6dbdd20aSAndroid Build Coastguard Worker ASSERT_FALSE(future.Poll(&ctx).IsPending());
120*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(channel.ReadNonBlocking().item, 3);
121*6dbdd20aSAndroid Build Coastguard Worker }
122*6dbdd20aSAndroid Build Coastguard Worker
TEST(UtilUnittest,RunOnThreadPool)123*6dbdd20aSAndroid Build Coastguard Worker TEST(UtilUnittest, RunOnThreadPool) {
124*6dbdd20aSAndroid Build Coastguard Worker base::FlatSet<base::PlatformHandle> interested;
125*6dbdd20aSAndroid Build Coastguard Worker base::FlatSet<base::PlatformHandle> ready;
126*6dbdd20aSAndroid Build Coastguard Worker PollContext ctx(&interested, &ready);
127*6dbdd20aSAndroid Build Coastguard Worker
128*6dbdd20aSAndroid Build Coastguard Worker base::ThreadPool pool(1);
129*6dbdd20aSAndroid Build Coastguard Worker base::Stream<int> stream =
130*6dbdd20aSAndroid Build Coastguard Worker base::RunOnThreadPool<int>(&pool, [counter = 0]() mutable {
131*6dbdd20aSAndroid Build Coastguard Worker return counter == 2 ? std::nullopt : std::make_optional(counter++);
132*6dbdd20aSAndroid Build Coastguard Worker });
133*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(WaitForStreamReady(stream, interested, ctx), 0);
134*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(WaitForStreamReady(stream, interested, ctx), 1);
135*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(WaitForStreamReady(stream, interested, ctx), std::nullopt);
136*6dbdd20aSAndroid Build Coastguard Worker }
137*6dbdd20aSAndroid Build Coastguard Worker
TEST(UtilUnittest,RunOnceOnThreadPool)138*6dbdd20aSAndroid Build Coastguard Worker TEST(UtilUnittest, RunOnceOnThreadPool) {
139*6dbdd20aSAndroid Build Coastguard Worker base::FlatSet<base::PlatformHandle> interested;
140*6dbdd20aSAndroid Build Coastguard Worker base::FlatSet<base::PlatformHandle> ready;
141*6dbdd20aSAndroid Build Coastguard Worker PollContext ctx(&interested, &ready);
142*6dbdd20aSAndroid Build Coastguard Worker
143*6dbdd20aSAndroid Build Coastguard Worker base::ThreadPool pool(1);
144*6dbdd20aSAndroid Build Coastguard Worker base::Future<int> fut =
145*6dbdd20aSAndroid Build Coastguard Worker base::RunOnceOnThreadPool<int>(&pool, []() mutable { return 1; });
146*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(WaitForFutureReady(fut, interested, ctx), 1);
147*6dbdd20aSAndroid Build Coastguard Worker }
148*6dbdd20aSAndroid Build Coastguard Worker
149*6dbdd20aSAndroid Build Coastguard Worker } // namespace
150*6dbdd20aSAndroid Build Coastguard Worker } // namespace base
151*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto
152