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