xref: /aosp_15_r20/external/cronet/base/task/current_thread.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_TASK_CURRENT_THREAD_H_
6 #define BASE_TASK_CURRENT_THREAD_H_
7 
8 #include <ostream>
9 #include <type_traits>
10 
11 #include "base/base_export.h"
12 #include "base/callback_list.h"
13 #include "base/check.h"
14 #include "base/functional/callback_forward.h"
15 #include "base/memory/raw_ptr.h"
16 #include "base/memory/scoped_refptr.h"
17 #include "base/message_loop/ios_cronet_buildflags.h"
18 #include "base/message_loop/message_pump_for_io.h"
19 #include "base/message_loop/message_pump_for_ui.h"
20 #include "base/pending_task.h"
21 #include "base/task/sequence_manager/task_time_observer.h"
22 #include "base/task/single_thread_task_runner.h"
23 #include "base/task/task_observer.h"
24 #include "build/build_config.h"
25 
26 namespace autofill {
27 class NextIdleTimeTicks;
28 }
29 
30 namespace content {
31 class BrowserMainLoop;
32 }
33 
34 namespace web {
35 class WebTaskEnvironment;
36 }
37 
38 namespace base {
39 
40 namespace test {
41 bool RunUntil(FunctionRef<bool(void)>);
42 void TestPredicateOrRegisterOnNextIdleCallback(base::FunctionRef<bool(void)>,
43                                                CallbackListSubscription*,
44                                                OnceClosure);
45 }  // namespace test
46 
47 namespace sequence_manager {
48 namespace internal {
49 class SequenceManagerImpl;
50 }
51 }  // namespace sequence_manager
52 
53 // CurrentThread is a proxy to a subset of Task related APIs bound to the
54 // current thread
55 //
56 // Current(UI|IO)Thread is available statically through
57 // Current(UI|IO)Thread::Get() on threads that have registered as CurrentThread
58 // on this physical thread (e.g. by using SingleThreadTaskExecutor). APIs
59 // intended for all consumers on the thread should be on Current(UI|IO)Thread,
60 // while internal APIs might be on multiple internal classes (e.g.
61 // SequenceManager).
62 //
63 // Why: Historically MessageLoop would take care of everything related to event
64 // processing on a given thread. Nowadays that functionality is split among
65 // different classes. At that time MessageLoop::current() gave access to the
66 // full MessageLoop API, preventing both addition of powerful owner-only APIs as
67 // well as making it harder to remove callers of deprecated APIs (that need to
68 // stick around for a few owner-only use cases and re-accrue callers after
69 // cleanup per remaining publicly available).
70 //
71 // As such, many methods below are flagged as deprecated and should be removed
72 // once all static callers have been migrated.
73 class BASE_EXPORT CurrentThread {
74  public:
75   // CurrentThread is effectively just a disguised pointer and is fine to
76   // copy/move around.
77   CurrentThread(const CurrentThread& other) = default;
78   CurrentThread(CurrentThread&& other) = default;
79   CurrentThread& operator=(const CurrentThread& other) = default;
80 
81   friend bool operator==(const CurrentThread&, const CurrentThread&) = default;
82 
83   // Returns a proxy object to interact with the Task related APIs for the
84   // current thread. It must only be used on the thread it was obtained.
85   static CurrentThread Get();
86 
87   // Return an empty CurrentThread. No methods should be called on this
88   // object.
89   static CurrentThread GetNull();
90 
91   // Returns true if the current thread is registered to expose CurrentThread
92   // API. Prefer this to verifying the boolean value of Get() (so that Get() can
93   // ultimately DCHECK it's only invoked when IsSet()).
94   static bool IsSet();
95 
96   // Allow CurrentThread to be used like a pointer to support the many
97   // callsites that used MessageLoop::current() that way when it was a
98   // MessageLoop*.
99   CurrentThread* operator->() { return this; }
100   explicit operator bool() const { return !!current_; }
101 
102   // A DestructionObserver is notified when the current task execution
103   // environment is being destroyed. These observers are notified prior to
104   // CurrentThread::IsSet() being changed to return false. This gives interested
105   // parties the chance to do final cleanup.
106   //
107   // NOTE: Any tasks posted to the current thread during this notification will
108   // not be run. Instead, they will be deleted.
109   //
110   // Deprecation note: Prefer SequenceLocalStorageSlot<std::unique_ptr<Foo>> to
111   // DestructionObserver to bind an object's lifetime to the current
112   // thread/sequence.
113   class BASE_EXPORT DestructionObserver {
114    public:
115     // TODO(https://crbug.com/891670): Rename to
116     // WillDestroyCurrentTaskExecutionEnvironment
117     virtual void WillDestroyCurrentMessageLoop() = 0;
118 
119    protected:
120     virtual ~DestructionObserver() = default;
121   };
122 
123   // Add a DestructionObserver, which will start receiving notifications
124   // immediately.
125   void AddDestructionObserver(DestructionObserver* destruction_observer);
126 
127   // Remove a DestructionObserver.  It is safe to call this method while a
128   // DestructionObserver is receiving a notification callback.
129   void RemoveDestructionObserver(DestructionObserver* destruction_observer);
130 
131   // Forwards to SequenceManager::SetTaskRunner().
132   // DEPRECATED(https://crbug.com/825327): only owners of the SequenceManager
133   // instance should replace its TaskRunner.
134   void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner);
135 
136   // Forwards to SequenceManager::(Add|Remove)TaskObserver.
137   // DEPRECATED(https://crbug.com/825327): only owners of the SequenceManager
138   // instance should add task observers on it.
139   void AddTaskObserver(TaskObserver* task_observer);
140   void RemoveTaskObserver(TaskObserver* task_observer);
141 
142   // When this functionality is enabled, the queue time will be recorded for
143   // posted tasks.
144   void SetAddQueueTimeToTasks(bool enable);
145 
146   // Registers a `OnceClosure` to be called on this thread the next time it goes
147   // idle. This is meant for internal usage; callers should use BEST_EFFORT
148   // tasks instead of this for generic work that needs to wait until quiescence
149   // to run.
150   class RegisterOnNextIdleCallbackPasskey {
151    private:
RegisterOnNextIdleCallbackPasskey()152     RegisterOnNextIdleCallbackPasskey() {}
153 
154     friend autofill::NextIdleTimeTicks;
155     friend content::BrowserMainLoop;
156     friend bool test::RunUntil(FunctionRef<bool(void)>);
157     friend void test::TestPredicateOrRegisterOnNextIdleCallback(
158         base::FunctionRef<bool(void)>,
159         CallbackListSubscription*,
160         OnceClosure);
161   };
162   [[nodiscard]] CallbackListSubscription RegisterOnNextIdleCallback(
163       RegisterOnNextIdleCallbackPasskey,
164       OnceClosure on_next_idle_callback);
165 
166   // Enables nested task processing in scope of an upcoming native message loop.
167   // Some unwanted message loops may occur when using common controls or printer
168   // functions. Hence, nested task processing is disabled by default to avoid
169   // unplanned reentrancy. This re-enables it in cases where the stack is
170   // reentrancy safe and processing nestable tasks is explicitly safe.
171   //
172   // For instance,
173   // - The current thread is running a message loop.
174   // - It receives a task #1 and executes it.
175   // - The task #1 implicitly starts a nested message loop, like a MessageBox in
176   //   the unit test. This can also be StartDoc or GetSaveFileName.
177   // - The thread receives a task #2 before or while in this second message
178   //   loop.
179   // - With NestableTasksAllowed set to true, the task #2 will run right away.
180   //   Otherwise, it will get executed right after task #1 completes at "thread
181   //   message loop level".
182   //
183   // Use RunLoop::Type::kNestableTasksAllowed when nesting is triggered by the
184   // application RunLoop rather than by native code.
185   class BASE_EXPORT ScopedAllowApplicationTasksInNativeNestedLoop {
186    public:
187     ScopedAllowApplicationTasksInNativeNestedLoop();
188     ~ScopedAllowApplicationTasksInNativeNestedLoop();
189 
190    private:
191     const raw_ptr<sequence_manager::internal::SequenceManagerImpl>
192         sequence_manager_;
193     const bool previous_state_;
194   };
195 
196   // Returns true if nestable tasks are allowed on the current thread at this
197   // time (i.e. if a native nested loop would start from the callee's point in
198   // the stack, would it be allowed to run application tasks).
199   bool ApplicationTasksAllowedInNativeNestedLoop() const;
200 
201   // Returns true if this instance is bound to the current thread.
202   bool IsBoundToCurrentThread() const;
203 
204   // Returns true if the current thread is idle (ignoring delayed tasks). This
205   // is the same condition which triggers DoWork() to return false: i.e. out of
206   // tasks which can be processed at the current run-level -- there might be
207   // deferred non-nestable tasks remaining if currently in a nested run level.
208   bool IsIdleForTesting();
209 
210   // Enables ThreadControllerWithMessagePumpImpl's TimeKeeper metrics.
211   // `thread_name` will be used as a suffix.
212   void EnableMessagePumpTimeKeeperMetrics(const char* thread_name);
213 
214  protected:
CurrentThread(sequence_manager::internal::SequenceManagerImpl * sequence_manager)215   explicit CurrentThread(
216       sequence_manager::internal::SequenceManagerImpl* sequence_manager)
217       : current_(sequence_manager) {}
218 
219   static sequence_manager::internal::SequenceManagerImpl*
220   GetCurrentSequenceManagerImpl();
221 
222   friend class MessagePumpLibeventTest;
223   friend class ScheduleWorkTest;
224   friend class Thread;
225   friend class sequence_manager::internal::SequenceManagerImpl;
226   friend class MessageLoopTaskRunnerTest;
227   friend class web::WebTaskEnvironment;
228 
229   raw_ptr<sequence_manager::internal::SequenceManagerImpl> current_;
230 };
231 
232 #if !BUILDFLAG(IS_NACL)
233 
234 // UI extension of CurrentThread.
235 class BASE_EXPORT CurrentUIThread : public CurrentThread {
236  public:
237   // Returns an interface for the CurrentUIThread of the current thread.
238   // Asserts that IsSet().
239   static CurrentUIThread Get();
240 
241   // Returns true if the current thread is running a CurrentUIThread.
242   static bool IsSet();
243 
244   CurrentUIThread* operator->() { return this; }
245 
246 #if BUILDFLAG(IS_OZONE) && !BUILDFLAG(IS_FUCHSIA) && !BUILDFLAG(IS_WIN)
247   static_assert(
248       std::is_base_of_v<WatchableIOMessagePumpPosix, MessagePumpForUI>,
249       "CurrentThreadForUI::WatchFileDescriptor is supported only"
250       "by MessagePumpLibevent and MessagePumpGlib implementations.");
251   bool WatchFileDescriptor(int fd,
252                            bool persistent,
253                            MessagePumpForUI::Mode mode,
254                            MessagePumpForUI::FdWatchController* controller,
255                            MessagePumpForUI::FdWatcher* delegate);
256 #endif
257 
258 #if BUILDFLAG(IS_IOS)
259   // Forwards to SequenceManager::Attach().
260   // TODO(https://crbug.com/825327): Plumb the actual SequenceManager* to
261   // callers and remove ability to access this method from
262   // CurrentUIThread.
263   void Attach();
264 #endif
265 
266 #if BUILDFLAG(IS_ANDROID)
267   // Forwards to MessagePumpAndroid::Abort().
268   // TODO(https://crbug.com/825327): Plumb the actual MessagePumpForUI* to
269   // callers and remove ability to access this method from
270   // CurrentUIThread.
271   void Abort();
272 #endif
273 
274 #if BUILDFLAG(IS_WIN)
275   void AddMessagePumpObserver(MessagePumpForUI::Observer* observer);
276   void RemoveMessagePumpObserver(MessagePumpForUI::Observer* observer);
277 #endif
278 
279  private:
CurrentUIThread(sequence_manager::internal::SequenceManagerImpl * current)280   explicit CurrentUIThread(
281       sequence_manager::internal::SequenceManagerImpl* current)
282       : CurrentThread(current) {}
283 
284   MessagePumpForUI* GetMessagePumpForUI() const;
285 };
286 
287 #endif  // !BUILDFLAG(IS_NACL)
288 
289 // ForIO extension of CurrentThread.
290 class BASE_EXPORT CurrentIOThread : public CurrentThread {
291  public:
292   // Returns an interface for the CurrentIOThread of the current thread.
293   // Asserts that IsSet().
294   static CurrentIOThread Get();
295 
296   // Returns true if the current thread is running a CurrentIOThread.
297   static bool IsSet();
298 
299   CurrentIOThread* operator->() { return this; }
300 
301 #if !BUILDFLAG(IS_NACL)
302 
303 #if BUILDFLAG(IS_WIN)
304   // Please see MessagePumpWin for definitions of these methods.
305   HRESULT RegisterIOHandler(HANDLE file, MessagePumpForIO::IOHandler* handler);
306   bool RegisterJobObject(HANDLE job, MessagePumpForIO::IOHandler* handler);
307 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
308   // Please see WatchableIOMessagePumpPosix for definition.
309   // Prefer base::FileDescriptorWatcher for non-critical IO.
310   bool WatchFileDescriptor(int fd,
311                            bool persistent,
312                            MessagePumpForIO::Mode mode,
313                            MessagePumpForIO::FdWatchController* controller,
314                            MessagePumpForIO::FdWatcher* delegate);
315 #endif  // BUILDFLAG(IS_WIN)
316 
317 #if BUILDFLAG(IS_MAC) || (BUILDFLAG(IS_IOS) && !BUILDFLAG(CRONET_BUILD))
318   bool WatchMachReceivePort(
319       mach_port_t port,
320       MessagePumpForIO::MachPortWatchController* controller,
321       MessagePumpForIO::MachPortWatcher* delegate);
322 #endif
323 
324 #if BUILDFLAG(IS_FUCHSIA)
325   // Additional watch API for native platform resources.
326   bool WatchZxHandle(zx_handle_t handle,
327                      bool persistent,
328                      zx_signals_t signals,
329                      MessagePumpForIO::ZxHandleWatchController* controller,
330                      MessagePumpForIO::ZxHandleWatcher* delegate);
331 #endif  // BUILDFLAG(IS_FUCHSIA)
332 
333 #endif  // !BUILDFLAG(IS_NACL)
334 
335  private:
CurrentIOThread(sequence_manager::internal::SequenceManagerImpl * current)336   explicit CurrentIOThread(
337       sequence_manager::internal::SequenceManagerImpl* current)
338       : CurrentThread(current) {}
339 
340   MessagePumpForIO* GetMessagePumpForIO() const;
341 };
342 
343 }  // namespace base
344 
345 #endif  // BASE_TASK_CURRENT_THREAD_H_
346