|  | // Copyright 2016 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef BASE_TASK_SCHEDULER_SCHEDULER_WORKER_H_ | 
|  | #define BASE_TASK_SCHEDULER_SCHEDULER_WORKER_H_ | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "base/base_export.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/memory/ref_counted.h" | 
|  | #include "base/synchronization/atomic_flag.h" | 
|  | #include "base/synchronization/waitable_event.h" | 
|  | #include "base/task_scheduler/can_schedule_sequence_observer.h" | 
|  | #include "base/task_scheduler/scheduler_lock.h" | 
|  | #include "base/task_scheduler/scheduler_worker_params.h" | 
|  | #include "base/task_scheduler/sequence.h" | 
|  | #include "base/task_scheduler/tracked_ref.h" | 
|  | #include "base/threading/platform_thread.h" | 
|  | #include "base/time/time.h" | 
|  | #include "build_config.h" | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | #include "base/win/com_init_check_hook.h" | 
|  | #endif | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | class SchedulerWorkerObserver; | 
|  |  | 
|  | namespace internal { | 
|  |  | 
|  | class TaskTracker; | 
|  |  | 
|  | // A worker that manages a single thread to run Tasks from Sequences returned | 
|  | // by a delegate. | 
|  | // | 
|  | // A SchedulerWorker starts out sleeping. It is woken up by a call to WakeUp(). | 
|  | // After a wake-up, a SchedulerWorker runs Tasks from Sequences returned by the | 
|  | // GetWork() method of its delegate as long as it doesn't return nullptr. It | 
|  | // also periodically checks with its TaskTracker whether shutdown has completed | 
|  | // and exits when it has. | 
|  | // | 
|  | // This class is thread-safe. | 
|  | class BASE_EXPORT SchedulerWorker | 
|  | : public RefCountedThreadSafe<SchedulerWorker>, | 
|  | public PlatformThread::Delegate { | 
|  | public: | 
|  | // Labels this SchedulerWorker's association. This doesn't affect any logic | 
|  | // but will add a stack frame labeling this thread for ease of stack trace | 
|  | // identification. | 
|  | enum class ThreadLabel { | 
|  | POOLED, | 
|  | SHARED, | 
|  | DEDICATED, | 
|  | #if defined(OS_WIN) | 
|  | SHARED_COM, | 
|  | DEDICATED_COM, | 
|  | #endif  // defined(OS_WIN) | 
|  | }; | 
|  |  | 
|  | // Delegate interface for SchedulerWorker. All methods except | 
|  | // OnCanScheduleSequence() (inherited from CanScheduleSequenceObserver) are | 
|  | // called from the thread managed by the SchedulerWorker instance. | 
|  | class BASE_EXPORT Delegate : public CanScheduleSequenceObserver { | 
|  | public: | 
|  | ~Delegate() override = default; | 
|  |  | 
|  | // Returns the ThreadLabel the Delegate wants its SchedulerWorkers' stacks | 
|  | // to be labeled with. | 
|  | virtual ThreadLabel GetThreadLabel() const = 0; | 
|  |  | 
|  | // Called by |worker|'s thread when it enters its main function. | 
|  | virtual void OnMainEntry(const SchedulerWorker* worker) = 0; | 
|  |  | 
|  | // Called by |worker|'s thread to get a Sequence from which to run a Task. | 
|  | virtual scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) = 0; | 
|  |  | 
|  | // Called by the SchedulerWorker after it ran a task. | 
|  | virtual void DidRunTask() = 0; | 
|  |  | 
|  | // Called when |sequence| isn't empty after the SchedulerWorker pops a Task | 
|  | // from it. |sequence| is the last Sequence returned by GetWork(). | 
|  | // | 
|  | // TODO(fdoray): Rename to RescheduleSequence() to match TaskTracker | 
|  | // terminology. | 
|  | virtual void ReEnqueueSequence(scoped_refptr<Sequence> sequence) = 0; | 
|  |  | 
|  | // Called to determine how long to sleep before the next call to GetWork(). | 
|  | // GetWork() may be called before this timeout expires if the worker's | 
|  | // WakeUp() method is called. | 
|  | virtual TimeDelta GetSleepTimeout() = 0; | 
|  |  | 
|  | // Called by the SchedulerWorker's thread to wait for work. Override this | 
|  | // method if the thread in question needs special handling to go to sleep. | 
|  | // |wake_up_event| is a manually resettable event and is signaled on | 
|  | // SchedulerWorker::WakeUp() | 
|  | virtual void WaitForWork(WaitableEvent* wake_up_event); | 
|  |  | 
|  | // Called by |worker|'s thread right before the main function exits. The | 
|  | // Delegate is free to release any associated resources in this call. It is | 
|  | // guaranteed that SchedulerWorker won't access the Delegate or the | 
|  | // TaskTracker after calling OnMainExit() on the Delegate. | 
|  | virtual void OnMainExit(SchedulerWorker* worker) {} | 
|  | }; | 
|  |  | 
|  | // Creates a SchedulerWorker that runs Tasks from Sequences returned by | 
|  | // |delegate|. No actual thread will be created for this SchedulerWorker | 
|  | // before Start() is called. |priority_hint| is the preferred thread priority; | 
|  | // the actual thread priority depends on shutdown state and platform | 
|  | // capabilities. |task_tracker| is used to handle shutdown behavior of Tasks. | 
|  | // |predecessor_lock| is a lock that is allowed to be held when calling | 
|  | // methods on this SchedulerWorker. |backward_compatibility| indicates | 
|  | // whether backward compatibility is enabled. Either JoinForTesting() or | 
|  | // Cleanup() must be called before releasing the last external reference. | 
|  | SchedulerWorker(ThreadPriority priority_hint, | 
|  | std::unique_ptr<Delegate> delegate, | 
|  | TrackedRef<TaskTracker> task_tracker, | 
|  | const SchedulerLock* predecessor_lock = nullptr, | 
|  | SchedulerBackwardCompatibility backward_compatibility = | 
|  | SchedulerBackwardCompatibility::DISABLED); | 
|  |  | 
|  | // Creates a thread to back the SchedulerWorker. The thread will be in a wait | 
|  | // state pending a WakeUp() call. No thread will be created if Cleanup() was | 
|  | // called. If specified, |scheduler_worker_observer| will be notified when the | 
|  | // worker enters and exits its main function. It must not be destroyed before | 
|  | // JoinForTesting() has returned (must never be destroyed in production). | 
|  | // Returns true on success. | 
|  | bool Start(SchedulerWorkerObserver* scheduler_worker_observer = nullptr); | 
|  |  | 
|  | // Wakes up this SchedulerWorker if it wasn't already awake. After this is | 
|  | // called, this SchedulerWorker will run Tasks from Sequences returned by the | 
|  | // GetWork() method of its delegate until it returns nullptr. No-op if Start() | 
|  | // wasn't called. DCHECKs if called after Start() has failed or after | 
|  | // Cleanup() has been called. | 
|  | void WakeUp(); | 
|  |  | 
|  | SchedulerWorker::Delegate* delegate() { return delegate_.get(); } | 
|  |  | 
|  | // Joins this SchedulerWorker. If a Task is already running, it will be | 
|  | // allowed to complete its execution. This can only be called once. | 
|  | // | 
|  | // Note: A thread that detaches before JoinForTesting() is called may still be | 
|  | // running after JoinForTesting() returns. However, it can't run tasks after | 
|  | // JoinForTesting() returns. | 
|  | void JoinForTesting(); | 
|  |  | 
|  | // Returns true if the worker is alive. | 
|  | bool ThreadAliveForTesting() const; | 
|  |  | 
|  | // Makes a request to cleanup the worker. This may be called from any thread. | 
|  | // The caller is expected to release its reference to this object after | 
|  | // calling Cleanup(). Further method calls after Cleanup() returns are | 
|  | // undefined. | 
|  | // | 
|  | // Expected Usage: | 
|  | //   scoped_refptr<SchedulerWorker> worker_ = /* Existing Worker */ | 
|  | //   worker_->Cleanup(); | 
|  | //   worker_ = nullptr; | 
|  | void Cleanup(); | 
|  |  | 
|  | private: | 
|  | friend class RefCountedThreadSafe<SchedulerWorker>; | 
|  | class Thread; | 
|  |  | 
|  | ~SchedulerWorker() override; | 
|  |  | 
|  | bool ShouldExit() const; | 
|  |  | 
|  | // Returns the thread priority to use based on the priority hint, current | 
|  | // shutdown state, and platform capabilities. | 
|  | ThreadPriority GetDesiredThreadPriority() const; | 
|  |  | 
|  | // Changes the thread priority to |desired_thread_priority|. Must be called on | 
|  | // the thread managed by |this|. | 
|  | void UpdateThreadPriority(ThreadPriority desired_thread_priority); | 
|  |  | 
|  | // PlatformThread::Delegate: | 
|  | void ThreadMain() override; | 
|  |  | 
|  | // Dummy frames to act as "RunLabeledWorker()" (see RunMain() below). Their | 
|  | // impl is aliased to prevent compiler/linker from optimizing them out. | 
|  | void RunPooledWorker(); | 
|  | void RunBackgroundPooledWorker(); | 
|  | void RunSharedWorker(); | 
|  | void RunBackgroundSharedWorker(); | 
|  | void RunDedicatedWorker(); | 
|  | void RunBackgroundDedicatedWorker(); | 
|  | #if defined(OS_WIN) | 
|  | void RunSharedCOMWorker(); | 
|  | void RunBackgroundSharedCOMWorker(); | 
|  | void RunDedicatedCOMWorker(); | 
|  | void RunBackgroundDedicatedCOMWorker(); | 
|  | #endif  // defined(OS_WIN) | 
|  |  | 
|  | // The real main, invoked through : | 
|  | //     ThreadMain() -> RunLabeledWorker() -> RunWorker(). | 
|  | // "RunLabeledWorker()" is a dummy frame based on ThreadLabel+ThreadPriority | 
|  | // and used to easily identify threads in stack traces. | 
|  | void RunWorker(); | 
|  |  | 
|  | // Self-reference to prevent destruction of |this| while the thread is alive. | 
|  | // Set in Start() before creating the thread. Reset in ThreadMain() before the | 
|  | // thread exits. No lock required because the first access occurs before the | 
|  | // thread is created and the second access occurs on the thread. | 
|  | scoped_refptr<SchedulerWorker> self_; | 
|  |  | 
|  | // Synchronizes access to |thread_handle_|. | 
|  | mutable SchedulerLock thread_lock_; | 
|  |  | 
|  | // Handle for the thread managed by |this|. | 
|  | PlatformThreadHandle thread_handle_; | 
|  |  | 
|  | // Event to wake up the thread managed by |this|. | 
|  | WaitableEvent wake_up_event_{WaitableEvent::ResetPolicy::AUTOMATIC, | 
|  | WaitableEvent::InitialState::NOT_SIGNALED}; | 
|  |  | 
|  | // Whether the thread should exit. Set by Cleanup(). | 
|  | AtomicFlag should_exit_; | 
|  |  | 
|  | const std::unique_ptr<Delegate> delegate_; | 
|  | const TrackedRef<TaskTracker> task_tracker_; | 
|  |  | 
|  | // Optional observer notified when a worker enters and exits its main | 
|  | // function. Set in Start() and never modified afterwards. | 
|  | SchedulerWorkerObserver* scheduler_worker_observer_ = nullptr; | 
|  |  | 
|  | // Desired thread priority. | 
|  | const ThreadPriority priority_hint_; | 
|  |  | 
|  | // Actual thread priority. Can be different than |priority_hint_| depending on | 
|  | // system capabilities and shutdown state. No lock required because all post- | 
|  | // construction accesses occur on the thread. | 
|  | ThreadPriority current_thread_priority_; | 
|  |  | 
|  | #if defined(OS_WIN) && !defined(COM_INIT_CHECK_HOOK_ENABLED) | 
|  | const SchedulerBackwardCompatibility backward_compatibility_; | 
|  | #endif | 
|  |  | 
|  | // Set once JoinForTesting() has been called. | 
|  | AtomicFlag join_called_for_testing_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(SchedulerWorker); | 
|  | }; | 
|  |  | 
|  | }  // namespace internal | 
|  | }  // namespace base | 
|  |  | 
|  | #endif  // BASE_TASK_SCHEDULER_SCHEDULER_WORKER_H_ |