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