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