xref: /aosp_15_r20/system/update_engine/common/scoped_task_id.h (revision 5a9231315b4521097b8dc3750bc806fcafe0c72f)
1*5a923131SAndroid Build Coastguard Worker //
2*5a923131SAndroid Build Coastguard Worker // Copyright (C) 2021 The Android Open Source Project
3*5a923131SAndroid Build Coastguard Worker //
4*5a923131SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
5*5a923131SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
6*5a923131SAndroid Build Coastguard Worker // You may obtain a copy of the License at
7*5a923131SAndroid Build Coastguard Worker //
8*5a923131SAndroid Build Coastguard Worker //      http://www.apache.org/licenses/LICENSE-2.0
9*5a923131SAndroid Build Coastguard Worker //
10*5a923131SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
11*5a923131SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
12*5a923131SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*5a923131SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
14*5a923131SAndroid Build Coastguard Worker // limitations under the License.
15*5a923131SAndroid Build Coastguard Worker //
16*5a923131SAndroid Build Coastguard Worker 
17*5a923131SAndroid Build Coastguard Worker #ifndef UPDATE_ENGINE_SCOPED_TASK_ID_H_
18*5a923131SAndroid Build Coastguard Worker #define UPDATE_ENGINE_SCOPED_TASK_ID_H_
19*5a923131SAndroid Build Coastguard Worker 
20*5a923131SAndroid Build Coastguard Worker #include <ostream>
21*5a923131SAndroid Build Coastguard Worker #include <type_traits>
22*5a923131SAndroid Build Coastguard Worker #include <utility>
23*5a923131SAndroid Build Coastguard Worker 
24*5a923131SAndroid Build Coastguard Worker #include <base/bind.h>
25*5a923131SAndroid Build Coastguard Worker #include <brillo/message_loops/message_loop.h>
26*5a923131SAndroid Build Coastguard Worker 
27*5a923131SAndroid Build Coastguard Worker namespace chromeos_update_engine {
28*5a923131SAndroid Build Coastguard Worker 
29*5a923131SAndroid Build Coastguard Worker // This class provides unique_ptr like semantic for |MessageLoop::TaskId|, when
30*5a923131SAndroid Build Coastguard Worker // instance of this class goes out of scope, underlying task will be cancelled.
31*5a923131SAndroid Build Coastguard Worker class ScopedTaskId {
32*5a923131SAndroid Build Coastguard Worker   using MessageLoop = brillo::MessageLoop;
33*5a923131SAndroid Build Coastguard Worker 
34*5a923131SAndroid Build Coastguard Worker  public:
35*5a923131SAndroid Build Coastguard Worker   // Move only type similar to unique_ptr.
36*5a923131SAndroid Build Coastguard Worker   ScopedTaskId(const ScopedTaskId&) = delete;
37*5a923131SAndroid Build Coastguard Worker   ScopedTaskId& operator=(const ScopedTaskId&) = delete;
38*5a923131SAndroid Build Coastguard Worker 
39*5a923131SAndroid Build Coastguard Worker   friend std::ostream& operator<<(std::ostream& out, const ScopedTaskId& task) {
40*5a923131SAndroid Build Coastguard Worker     out << task.task_id_;
41*5a923131SAndroid Build Coastguard Worker     return out;
42*5a923131SAndroid Build Coastguard Worker   }
43*5a923131SAndroid Build Coastguard Worker 
44*5a923131SAndroid Build Coastguard Worker   constexpr ScopedTaskId() = default;
45*5a923131SAndroid Build Coastguard Worker 
ScopedTaskId(ScopedTaskId && other)46*5a923131SAndroid Build Coastguard Worker   constexpr ScopedTaskId(ScopedTaskId&& other) noexcept {
47*5a923131SAndroid Build Coastguard Worker     *this = std::move(other);
48*5a923131SAndroid Build Coastguard Worker   }
49*5a923131SAndroid Build Coastguard Worker 
50*5a923131SAndroid Build Coastguard Worker   constexpr ScopedTaskId& operator=(ScopedTaskId&& other) noexcept {
51*5a923131SAndroid Build Coastguard Worker     std::swap(task_id_, other.task_id_);
52*5a923131SAndroid Build Coastguard Worker     return *this;
53*5a923131SAndroid Build Coastguard Worker   }
54*5a923131SAndroid Build Coastguard Worker 
55*5a923131SAndroid Build Coastguard Worker   // Post a callback on current message loop, return true if succeeded, false if
56*5a923131SAndroid Build Coastguard Worker   // the previous callback hasn't run yet, or scheduling failed at MessageLoop
57*5a923131SAndroid Build Coastguard Worker   // side.
58*5a923131SAndroid Build Coastguard Worker   [[nodiscard]] bool PostTask(const base::Location& from_here,
59*5a923131SAndroid Build Coastguard Worker                               base::OnceClosure&& callback,
60*5a923131SAndroid Build Coastguard Worker                               base::TimeDelta delay = {}) noexcept {
61*5a923131SAndroid Build Coastguard Worker     return PostTask<decltype(callback)>(from_here, std::move(callback), delay);
62*5a923131SAndroid Build Coastguard Worker   }
63*5a923131SAndroid Build Coastguard Worker   [[nodiscard]] bool PostTask(const base::Location& from_here,
64*5a923131SAndroid Build Coastguard Worker                               std::function<void()>&& callback,
65*5a923131SAndroid Build Coastguard Worker                               base::TimeDelta delay = {}) noexcept {
66*5a923131SAndroid Build Coastguard Worker     return PostTask<decltype(callback)>(from_here, std::move(callback), delay);
67*5a923131SAndroid Build Coastguard Worker   }
68*5a923131SAndroid Build Coastguard Worker 
~ScopedTaskId()69*5a923131SAndroid Build Coastguard Worker   ~ScopedTaskId() noexcept { Cancel(); }
70*5a923131SAndroid Build Coastguard Worker 
71*5a923131SAndroid Build Coastguard Worker   // Cancel the underlying managed task, true if cancel successful. False if no
72*5a923131SAndroid Build Coastguard Worker   // task scheduled or task cancellation failed
Cancel()73*5a923131SAndroid Build Coastguard Worker   bool Cancel() noexcept {
74*5a923131SAndroid Build Coastguard Worker     if (task_id_ != MessageLoop::kTaskIdNull) {
75*5a923131SAndroid Build Coastguard Worker       if (MessageLoop::current()->CancelTask(task_id_)) {
76*5a923131SAndroid Build Coastguard Worker         LOG(INFO) << "Cancelled task id " << task_id_;
77*5a923131SAndroid Build Coastguard Worker         task_id_ = MessageLoop::kTaskIdNull;
78*5a923131SAndroid Build Coastguard Worker         return true;
79*5a923131SAndroid Build Coastguard Worker       }
80*5a923131SAndroid Build Coastguard Worker     }
81*5a923131SAndroid Build Coastguard Worker     return false;
82*5a923131SAndroid Build Coastguard Worker   }
83*5a923131SAndroid Build Coastguard Worker 
IsScheduled()84*5a923131SAndroid Build Coastguard Worker   [[nodiscard]] constexpr bool IsScheduled() const noexcept {
85*5a923131SAndroid Build Coastguard Worker     return task_id_ != MessageLoop::kTaskIdNull;
86*5a923131SAndroid Build Coastguard Worker   }
87*5a923131SAndroid Build Coastguard Worker 
88*5a923131SAndroid Build Coastguard Worker   [[nodiscard]] constexpr bool operator==(const ScopedTaskId& other) const
89*5a923131SAndroid Build Coastguard Worker       noexcept {
90*5a923131SAndroid Build Coastguard Worker     return other.task_id_ == task_id_;
91*5a923131SAndroid Build Coastguard Worker   }
92*5a923131SAndroid Build Coastguard Worker 
93*5a923131SAndroid Build Coastguard Worker   [[nodiscard]] constexpr bool operator<(const ScopedTaskId& other) const
94*5a923131SAndroid Build Coastguard Worker       noexcept {
95*5a923131SAndroid Build Coastguard Worker     return task_id_ < other.task_id_;
96*5a923131SAndroid Build Coastguard Worker   }
97*5a923131SAndroid Build Coastguard Worker 
98*5a923131SAndroid Build Coastguard Worker   template <typename Callable>
PostTask(const base::Location & from_here,Callable && callback,base::TimeDelta delay)99*5a923131SAndroid Build Coastguard Worker   [[nodiscard]] bool PostTask(const base::Location& from_here,
100*5a923131SAndroid Build Coastguard Worker                               Callable&& callback,
101*5a923131SAndroid Build Coastguard Worker                               base::TimeDelta delay) noexcept {
102*5a923131SAndroid Build Coastguard Worker     if (task_id_ != MessageLoop::kTaskIdNull) {
103*5a923131SAndroid Build Coastguard Worker       LOG(ERROR) << "Scheduling another task but task id " << task_id_
104*5a923131SAndroid Build Coastguard Worker                  << " isn't executed yet! This can cause the old task to leak.";
105*5a923131SAndroid Build Coastguard Worker       return false;
106*5a923131SAndroid Build Coastguard Worker     }
107*5a923131SAndroid Build Coastguard Worker     task_id_ = MessageLoop::current()->PostDelayedTask(
108*5a923131SAndroid Build Coastguard Worker         from_here,
109*5a923131SAndroid Build Coastguard Worker         base::BindOnce(&ScopedTaskId::ExecuteTask<decltype(callback)>,
110*5a923131SAndroid Build Coastguard Worker                        base::Unretained(this),
111*5a923131SAndroid Build Coastguard Worker                        std::move(callback)),
112*5a923131SAndroid Build Coastguard Worker         delay);
113*5a923131SAndroid Build Coastguard Worker     return task_id_ != MessageLoop::kTaskIdNull;
114*5a923131SAndroid Build Coastguard Worker   }
115*5a923131SAndroid Build Coastguard Worker 
116*5a923131SAndroid Build Coastguard Worker  private:
117*5a923131SAndroid Build Coastguard Worker   template <typename Callable>
ExecuteTask(Callable && callback)118*5a923131SAndroid Build Coastguard Worker   void ExecuteTask(Callable&& callback) {
119*5a923131SAndroid Build Coastguard Worker     task_id_ = MessageLoop::kTaskIdNull;
120*5a923131SAndroid Build Coastguard Worker     if constexpr (std::is_same_v<Callable&&, base::OnceClosure&&>) {
121*5a923131SAndroid Build Coastguard Worker       std::move(callback).Run();
122*5a923131SAndroid Build Coastguard Worker     } else if constexpr (std::is_same_v<Callable&&,
123*5a923131SAndroid Build Coastguard Worker                                         base::RepeatingCallback<void()>&&>) {
124*5a923131SAndroid Build Coastguard Worker       std::move(callback).Run();
125*5a923131SAndroid Build Coastguard Worker     } else {
126*5a923131SAndroid Build Coastguard Worker       std::move(callback)();
127*5a923131SAndroid Build Coastguard Worker     }
128*5a923131SAndroid Build Coastguard Worker   }
129*5a923131SAndroid Build Coastguard Worker   MessageLoop::TaskId task_id_{MessageLoop::kTaskIdNull};
130*5a923131SAndroid Build Coastguard Worker };
131*5a923131SAndroid Build Coastguard Worker }  // namespace chromeos_update_engine
132*5a923131SAndroid Build Coastguard Worker 
133*5a923131SAndroid Build Coastguard Worker #endif
134