• 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_THREAD_GROUP_IMPL_H_
6 #define BASE_TASK_THREAD_POOL_THREAD_GROUP_IMPL_H_
7 
8 #include <optional>
9 #include <string_view>
10 #include <vector>
11 
12 #include "base/base_export.h"
13 #include "base/gtest_prod_util.h"
14 #include "base/synchronization/condition_variable.h"
15 #include "base/synchronization/waitable_event.h"
16 #include "base/task/thread_pool/task_source.h"
17 #include "base/task/thread_pool/thread_group.h"
18 #include "base/task/thread_pool/tracked_ref.h"
19 #include "base/task/thread_pool/worker_thread.h"
20 #include "base/task/thread_pool/worker_thread_set.h"
21 #include "base/time/time.h"
22 
23 namespace base {
24 
25 class WorkerThreadObserver;
26 
27 namespace internal {
28 
29 class TaskTracker;
30 
31 // A group of |WorkerThread|s that run |Task|s.
32 //
33 // The thread group doesn't create threads until Start() is called. Tasks can be
34 // posted at any time but will not run until after Start() is called.
35 //
36 // This class is thread-safe.
37 class BASE_EXPORT ThreadGroupImpl : public ThreadGroup {
38  public:
39   // Constructs a group without workers.
40   //
41   // |histogram_label| is used to label the thread group's histograms as
42   // "ThreadPool." + histogram_name + "." + |histogram_label| + extra suffixes.
43   // It must not be empty. |thread group_label| is used to label the thread
44   // group's threads, it must not be empty. |thread_type_hint| is the preferred
45   // thread type; the actual thread type depends on shutdown state and platform
46   // capabilities. |task_tracker| keeps track of tasks.
47   ThreadGroupImpl(std::string_view histogram_label,
48                   std::string_view thread_group_label,
49                   ThreadType thread_type_hint,
50                   TrackedRef<TaskTracker> task_tracker,
51                   TrackedRef<Delegate> delegate);
52 
53   ThreadGroupImpl(const ThreadGroupImpl&) = delete;
54   ThreadGroupImpl& operator=(const ThreadGroupImpl&) = delete;
55   // Destroying a ThreadGroupImpl returned by Create() is not allowed
56   // in production; it is always leaked. In tests, it can only be destroyed
57   // after JoinForTesting() has returned.
58   ~ThreadGroupImpl() override;
59 
60   // ThreadGroup:
61   void Start(size_t max_tasks,
62              size_t max_best_effort_tasks,
63              TimeDelta suggested_reclaim_time,
64              scoped_refptr<SingleThreadTaskRunner> service_thread_task_runner,
65              WorkerThreadObserver* worker_thread_observer,
66              WorkerEnvironment worker_environment,
67              bool synchronous_thread_start_for_testing = false,
68              std::optional<TimeDelta> may_block_threshold =
69                  std::optional<TimeDelta>()) override;
70   void JoinForTesting() override;
71   void DidUpdateCanRunPolicy() override;
72   void OnShutdownStarted() override;
73   // Returns the number of workers that are idle (i.e. not running tasks).
74   size_t NumberOfIdleWorkersLockRequiredForTesting() const
75       EXCLUSIVE_LOCKS_REQUIRED(lock_) override;
76 
77  private:
78   class ScopedCommandsExecutor;
79   class WorkerDelegate;
80   friend class WorkerDelegate;
81 
82   // friend tests so that they can access |blocked_workers_poll_period| and
83   // may_block_threshold(), both in ThreadGroup.
84   friend class ThreadGroupImplBlockingTest;
85   friend class ThreadGroupImplMayBlockTest;
86   FRIEND_TEST_ALL_PREFIXES(ThreadGroupImplBlockingTest,
87                            ThreadBlockUnblockPremature);
88   FRIEND_TEST_ALL_PREFIXES(ThreadGroupImplBlockingTest,
89                            ThreadBlockUnblockPrematureBestEffort);
90 
91   // ThreadGroup:
92   void UpdateSortKey(TaskSource::Transaction transaction) override;
93   void PushTaskSourceAndWakeUpWorkers(
94       RegisteredTaskSourceAndTransaction transaction_with_task_source) override;
95   void EnsureEnoughWorkersLockRequired(BaseScopedCommandsExecutor* executor)
96       override EXCLUSIVE_LOCKS_REQUIRED(lock_);
97   void ScheduleAdjustMaxTasks() override;
98   void AdjustMaxTasks() override;
99 
100   // Creates a worker and schedules its start, if needed, to maintain one idle
101   // worker, |max_tasks_| permitting.
102   void MaintainAtLeastOneIdleWorkerLockRequired(
103       ScopedCommandsExecutor* executor) EXCLUSIVE_LOCKS_REQUIRED(lock_);
104 
105   // Creates a worker, adds it to the thread group, schedules its start and
106   // returns it. Cannot be called before Start().
107   scoped_refptr<WorkerThread> CreateAndRegisterWorkerLockRequired(
108       ScopedCommandsExecutor* executor) EXCLUSIVE_LOCKS_REQUIRED(lock_);
109 
110   // Returns the number of workers that are awake (i.e. not on the idle set).
111   size_t GetNumAwakeWorkersLockRequired() const EXCLUSIVE_LOCKS_REQUIRED(lock_);
112 
113   bool IsOnIdleSetLockRequired(WorkerThread* worker) const
114       EXCLUSIVE_LOCKS_REQUIRED(lock_);
115 
116   size_t worker_sequence_num_ GUARDED_BY(lock_) = 0;
117 
118   // Ordered set of idle workers; the order uses pointer comparison, this is
119   // arbitrary but stable. Initially, all workers are on this set. A worker is
120   // removed from the set before its WakeUp() function is called and when it
121   // receives work from GetWork() (a worker calls GetWork() when its sleep
122   // timeout expires, even if its WakeUp() method hasn't been called). A worker
123   // is inserted on this set when it receives nullptr from GetWork().
124   WorkerThreadSet idle_workers_set_ GUARDED_BY(lock_);
125 
126   // Ensures recently cleaned up workers (ref.
127   // WorkerDelegate::CleanupLockRequired()) had time to exit as
128   // they have a raw reference to |this| (and to TaskTracker) which can
129   // otherwise result in racy use-after-frees per no longer being part of
130   // |workers_| and hence not being explicitly joined in JoinForTesting():
131   // https://crbug.com/810464. Uses AtomicRefCount to make its only public
132   // method thread-safe.
133   TrackedRefFactory<ThreadGroupImpl> tracked_ref_factory_;
134 };
135 
136 }  // namespace internal
137 }  // namespace base
138 
139 #endif  // BASE_TASK_THREAD_POOL_THREAD_GROUP_IMPL_H_
140