• 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_WORKER_THREAD_H_
6 #define BASE_TASK_THREAD_POOL_WORKER_THREAD_H_
7 
8 #include <memory>
9 
10 #include "base/base_export.h"
11 #include "base/compiler_specific.h"
12 #include "base/memory/raw_ptr.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/synchronization/atomic_flag.h"
15 #include "base/synchronization/waitable_event.h"
16 #include "base/task/common/checked_lock.h"
17 #include "base/task/thread_pool/task_source.h"
18 #include "base/task/thread_pool/tracked_ref.h"
19 #include "base/thread_annotations.h"
20 #include "base/threading/platform_thread.h"
21 #include "base/time/time.h"
22 #include "build/build_config.h"
23 
24 namespace base {
25 
26 class WorkerThreadObserver;
27 
28 namespace internal {
29 
30 class TaskTracker;
31 
32 // A worker that manages a single thread to run Tasks from TaskSources returned
33 // by a delegate.
34 //
35 // A WorkerThread starts out sleeping. It is woken up by a call to WakeUp().
36 // After a wake-up, a WorkerThread runs Tasks from TaskSources returned by
37 // the GetWork() method of its delegate as long as it doesn't return nullptr. It
38 // also periodically checks with its TaskTracker whether shutdown has completed
39 // and exits when it has.
40 //
41 // This class is thread-safe.
42 class BASE_EXPORT WorkerThread : public RefCountedThreadSafe<WorkerThread>,
43                                  public PlatformThread::Delegate {
44  public:
45   // Labels this WorkerThread's association. This doesn't affect any logic
46   // but will add a stack frame labeling this thread for ease of stack trace
47   // identification.
48   enum class ThreadLabel {
49     POOLED,
50     SHARED,
51     DEDICATED,
52 #if BUILDFLAG(IS_WIN)
53     SHARED_COM,
54     DEDICATED_COM,
55 #endif  // BUILDFLAG(IS_WIN)
56   };
57 
58   // Delegate interface for WorkerThread. All methods are called from the
59   // thread managed by the WorkerThread instance.
60   class BASE_EXPORT Delegate {
61    public:
62     virtual ~Delegate() = default;
63 
64     // Returns the ThreadLabel the Delegate wants its WorkerThreads' stacks
65     // to be labeled with.
66     virtual ThreadLabel GetThreadLabel() const = 0;
67 
68     // Called by |worker|'s thread when it enters its main function.
69     virtual void OnMainEntry(WorkerThread* worker) = 0;
70 
71     // Called by |worker|'s thread to get a TaskSource from which to run a Task.
72     virtual RegisteredTaskSource GetWork(WorkerThread* worker) = 0;
73 
74     // Called by the WorkerThread after it ran a Task. If the Task's
75     // TaskSource should be reenqueued, it is passed to |task_source|.
76     // Otherwise, |task_source| is nullptr.
77     virtual void DidProcessTask(RegisteredTaskSource task_source) = 0;
78 
79     // Called to determine how long to sleep before the next call to GetWork().
80     // GetWork() may be called before this timeout expires if the worker's
81     // WakeUp() method is called.
82     virtual TimeDelta GetSleepTimeout() = 0;
83 
84     // Called by the WorkerThread's thread to wait for work. Override this
85     // method if the thread in question needs special handling to go to sleep.
86     // |wake_up_event| is a manually resettable event and is signaled on
87     // WorkerThread::WakeUp()
88     virtual void WaitForWork(WaitableEvent* wake_up_event);
89 
90     // Called by |worker|'s thread right before the main function exits. The
91     // Delegate is free to release any associated resources in this call. It is
92     // guaranteed that WorkerThread won't access the Delegate or the
93     // TaskTracker after calling OnMainExit() on the Delegate.
OnMainExit(WorkerThread * worker)94     virtual void OnMainExit(WorkerThread* worker) {}
95 
96     // Called by a WorkerThread when it is woken up without any work being
97     // available for it to run.
RecordUnnecessaryWakeup()98     virtual void RecordUnnecessaryWakeup() {}
99 
100     static constexpr TimeDelta kPurgeThreadCacheIdleDelay = Seconds(1);
101   };
102 
103   // Creates a WorkerThread that runs Tasks from TaskSources returned by
104   // |delegate|. No actual thread will be created for this WorkerThread
105   // before Start() is called. |thread_type_hint| is the preferred thread type;
106   // the actual thread type depends on shutdown state and platform
107   // capabilities. |task_tracker| is used to handle shutdown behavior of Tasks.
108   // |sequence_num| is an index that helps identifying this WorkerThread.
109   // |predecessor_lock| is a lock that is allowed to be held when calling
110   // methods on this WorkerThread. |backward_compatibility| indicates
111   // whether backward compatibility is enabled. Either JoinForTesting() or
112   // Cleanup() must be called before releasing the last external reference.
113   WorkerThread(ThreadType thread_type_hint,
114                std::unique_ptr<Delegate> delegate,
115                TrackedRef<TaskTracker> task_tracker,
116                size_t sequence_num,
117                const CheckedLock* predecessor_lock = nullptr);
118 
119   WorkerThread(const WorkerThread&) = delete;
120   WorkerThread& operator=(const WorkerThread&) = delete;
121 
122   // Creates a thread to back the WorkerThread. The thread will be in a wait
123   // state pending a WakeUp() call. No thread will be created if Cleanup() was
124   // called. `io_thread_task_runner` is used to setup FileDescriptorWatcher on
125   // worker threads. `io_thread_task_runner` must refer to a Thread with
126   // MessgaePumpType::IO. If specified, |worker_thread_observer| will be
127   // notified when the worker enters and exits its main function. It must not be
128   // destroyed before JoinForTesting() has returned (must never be destroyed in
129   // production). Returns true on success.
130   bool Start(scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_,
131              WorkerThreadObserver* worker_thread_observer = nullptr);
132 
133   // Wakes up this WorkerThread if it wasn't already awake. After this is
134   // called, this WorkerThread will run Tasks from TaskSources returned by
135   // the GetWork() method of its delegate until it returns nullptr. No-op if
136   // Start() wasn't called. DCHECKs if called after Start() has failed or after
137   // Cleanup() has been called.
138   void WakeUp();
139 
delegate()140   WorkerThread::Delegate* delegate() { return delegate_.get(); }
141 
142   // Joins this WorkerThread. If a Task is already running, it will be
143   // allowed to complete its execution. This can only be called once.
144   //
145   // Note: A thread that detaches before JoinForTesting() is called may still be
146   // running after JoinForTesting() returns. However, it can't run tasks after
147   // JoinForTesting() returns.
148   void JoinForTesting();
149 
150   // Returns true if the worker is alive.
151   bool ThreadAliveForTesting() const;
152 
153   // Makes a request to cleanup the worker. This may be called from any thread.
154   // The caller is expected to release its reference to this object after
155   // calling Cleanup(). Further method calls after Cleanup() returns are
156   // undefined.
157   //
158   // Expected Usage:
159   //   scoped_refptr<WorkerThread> worker_ = /* Existing Worker */
160   //   worker_->Cleanup();
161   //   worker_ = nullptr;
162   void Cleanup();
163 
164   // Possibly updates the thread type to the appropriate type based on the
165   // thread type hint, current shutdown state, and platform capabilities.
166   // Must be called on the thread managed by |this|.
167   void MaybeUpdateThreadType();
168 
169   // Informs this WorkerThread about periods during which it is not being
170   // used. Thread-safe.
171   void BeginUnusedPeriod();
172   void EndUnusedPeriod();
173   // Returns the last time this WorkerThread was used. Returns a null time if
174   // this WorkerThread is currently in-use. Thread-safe.
175   TimeTicks GetLastUsedTime() const;
176 
sequence_num()177   size_t sequence_num() const { return sequence_num_; }
178 
179  private:
180   friend class RefCountedThreadSafe<WorkerThread>;
181   class Thread;
182 
183   ~WorkerThread() override;
184 
185   bool ShouldExit() const;
186 
187   // Returns the thread type to use based on the thread type hint, current
188   // shutdown state, and platform capabilities.
189   ThreadType GetDesiredThreadType() const;
190 
191   // Changes the thread type to |desired_thread_type|. Must be called on the
192   // thread managed by |this|.
193   void UpdateThreadType(ThreadType desired_thread_type);
194 
195   // PlatformThread::Delegate:
196   void ThreadMain() override;
197 
198   // Dummy frames to act as "RunLabeledWorker()" (see RunMain() below). Their
199   // impl is aliased to prevent compiler/linker from optimizing them out.
200   void RunPooledWorker();
201   void RunBackgroundPooledWorker();
202   void RunSharedWorker();
203   void RunBackgroundSharedWorker();
204   void RunDedicatedWorker();
205   void RunBackgroundDedicatedWorker();
206 #if BUILDFLAG(IS_WIN)
207   void RunSharedCOMWorker();
208   void RunBackgroundSharedCOMWorker();
209   void RunDedicatedCOMWorker();
210   void RunBackgroundDedicatedCOMWorker();
211 #endif  // BUILDFLAG(IS_WIN)
212 
213   // The real main, invoked through :
214   //     ThreadMain() -> RunLabeledWorker() -> RunWorker().
215   // "RunLabeledWorker()" is a dummy frame based on ThreadLabel+ThreadType
216   // and used to easily identify threads in stack traces.
217   NOT_TAIL_CALLED void RunWorker();
218 
219   // Self-reference to prevent destruction of |this| while the thread is alive.
220   // Set in Start() before creating the thread. Reset in ThreadMain() before the
221   // thread exits. No lock required because the first access occurs before the
222   // thread is created and the second access occurs on the thread.
223   scoped_refptr<WorkerThread> self_;
224 
225   mutable CheckedLock thread_lock_;
226 
227   // Handle for the thread managed by |this|.
228   PlatformThreadHandle thread_handle_ GUARDED_BY(thread_lock_);
229 
230   // The last time this worker was used by its owner (e.g. to process work or
231   // stand as a required idle thread).
232   TimeTicks last_used_time_ GUARDED_BY(thread_lock_);
233 
234   // Event to wake up the thread managed by |this|.
235   WaitableEvent wake_up_event_{WaitableEvent::ResetPolicy::AUTOMATIC,
236                                WaitableEvent::InitialState::NOT_SIGNALED};
237 
238   // Whether the thread should exit. Set by Cleanup().
239   AtomicFlag should_exit_;
240 
241   const std::unique_ptr<Delegate> delegate_;
242   const TrackedRef<TaskTracker> task_tracker_;
243 
244   // Optional observer notified when a worker enters and exits its main
245   // function. Set in Start() and never modified afterwards.
246   raw_ptr<WorkerThreadObserver> worker_thread_observer_ = nullptr;
247 
248   // Desired thread type.
249   const ThreadType thread_type_hint_;
250 
251   // Actual thread type. Can be different than |thread_type_hint_|
252   // depending on system capabilities and shutdown state. No lock required
253   // because all post-construction accesses occur on the thread.
254   ThreadType current_thread_type_;
255 
256   // Set once JoinForTesting() has been called.
257   AtomicFlag join_called_for_testing_;
258 
259   const size_t sequence_num_;
260 
261   // Service thread task runner.
262   scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_;
263 };
264 
265 }  // namespace internal
266 }  // namespace base
267 
268 #endif  // BASE_TASK_THREAD_POOL_WORKER_THREAD_H_
269