• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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_THREAD_POOL_TASK_TRACKER_H_
6 #define BASE_TASK_THREAD_POOL_TASK_TRACKER_H_
7 
8 #include <atomic>
9 #include <functional>
10 #include <limits>
11 #include <memory>
12 #include <queue>
13 #include <string>
14 
15 #include "base/atomicops.h"
16 #include "base/base_export.h"
17 #include "base/containers/circular_deque.h"
18 #include "base/functional/callback_forward.h"
19 #include "base/sequence_checker.h"
20 #include "base/strings/string_piece.h"
21 #include "base/synchronization/waitable_event.h"
22 #include "base/task/common/checked_lock.h"
23 #include "base/task/common/task_annotator.h"
24 #include "base/task/task_traits.h"
25 #include "base/task/thread_pool/task.h"
26 #include "base/task/thread_pool/task_source.h"
27 #include "base/task/thread_pool/tracked_ref.h"
28 #include "base/thread_annotations.h"
29 #include "base/threading/thread_local.h"
30 
31 namespace base {
32 
33 class ConditionVariable;
34 
35 namespace internal {
36 
37 // Determines which tasks are allowed to run.
38 enum class CanRunPolicy {
39   // All tasks are allowed to run.
40   kAll,
41   // Only USER_VISIBLE and USER_BLOCKING tasks are allowed to run.
42   kForegroundOnly,
43   // No tasks can run.
44   kNone,
45 };
46 
47 // TaskTracker enforces policies that determines whether:
48 // - A task can be pushed to a task source (WillPostTask).
49 // - A task source can be queued (WillQueueTaskSource).
50 // - Tasks for a given priority can run (CanRunPriority).
51 // - The next task in a queued task source can run (RunAndPopNextTask).
52 // TaskTracker also sets up the environment to run a task (RunAndPopNextTask)
53 // and records metrics and trace events. This class is thread-safe.
54 class BASE_EXPORT TaskTracker {
55  public:
56   TaskTracker();
57   TaskTracker(const TaskTracker&) = delete;
58   TaskTracker& operator=(const TaskTracker&) = delete;
59   virtual ~TaskTracker();
60 
61   // Initiates shutdown. Once this is called, only BLOCK_SHUTDOWN tasks will
62   // start running (doesn't affect tasks that are already running). This can
63   // only be called once.
64   void StartShutdown();
65 
66   // Synchronously completes shutdown. StartShutdown() must be called first.
67   // Returns when:
68   // - All SKIP_ON_SHUTDOWN tasks that were already running have completed their
69   //   execution.
70   // - All posted BLOCK_SHUTDOWN tasks have completed their execution.
71   // CONTINUE_ON_SHUTDOWN tasks still may be running after Shutdown returns.
72   // This can only be called once.
73   void CompleteShutdown();
74 
75   // Waits until there are no incomplete task sources. May be called in tests
76   // to validate that a condition is met after all task sources have run.
77   //
78   // Does not wait for delayed tasks. Waits for task sources posted from
79   // other threads during the call. Returns immediately when shutdown completes.
80   void FlushForTesting();
81 
82   // Returns and calls |flush_callback| when there are no incomplete undelayed
83   // tasks. |flush_callback| may be called back on any thread and should not
84   // perform a lot of work. May be used when additional work on the current
85   // thread needs to be performed during a flush. Only one
86   // FlushAsyncForTesting() may be pending at any given time.
87   void FlushAsyncForTesting(OnceClosure flush_callback);
88 
89   // Sets the new CanRunPolicy policy, possibly affecting result of
90   // CanRunPriority(). The caller must wake up worker as appropriate so that
91   // tasks that are allowed to run by the new policy can be scheduled.
92   void SetCanRunPolicy(CanRunPolicy can_run_policy);
93 
94   // Informs this TaskTracker that |task| with |shutdown_behavior| is about to
95   // be pushed to a task source (if non-delayed) or be added to the
96   // DelayedTaskManager (if delayed). Returns true if this operation is allowed
97   // (the operation should be performed if-and-only-if it is). This method may
98   // also modify metadata on |task| if desired.
99   // If this returns false, `task` must be leaked by the caller if deleting it
100   // on the current sequence may invoke sequence-affine code that belongs to
101   // another sequence.
102   bool WillPostTask(Task* task, TaskShutdownBehavior shutdown_behavior);
103 
104   // Informs this TaskTracker that |task| that is about to be pushed to a task
105   // source with |priority|. Returns true if this operation is allowed (the
106   // operation should be performed if-and-only-if it is).
107   [[nodiscard]] bool WillPostTaskNow(const Task& task,
108                                      TaskPriority priority) const;
109 
110   // Informs this TaskTracker that |task_source| is about to be queued. Returns
111   // a RegisteredTaskSource that should be queued if-and-only-if it evaluates to
112   // true.
113   RegisteredTaskSource RegisterTaskSource(
114       scoped_refptr<TaskSource> task_source);
115 
116   // Returns true if a task with |priority| can run under to the current policy.
117   bool CanRunPriority(TaskPriority priority) const;
118 
119   // Runs the next task in |task_source| unless the current shutdown state
120   // prevents that. Then, pops the task from |task_source| (even if it didn't
121   // run). Returns |task_source| if non-empty after popping a task from it
122   // (which indicates that it should be reenqueued). WillPostTask() must have
123   // allowed the task in front of |task_source| to be posted before this is
124   // called.
125   RegisteredTaskSource RunAndPopNextTask(RegisteredTaskSource task_source);
126 
127   // Returns true once shutdown has started (StartShutdown() was called).
128   // Note: sequential consistency with the thread calling StartShutdown() isn't
129   // guaranteed by this call.
130   bool HasShutdownStarted() const;
131 
132   // Returns true if shutdown has completed (StartShutdown() was called and
133   // no tasks are blocking shutdown).
134   bool IsShutdownComplete() const;
135 
GetTrackedRef()136   TrackedRef<TaskTracker> GetTrackedRef() {
137     return tracked_ref_factory_.GetTrackedRef();
138   }
139 
140   void BeginFizzlingBlockShutdownTasks();
141   void EndFizzlingBlockShutdownTasks();
142 
143   // Returns true if there are task sources that haven't completed their
144   // execution (still queued or in progress). If it returns false: the side-
145   // effects of all completed tasks are guaranteed to be visible to the caller.
146   bool HasIncompleteTaskSourcesForTesting() const;
147 
148  protected:
149   // Runs and deletes |task|. |task| is deleted in the environment where it
150   // runs. |task_source| is the task source from which |task| was extracted.
151   // |traits| are the traits of |task_source|. An override is expected to call
152   // its parent's implementation but is free to perform extra work before and
153   // after doing so.
154   virtual void RunTask(Task task,
155                        TaskSource* task_source,
156                        const TaskTraits& traits);
157 
158   // Allow a subclass to wait more interactively for any running shutdown tasks
159   // before blocking the thread.
160   virtual void BeginCompleteShutdown(base::WaitableEvent& shutdown_event);
161 
162   // Asserts that FlushForTesting() is allowed to be called. Overridden in tests
163   // in situations where it is not.
AssertFlushForTestingAllowed()164   virtual void AssertFlushForTestingAllowed() {}
165 
166  private:
167   friend class RegisteredTaskSource;
168   class State;
169 
170   void PerformShutdown();
171 
172   // Called before WillPostTask() informs the tracing system that a task has
173   // been posted. Updates |num_items_blocking_shutdown_| if necessary and
174   // returns true if the current shutdown state allows the task to be posted.
175   bool BeforeQueueTaskSource(TaskShutdownBehavior shutdown_behavior);
176 
177   // Called before a task with |effective_shutdown_behavior| is run by
178   // RunTask(). Updates |num_items_blocking_shutdown_| if necessary and returns
179   // true if the current shutdown state allows the task to be run.
180   bool BeforeRunTask(TaskShutdownBehavior shutdown_behavior);
181 
182   // Called after a task with |effective_shutdown_behavior| has been run by
183   // RunTask(). Updates |num_items_blocking_shutdown_| if necessary.
184   void AfterRunTask(TaskShutdownBehavior shutdown_behavior);
185 
186   // Informs this TaskTracker that |task_source| won't be reenqueued and returns
187   // the underlying TaskSource. This is called before destroying a valid
188   // RegisteredTaskSource. Updates |num_items_blocking_shutdown_| if necessary.
189   scoped_refptr<TaskSource> UnregisterTaskSource(
190       scoped_refptr<TaskSource> task_source);
191 
192   // Called when an item blocking shutdown finishes after shutdown has started.
193   void DecrementNumItemsBlockingShutdown();
194 
195   // Decrements the number of incomplete task sources and signals |flush_cv_|
196   // if it reaches zero.
197   void DecrementNumIncompleteTaskSources();
198 
199   // Invokes all |flush_callbacks_for_testing_| if any in a lock-safe manner.
200   void InvokeFlushCallbacksForTesting();
201 
202   // Dummy frames to allow identification of shutdown behavior in a stack trace.
203   void RunContinueOnShutdown(Task& task,
204                              const TaskTraits& traits,
205                              TaskSource* task_source,
206                              const SequenceToken& token);
207   void RunSkipOnShutdown(Task& task,
208                          const TaskTraits& traits,
209                          TaskSource* task_source,
210                          const SequenceToken& token);
211   void RunBlockShutdown(Task& task,
212                         const TaskTraits& traits,
213                         TaskSource* task_source,
214                         const SequenceToken& token);
215   void RunTaskWithShutdownBehavior(Task& task,
216                                    const TaskTraits& traits,
217                                    TaskSource* task_source,
218                                    const SequenceToken& token);
219 
220   NOT_TAIL_CALLED void RunTaskImpl(Task& task,
221                                    const TaskTraits& traits,
222                                    TaskSource* task_source,
223                                    const SequenceToken& token);
224 
225   TaskAnnotator task_annotator_;
226 
227   // Indicates whether logging information about TaskPriority::BEST_EFFORT tasks
228   // was enabled with a command line switch.
229   const bool has_log_best_effort_tasks_switch_;
230 
231   // Number of tasks blocking shutdown and boolean indicating whether shutdown
232   // has started. |shutdown_lock_| should be held to access |shutdown_event_|
233   // when this indicates that shutdown has started because State doesn't provide
234   // memory barriers. It intentionally trades having to use a Lock on shutdown
235   // with not needing memory barriers at runtime.
236   const std::unique_ptr<State> state_;
237 
238   // Number of task sources that haven't completed their execution. Is
239   // decremented with a memory barrier after the last task of a task source
240   // runs. Is accessed with an acquire memory barrier in FlushForTesting(). The
241   // memory barriers ensure that the memory written by flushed task sources is
242   // visible when FlushForTesting() returns.
243   std::atomic_int num_incomplete_task_sources_{0};
244 
245   // Global policy the determines result of CanRunPriority().
246   std::atomic<CanRunPolicy> can_run_policy_;
247 
248   // Lock associated with |flush_cv_|. Partially synchronizes access to
249   // |num_incomplete_task_sources_|. Full synchronization isn't needed
250   // because it's atomic, but synchronization is needed to coordinate waking and
251   // sleeping at the right time. Fully synchronizes access to
252   // |flush_callbacks_for_testing_|.
253   mutable CheckedLock flush_lock_;
254 
255   // Signaled when |num_incomplete_task_sources_| is or reaches zero or when
256   // shutdown completes.
257   const std::unique_ptr<ConditionVariable> flush_cv_;
258 
259   // All invoked, if any, when |num_incomplete_task_sources_| is zero or when
260   // shutdown completes.
261   base::circular_deque<OnceClosure> flush_callbacks_for_testing_
262       GUARDED_BY(flush_lock_);
263 
264   // Synchronizes access to shutdown related members below.
265   mutable CheckedLock shutdown_lock_;
266 
267   // Event instantiated when shutdown starts and signaled when shutdown
268   // completes.
269   std::unique_ptr<WaitableEvent> shutdown_event_ GUARDED_BY(shutdown_lock_);
270 
271   // Ensures all state (e.g. dangling cleaned up workers) is coalesced before
272   // destroying the TaskTracker (e.g. in test environments).
273   // Ref. https://crbug.com/827615.
274   TrackedRefFactory<TaskTracker> tracked_ref_factory_;
275 };
276 
277 }  // namespace internal
278 }  // namespace base
279 
280 #endif  // BASE_TASK_THREAD_POOL_TASK_TRACKER_H_
281