Bug 1867190 - Initialise the PHC allocate delay later r=glandium
[gecko.git] / xpcom / threads / TimerThread.h
blobf6a5827b943467a53658bc6a415813420a98341f
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef TimerThread_h___
8 #define TimerThread_h___
10 #include "nsIObserver.h"
11 #include "nsIRunnable.h"
12 #include "nsIThread.h"
14 #include "nsTimerImpl.h"
15 #include "nsThreadUtils.h"
17 #include "nsTArray.h"
19 #include "mozilla/Attributes.h"
20 #include "mozilla/HalTypes.h"
21 #include "mozilla/Monitor.h"
22 #include "mozilla/ProfilerUtils.h"
24 // Enable this to compute lots of interesting statistics and print them out when
25 // PrintStatistics() is called.
26 #define TIMER_THREAD_STATISTICS 0
28 class TimerThread final : public mozilla::Runnable, public nsIObserver {
29 public:
30 typedef mozilla::Monitor Monitor;
31 typedef mozilla::MutexAutoLock MutexAutoLock;
32 typedef mozilla::TimeStamp TimeStamp;
33 typedef mozilla::TimeDuration TimeDuration;
35 TimerThread();
37 NS_DECL_ISUPPORTS_INHERITED
38 NS_DECL_NSIRUNNABLE
39 NS_DECL_NSIOBSERVER
41 nsresult Shutdown();
43 nsresult AddTimer(nsTimerImpl* aTimer, const MutexAutoLock& aProofOfLock)
44 MOZ_REQUIRES(aTimer->mMutex);
45 nsresult RemoveTimer(nsTimerImpl* aTimer, const MutexAutoLock& aProofOfLock)
46 MOZ_REQUIRES(aTimer->mMutex);
47 // Considering only the first 'aSearchBound' timers (in firing order), returns
48 // the timeout of the first non-low-priority timer, on the current thread,
49 // that will fire before 'aDefault'. If no such timer exists, 'aDefault' is
50 // returned.
51 TimeStamp FindNextFireTimeForCurrentThread(TimeStamp aDefault,
52 uint32_t aSearchBound);
54 void DoBeforeSleep();
55 void DoAfterSleep();
57 bool IsOnTimerThread() const { return mThread->IsOnCurrentThread(); }
59 uint32_t AllowedEarlyFiringMicroseconds();
60 nsresult GetTimers(nsTArray<RefPtr<nsITimer>>& aRetVal);
62 private:
63 ~TimerThread();
65 bool mInitialized;
67 // These internal helper methods must be called while mMonitor is held.
68 // AddTimerInternal returns false if the insertion failed.
69 bool AddTimerInternal(nsTimerImpl& aTimer) MOZ_REQUIRES(mMonitor);
70 bool RemoveTimerInternal(nsTimerImpl& aTimer)
71 MOZ_REQUIRES(mMonitor, aTimer.mMutex);
72 void RemoveLeadingCanceledTimersInternal() MOZ_REQUIRES(mMonitor);
73 void RemoveFirstTimerInternal() MOZ_REQUIRES(mMonitor);
74 nsresult Init() MOZ_REQUIRES(mMonitor);
76 void PostTimerEvent(already_AddRefed<nsTimerImpl> aTimerRef)
77 MOZ_REQUIRES(mMonitor);
79 // Using atomic because this value is written to in one place, and read from
80 // in another, and those two locations are likely to be executed from separate
81 // threads. Reads/writes to an aligned value this size should be atomic even
82 // without using std::atomic, but doing this explicitly provides a good
83 // reminder that this is accessed from multiple threads.
84 std::atomic<mozilla::hal::ProcessPriority> mCachedPriority =
85 mozilla::hal::PROCESS_PRIORITY_UNKNOWN;
87 nsCOMPtr<nsIThread> mThread;
88 // Lock ordering requirements:
89 // (optional) ThreadWrapper::sMutex ->
90 // (optional) nsTimerImpl::mMutex ->
91 // TimerThread::mMonitor
92 Monitor mMonitor;
94 bool mShutdown MOZ_GUARDED_BY(mMonitor);
95 bool mWaiting MOZ_GUARDED_BY(mMonitor);
96 bool mNotified MOZ_GUARDED_BY(mMonitor);
97 bool mSleeping MOZ_GUARDED_BY(mMonitor);
99 class Entry final {
100 public:
101 explicit Entry(nsTimerImpl& aTimerImpl)
102 : mTimeout(aTimerImpl.mTimeout),
103 mDelay(aTimerImpl.mDelay),
104 mTimerImpl(&aTimerImpl) {
105 aTimerImpl.SetIsInTimerThread(true);
108 // Create an already-canceled entry with the given timeout.
109 explicit Entry(TimeStamp aTimeout)
110 : mTimeout(std::move(aTimeout)), mTimerImpl(nullptr) {}
112 // Don't allow copies, otherwise which one would manage `IsInTimerThread`?
113 Entry(const Entry&) = delete;
114 Entry& operator=(const Entry&) = delete;
116 // Move-only.
117 Entry(Entry&&) = default;
118 Entry& operator=(Entry&&) = default;
120 ~Entry() {
121 if (mTimerImpl) {
122 mTimerImpl->mMutex.AssertCurrentThreadOwns();
123 mTimerImpl->SetIsInTimerThread(false);
127 nsTimerImpl* Value() const { return mTimerImpl; }
129 void Forget() {
130 if (MOZ_UNLIKELY(!mTimerImpl)) {
131 return;
133 mTimerImpl->mMutex.AssertCurrentThreadOwns();
134 mTimerImpl->SetIsInTimerThread(false);
135 mTimerImpl = nullptr;
138 // Called with the Monitor held, but not the TimerImpl's mutex
139 already_AddRefed<nsTimerImpl> Take() {
140 if (MOZ_LIKELY(mTimerImpl)) {
141 MOZ_ASSERT(mTimerImpl->IsInTimerThread());
142 mTimerImpl->SetIsInTimerThread(false);
144 return mTimerImpl.forget();
147 const TimeStamp& Timeout() const { return mTimeout; }
148 const TimeDuration& Delay() const { return mDelay; }
150 private:
151 // These values are simply cached from the timer. Keeping them here is good
152 // for cache usage and allows us to avoid worrying about locking conflicts
153 // with the timer.
154 TimeStamp mTimeout;
155 TimeDuration mDelay;
157 RefPtr<nsTimerImpl> mTimerImpl;
160 // Computes and returns the index in mTimers at which a new timer with the
161 // specified timeout should be inserted in order to maintain "sorted" order.
162 size_t ComputeTimerInsertionIndex(const TimeStamp& timeout) const
163 MOZ_REQUIRES(mMonitor);
165 // Computes and returns when we should next try to wake up in order to handle
166 // the triggering of the timers in mTimers. Currently this is very simple and
167 // we always just plan to wake up for the next timer in the list. In the
168 // future this will be more sophisticated.
169 TimeStamp ComputeWakeupTimeFromTimers() const MOZ_REQUIRES(mMonitor);
171 // Computes how late a timer can acceptably fire.
172 // timerDuration is the duration of the timer whose delay we are calculating.
173 // Longer timers can tolerate longer firing delays.
174 // minDelay is an amount by which any timer can be delayed.
175 // This function will never return a value smaller than minDelay (unless this
176 // conflicts with maxDelay). maxDelay is the upper limit on the amount by
177 // which we will ever delay any timer. Takes precedence over minDelay if there
178 // is a conflict. (Zero will effectively disable timer coalescing.)
179 TimeDuration ComputeAcceptableFiringDelay(TimeDuration timerDuration,
180 TimeDuration minDelay,
181 TimeDuration maxDelay) const;
183 #ifdef XP_WIN
184 UINT ComputeDesiredTimerPeriod() const;
185 #endif
187 #ifdef DEBUG
188 // Checks mTimers to see if any entries are out of order or any cached
189 // timeouts are incorrect and will assert if any inconsistency is found. Has
190 // no side effects other than asserting so has no use in non-DEBUG builds.
191 void VerifyTimerListConsistency() const MOZ_REQUIRES(mMonitor);
192 #endif
194 // mTimers is maintained in a "pseudo-sorted" order wrt the timeouts.
195 // Specifcally, mTimers is sorted according to the timeouts *if you ignore the
196 // canceled entries* (those whose mTimerImpl is nullptr). Notably this means
197 // that you cannot use a binary search on this list.
198 nsTArray<Entry> mTimers MOZ_GUARDED_BY(mMonitor);
200 // Set only at the start of the thread's Run():
201 uint32_t mAllowedEarlyFiringMicroseconds MOZ_GUARDED_BY(mMonitor);
203 ProfilerThreadId mProfilerThreadId MOZ_GUARDED_BY(mMonitor);
205 // Time at which we were intending to wake up the last time that we slept.
206 // Is "null" if we have never slept or if our last sleep was "forever".
207 TimeStamp mIntendedWakeupTime;
209 #if TIMER_THREAD_STATISTICS
210 static constexpr size_t sTimersFiredPerWakeupBucketCount = 16;
211 static inline constexpr std::array<size_t, sTimersFiredPerWakeupBucketCount>
212 sTimersFiredPerWakeupThresholds = {
213 0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 20, 30, 40, 50, 70, (size_t)(-1)};
215 mutable AutoTArray<size_t, sTimersFiredPerWakeupBucketCount>
216 mTimersFiredPerWakeup MOZ_GUARDED_BY(mMonitor) = {0, 0, 0, 0, 0, 0, 0, 0,
217 0, 0, 0, 0, 0, 0, 0, 0};
218 mutable AutoTArray<size_t, sTimersFiredPerWakeupBucketCount>
219 mTimersFiredPerUnnotifiedWakeup MOZ_GUARDED_BY(mMonitor) = {
220 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
221 mutable AutoTArray<size_t, sTimersFiredPerWakeupBucketCount>
222 mTimersFiredPerNotifiedWakeup MOZ_GUARDED_BY(mMonitor) = {
223 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
225 mutable size_t mTotalTimersAdded MOZ_GUARDED_BY(mMonitor) = 0;
226 mutable size_t mTotalTimersRemoved MOZ_GUARDED_BY(mMonitor) = 0;
227 mutable size_t mTotalTimersFiredNotified MOZ_GUARDED_BY(mMonitor) = 0;
228 mutable size_t mTotalTimersFiredUnnotified MOZ_GUARDED_BY(mMonitor) = 0;
230 mutable size_t mTotalWakeupCount MOZ_GUARDED_BY(mMonitor) = 0;
231 mutable size_t mTotalUnnotifiedWakeupCount MOZ_GUARDED_BY(mMonitor) = 0;
232 mutable size_t mTotalNotifiedWakeupCount MOZ_GUARDED_BY(mMonitor) = 0;
234 mutable double mTotalActualTimerFiringDelayNotified MOZ_GUARDED_BY(mMonitor) =
235 0.0;
236 mutable double mTotalActualTimerFiringDelayUnnotified
237 MOZ_GUARDED_BY(mMonitor) = 0.0;
239 mutable TimeStamp mFirstTimerAdded MOZ_GUARDED_BY(mMonitor);
241 mutable size_t mEarlyWakeups MOZ_GUARDED_BY(mMonitor) = 0;
242 mutable double mTotalEarlyWakeupTime MOZ_GUARDED_BY(mMonitor) = 0.0;
244 void PrintStatistics() const;
245 #endif
247 #endif /* TimerThread_h___ */