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/spawn.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/task_runner.h"
22*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/thread_checker.h"
23*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/threading/future.h"
24*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/threading/poll.h"
25*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/threading/stream.h"
26*6dbdd20aSAndroid Build Coastguard Worker
27*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
28*6dbdd20aSAndroid Build Coastguard Worker namespace base {
29*6dbdd20aSAndroid Build Coastguard Worker
30*6dbdd20aSAndroid Build Coastguard Worker // Represents a future which is being polled to completion. Owned by
31*6dbdd20aSAndroid Build Coastguard Worker // SpawnHandle.
32*6dbdd20aSAndroid Build Coastguard Worker class PolledFuture {
33*6dbdd20aSAndroid Build Coastguard Worker public:
PolledFuture(TaskRunner * task_runner,Future<FVoid> future)34*6dbdd20aSAndroid Build Coastguard Worker explicit PolledFuture(TaskRunner* task_runner, Future<FVoid> future)
35*6dbdd20aSAndroid Build Coastguard Worker : task_runner_(task_runner), future_(std::move(future)) {
36*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(task_runner_->RunsTasksOnCurrentThread());
37*6dbdd20aSAndroid Build Coastguard Worker PollUntilFinish();
38*6dbdd20aSAndroid Build Coastguard Worker }
39*6dbdd20aSAndroid Build Coastguard Worker
~PolledFuture()40*6dbdd20aSAndroid Build Coastguard Worker ~PolledFuture() {
41*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK_THREAD(thread_checker);
42*6dbdd20aSAndroid Build Coastguard Worker ClearFutureAndWatches(interested_);
43*6dbdd20aSAndroid Build Coastguard Worker }
44*6dbdd20aSAndroid Build Coastguard Worker
45*6dbdd20aSAndroid Build Coastguard Worker private:
46*6dbdd20aSAndroid Build Coastguard Worker PolledFuture(PolledFuture&&) = delete;
47*6dbdd20aSAndroid Build Coastguard Worker PolledFuture& operator=(PolledFuture&&) = delete;
48*6dbdd20aSAndroid Build Coastguard Worker
PollUntilFinish()49*6dbdd20aSAndroid Build Coastguard Worker void PollUntilFinish() {
50*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(task_runner_->RunsTasksOnCurrentThread());
51*6dbdd20aSAndroid Build Coastguard Worker
52*6dbdd20aSAndroid Build Coastguard Worker auto pre_poll_interested = std::move(interested_);
53*6dbdd20aSAndroid Build Coastguard Worker interested_.clear();
54*6dbdd20aSAndroid Build Coastguard Worker
55*6dbdd20aSAndroid Build Coastguard Worker FuturePollResult<FVoid> res = future_->Poll(&context_);
56*6dbdd20aSAndroid Build Coastguard Worker if (!res.IsPending()) {
57*6dbdd20aSAndroid Build Coastguard Worker ClearFutureAndWatches(pre_poll_interested);
58*6dbdd20aSAndroid Build Coastguard Worker return;
59*6dbdd20aSAndroid Build Coastguard Worker }
60*6dbdd20aSAndroid Build Coastguard Worker
61*6dbdd20aSAndroid Build Coastguard Worker for (PlatformHandle fd : SetDifference(pre_poll_interested, interested_)) {
62*6dbdd20aSAndroid Build Coastguard Worker task_runner_->RemoveFileDescriptorWatch(fd);
63*6dbdd20aSAndroid Build Coastguard Worker }
64*6dbdd20aSAndroid Build Coastguard Worker
65*6dbdd20aSAndroid Build Coastguard Worker auto weak_this = weak_ptr_factory_.GetWeakPtr();
66*6dbdd20aSAndroid Build Coastguard Worker for (PlatformHandle fd : SetDifference(interested_, pre_poll_interested)) {
67*6dbdd20aSAndroid Build Coastguard Worker task_runner_->AddFileDescriptorWatch(fd, [weak_this, fd]() {
68*6dbdd20aSAndroid Build Coastguard Worker if (!weak_this) {
69*6dbdd20aSAndroid Build Coastguard Worker return;
70*6dbdd20aSAndroid Build Coastguard Worker }
71*6dbdd20aSAndroid Build Coastguard Worker weak_this->ready_ = {fd};
72*6dbdd20aSAndroid Build Coastguard Worker weak_this->PollUntilFinish();
73*6dbdd20aSAndroid Build Coastguard Worker });
74*6dbdd20aSAndroid Build Coastguard Worker }
75*6dbdd20aSAndroid Build Coastguard Worker }
76*6dbdd20aSAndroid Build Coastguard Worker
ClearFutureAndWatches(const FlatSet<PlatformHandle> & interested)77*6dbdd20aSAndroid Build Coastguard Worker void ClearFutureAndWatches(const FlatSet<PlatformHandle>& interested) {
78*6dbdd20aSAndroid Build Coastguard Worker future_ = std::nullopt;
79*6dbdd20aSAndroid Build Coastguard Worker for (PlatformHandle fd : interested) {
80*6dbdd20aSAndroid Build Coastguard Worker task_runner_->RemoveFileDescriptorWatch(fd);
81*6dbdd20aSAndroid Build Coastguard Worker }
82*6dbdd20aSAndroid Build Coastguard Worker interested_.clear();
83*6dbdd20aSAndroid Build Coastguard Worker ready_.clear();
84*6dbdd20aSAndroid Build Coastguard Worker }
85*6dbdd20aSAndroid Build Coastguard Worker
SetDifference(const FlatSet<PlatformHandle> & f,const FlatSet<PlatformHandle> & s)86*6dbdd20aSAndroid Build Coastguard Worker static std::vector<PlatformHandle> SetDifference(
87*6dbdd20aSAndroid Build Coastguard Worker const FlatSet<PlatformHandle>& f,
88*6dbdd20aSAndroid Build Coastguard Worker const FlatSet<PlatformHandle>& s) {
89*6dbdd20aSAndroid Build Coastguard Worker std::vector<PlatformHandle> out(f.size());
90*6dbdd20aSAndroid Build Coastguard Worker auto it = std::set_difference(f.begin(), f.end(), s.begin(), s.end(),
91*6dbdd20aSAndroid Build Coastguard Worker out.begin());
92*6dbdd20aSAndroid Build Coastguard Worker out.resize(static_cast<size_t>(std::distance(out.begin(), it)));
93*6dbdd20aSAndroid Build Coastguard Worker return out;
94*6dbdd20aSAndroid Build Coastguard Worker }
95*6dbdd20aSAndroid Build Coastguard Worker
96*6dbdd20aSAndroid Build Coastguard Worker TaskRunner* const task_runner_ = nullptr;
97*6dbdd20aSAndroid Build Coastguard Worker
98*6dbdd20aSAndroid Build Coastguard Worker std::optional<Future<FVoid>> future_;
99*6dbdd20aSAndroid Build Coastguard Worker FlatSet<PlatformHandle> interested_;
100*6dbdd20aSAndroid Build Coastguard Worker FlatSet<PlatformHandle> ready_;
101*6dbdd20aSAndroid Build Coastguard Worker PollContext context_{&interested_, &ready_};
102*6dbdd20aSAndroid Build Coastguard Worker
PERFETTO_THREAD_CHECKER(thread_checker)103*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_THREAD_CHECKER(thread_checker)
104*6dbdd20aSAndroid Build Coastguard Worker
105*6dbdd20aSAndroid Build Coastguard Worker // Keep this last.
106*6dbdd20aSAndroid Build Coastguard Worker WeakPtrFactory<PolledFuture> weak_ptr_factory_{this};
107*6dbdd20aSAndroid Build Coastguard Worker };
108*6dbdd20aSAndroid Build Coastguard Worker
SpawnHandle(TaskRunner * task_runner,std::function<Future<FVoid> ()> fn)109*6dbdd20aSAndroid Build Coastguard Worker SpawnHandle::SpawnHandle(TaskRunner* task_runner,
110*6dbdd20aSAndroid Build Coastguard Worker std::function<Future<FVoid>()> fn)
111*6dbdd20aSAndroid Build Coastguard Worker : task_runner_(task_runner),
112*6dbdd20aSAndroid Build Coastguard Worker polled_future_(std::make_shared<std::unique_ptr<PolledFuture>>()) {
113*6dbdd20aSAndroid Build Coastguard Worker task_runner->PostTask(
114*6dbdd20aSAndroid Build Coastguard Worker [t = task_runner, fn = std::move(fn), p = polled_future_]() mutable {
115*6dbdd20aSAndroid Build Coastguard Worker p->reset(new PolledFuture(t, fn()));
116*6dbdd20aSAndroid Build Coastguard Worker });
117*6dbdd20aSAndroid Build Coastguard Worker }
118*6dbdd20aSAndroid Build Coastguard Worker
~SpawnHandle()119*6dbdd20aSAndroid Build Coastguard Worker SpawnHandle::~SpawnHandle() {
120*6dbdd20aSAndroid Build Coastguard Worker task_runner_->PostTask(
121*6dbdd20aSAndroid Build Coastguard Worker [f = std::move(polled_future_)]() mutable { f.reset(); });
122*6dbdd20aSAndroid Build Coastguard Worker }
123*6dbdd20aSAndroid Build Coastguard Worker
124*6dbdd20aSAndroid Build Coastguard Worker } // namespace base
125*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto
126