xref: /aosp_15_r20/external/perfetto/src/base/threading/spawn.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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