1 // Copyright 2016 The Chromium Authors. All rights reserved.
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/macros.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/synchronization/atomic_flag.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "base/task/common/checked_lock.h"
16 #include "base/task/thread_pool/task_source.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 defined(OS_WIN)
52     SHARED_COM,
53     DEDICATED_COM,
54 #endif  // defined(OS_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 = 0;
66 
67     // Called by |worker|'s thread when it enters its main function.
68     virtual void OnMainEntry(const 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 WorkerThread after it ran a Task. If the Task's
74     // TaskSource should be reenqueued, it is passed to |task_source|.
75     // Otherwise, |task_source| is nullptr.
76     virtual void DidProcessTask(RegisteredTaskSource task_source) = 0;
77 
78     // Called to determine how long to sleep before the next call to GetWork().
79     // GetWork() may be called before this timeout expires if the worker's
80     // WakeUp() method is called.
81     virtual TimeDelta GetSleepTimeout() = 0;
82 
83     // Called by the WorkerThread's thread to wait for work. Override this
84     // method if the thread in question needs special handling to go to sleep.
85     // |wake_up_event| is a manually resettable event and is signaled on
86     // WorkerThread::WakeUp()
87     virtual void WaitForWork(WaitableEvent* wake_up_event);
88 
89     // Called by |worker|'s thread right before the main function exits. The
90     // Delegate is free to release any associated resources in this call. It is
91     // guaranteed that WorkerThread won't access the Delegate or the
92     // TaskTracker after calling OnMainExit() on the Delegate.
OnMainExit(WorkerThread * worker)93     virtual void OnMainExit(WorkerThread* worker) {}
94   };
95 
96   // Creates a WorkerThread that runs Tasks from TaskSources returned by
97   // |delegate|. No actual thread will be created for this WorkerThread
98   // before Start() is called. |priority_hint| is the preferred thread priority;
99   // the actual thread priority depends on shutdown state and platform
100   // capabilities. |task_tracker| is used to handle shutdown behavior of Tasks.
101   // |predecessor_lock| is a lock that is allowed to be held when calling
102   // methods on this WorkerThread. |backward_compatibility| indicates
103   // whether backward compatibility is enabled. Either JoinForTesting() or
104   // Cleanup() must be called before releasing the last external reference.
105   WorkerThread(ThreadPriority priority_hint,
106                std::unique_ptr<Delegate> delegate,
107                TrackedRef<TaskTracker> task_tracker,
108                const CheckedLock* predecessor_lock = nullptr);
109 
110   // Creates a thread to back the WorkerThread. The thread will be in a wait
111   // state pending a WakeUp() call. No thread will be created if Cleanup() was
112   // called. If specified, |worker_thread_observer| will be notified when the
113   // worker enters and exits its main function. It must not be destroyed before
114   // JoinForTesting() has returned (must never be destroyed in production).
115   // Returns true on success.
116   bool Start(WorkerThreadObserver* worker_thread_observer = nullptr);
117 
118   // Wakes up this WorkerThread if it wasn't already awake. After this is
119   // called, this WorkerThread will run Tasks from TaskSources returned by
120   // the GetWork() method of its delegate until it returns nullptr. No-op if
121   // Start() wasn't called. DCHECKs if called after Start() has failed or after
122   // Cleanup() has been called.
123   void WakeUp();
124 
delegate()125   WorkerThread::Delegate* delegate() { return delegate_.get(); }
126 
127   // Joins this WorkerThread. If a Task is already running, it will be
128   // allowed to complete its execution. This can only be called once.
129   //
130   // Note: A thread that detaches before JoinForTesting() is called may still be
131   // running after JoinForTesting() returns. However, it can't run tasks after
132   // JoinForTesting() returns.
133   void JoinForTesting();
134 
135   // Returns true if the worker is alive.
136   bool ThreadAliveForTesting() const;
137 
138   // Makes a request to cleanup the worker. This may be called from any thread.
139   // The caller is expected to release its reference to this object after
140   // calling Cleanup(). Further method calls after Cleanup() returns are
141   // undefined.
142   //
143   // Expected Usage:
144   //   scoped_refptr<WorkerThread> worker_ = /* Existing Worker */
145   //   worker_->Cleanup();
146   //   worker_ = nullptr;
147   void Cleanup();
148 
149   // Informs this WorkerThread about periods during which it is not being
150   // used. Thread-safe.
151   void BeginUnusedPeriod();
152   void EndUnusedPeriod();
153   // Returns the last time this WorkerThread was used. Returns a null time if
154   // this WorkerThread is currently in-use. Thread-safe.
155   TimeTicks GetLastUsedTime() const;
156 
157  private:
158   friend class RefCountedThreadSafe<WorkerThread>;
159   class Thread;
160 
161   ~WorkerThread() override;
162 
163   bool ShouldExit() const;
164 
165   // Returns the thread priority to use based on the priority hint, current
166   // shutdown state, and platform capabilities.
167   ThreadPriority GetDesiredThreadPriority() const;
168 
169   // Changes the thread priority to |desired_thread_priority|. Must be called on
170   // the thread managed by |this|.
171   void UpdateThreadPriority(ThreadPriority desired_thread_priority);
172 
173   // PlatformThread::Delegate:
174   void ThreadMain() override;
175 
176   // Dummy frames to act as "RunLabeledWorker()" (see RunMain() below). Their
177   // impl is aliased to prevent compiler/linker from optimizing them out.
178   void RunPooledWorker();
179   void RunBackgroundPooledWorker();
180   void RunSharedWorker();
181   void RunBackgroundSharedWorker();
182   void RunDedicatedWorker();
183   void RunBackgroundDedicatedWorker();
184 #if defined(OS_WIN)
185   void RunSharedCOMWorker();
186   void RunBackgroundSharedCOMWorker();
187   void RunDedicatedCOMWorker();
188   void RunBackgroundDedicatedCOMWorker();
189 #endif  // defined(OS_WIN)
190 
191   // The real main, invoked through :
192   //     ThreadMain() -> RunLabeledWorker() -> RunWorker().
193   // "RunLabeledWorker()" is a dummy frame based on ThreadLabel+ThreadPriority
194   // and used to easily identify threads in stack traces.
195   void RunWorker();
196 
197   // Self-reference to prevent destruction of |this| while the thread is alive.
198   // Set in Start() before creating the thread. Reset in ThreadMain() before the
199   // thread exits. No lock required because the first access occurs before the
200   // thread is created and the second access occurs on the thread.
201   scoped_refptr<WorkerThread> self_;
202 
203   mutable CheckedLock thread_lock_;
204 
205   // Handle for the thread managed by |this|.
206   PlatformThreadHandle thread_handle_ GUARDED_BY(thread_lock_);
207 
208   // The last time this worker was used by its owner (e.g. to process work or
209   // stand as a required idle thread).
210   TimeTicks last_used_time_ GUARDED_BY(thread_lock_);
211 
212   // Event to wake up the thread managed by |this|.
213   WaitableEvent wake_up_event_{WaitableEvent::ResetPolicy::AUTOMATIC,
214                                WaitableEvent::InitialState::NOT_SIGNALED};
215 
216   // Whether the thread should exit. Set by Cleanup().
217   AtomicFlag should_exit_;
218 
219   const std::unique_ptr<Delegate> delegate_;
220   const TrackedRef<TaskTracker> task_tracker_;
221 
222   // Optional observer notified when a worker enters and exits its main
223   // function. Set in Start() and never modified afterwards.
224   WorkerThreadObserver* worker_thread_observer_ = nullptr;
225 
226   // Desired thread priority.
227   const ThreadPriority priority_hint_;
228 
229   // Actual thread priority. Can be different than |priority_hint_| depending on
230   // system capabilities and shutdown state. No lock required because all post-
231   // construction accesses occur on the thread.
232   ThreadPriority current_thread_priority_;
233 
234   // Set once JoinForTesting() has been called.
235   AtomicFlag join_called_for_testing_;
236 
237   DISALLOW_COPY_AND_ASSIGN(WorkerThread);
238 };
239 
240 }  // namespace internal
241 }  // namespace base
242 
243 #endif  // BASE_TASK_THREAD_POOL_WORKER_THREAD_H_
244