Bug 1854550 - pt 12. Allow inlining between mozjemalloc and PHC r=glandium
[gecko.git] / xpcom / threads / nsTimerImpl.h
blob49f1fd00d53f7a629b27cb12d1a08d6efba82824
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 nsTimerImpl_h___
8 #define nsTimerImpl_h___
10 #include "nsITimer.h"
11 #include "nsIEventTarget.h"
12 #include "nsIObserver.h"
14 #include "nsCOMPtr.h"
16 #include "mozilla/Attributes.h"
17 #include "mozilla/Mutex.h"
18 #include "mozilla/StaticMutex.h"
19 #include "mozilla/TimeStamp.h"
20 #include "mozilla/Variant.h"
21 #include "mozilla/Logging.h"
23 extern mozilla::LogModule* GetTimerLog();
25 #define NS_TIMER_CID \
26 { /* 5ff24248-1dd2-11b2-8427-fbab44f29bc8 */ \
27 0x5ff24248, 0x1dd2, 0x11b2, { \
28 0x84, 0x27, 0xfb, 0xab, 0x44, 0xf2, 0x9b, 0xc8 \
29 } \
32 class nsIObserver;
34 namespace mozilla {
35 class LogModule;
38 // TimerThread, nsTimerEvent, and nsTimer have references to these. nsTimer has
39 // a separate lifecycle so we can Cancel() the underlying timer when the user of
40 // the nsTimer has let go of its last reference.
41 class nsTimerImpl {
42 ~nsTimerImpl() {
43 MOZ_ASSERT(!mIsInTimerThread);
45 // The nsITimer interface requires that its users keep a reference to the
46 // timers they use while those timers are initialized but have not yet
47 // fired. If this assert ever fails, it is a bug in the code that created
48 // and used the timer.
50 // Further, note that this should never fail even with a misbehaving user,
51 // because nsTimer::Release checks for a refcount of 1 with an armed timer
52 // (a timer whose only reference is from the timer thread) and when it hits
53 // this will remove the timer from the timer thread and thus destroy the
54 // last reference, preventing this situation from occurring.
55 MOZ_ASSERT(
56 mCallback.is<UnknownCallback>() || mEventTarget->IsOnCurrentThread(),
57 "Must not release mCallback off-target without canceling");
60 public:
61 typedef mozilla::TimeStamp TimeStamp;
63 nsTimerImpl(nsITimer* aTimer, nsIEventTarget* aTarget);
64 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsTimerImpl)
65 NS_DECL_NON_VIRTUAL_NSITIMER
67 static nsresult Startup();
68 static void Shutdown();
70 void SetDelayInternal(uint32_t aDelay, TimeStamp aBase = TimeStamp::Now());
71 void CancelImpl(bool aClearITimer);
73 void Fire(int32_t aGeneration);
75 int32_t GetGeneration() { return mGeneration; }
77 struct UnknownCallback {};
79 using InterfaceCallback = nsCOMPtr<nsITimerCallback>;
81 using ObserverCallback = nsCOMPtr<nsIObserver>;
83 /// A raw function pointer and its closed-over state, along with its name for
84 /// logging purposes.
85 struct FuncCallback {
86 nsTimerCallbackFunc mFunc;
87 void* mClosure;
88 const char* mName;
91 /// A callback defined by an owned closure and its name for logging purposes.
92 struct ClosureCallback {
93 std::function<void(nsITimer*)> mFunc;
94 const char* mName;
97 using Callback =
98 mozilla::Variant<UnknownCallback, InterfaceCallback, ObserverCallback,
99 FuncCallback, ClosureCallback>;
101 nsresult InitCommon(const mozilla::TimeDuration& aDelay, uint32_t aType,
102 Callback&& newCallback,
103 const mozilla::MutexAutoLock& aProofOfLock)
104 MOZ_REQUIRES(mMutex);
106 Callback& GetCallback() MOZ_REQUIRES(mMutex) {
107 mMutex.AssertCurrentThreadOwns();
108 return mCallback;
111 bool IsRepeating() const {
112 static_assert(nsITimer::TYPE_ONE_SHOT < nsITimer::TYPE_REPEATING_SLACK,
113 "invalid ordering of timer types!");
114 static_assert(
115 nsITimer::TYPE_REPEATING_SLACK < nsITimer::TYPE_REPEATING_PRECISE,
116 "invalid ordering of timer types!");
117 static_assert(nsITimer::TYPE_REPEATING_PRECISE <
118 nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP,
119 "invalid ordering of timer types!");
120 return mType >= nsITimer::TYPE_REPEATING_SLACK &&
121 mType < nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY;
124 bool IsLowPriority() const {
125 return mType == nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY ||
126 mType == nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY;
129 bool IsSlack() const {
130 return mType == nsITimer::TYPE_REPEATING_SLACK ||
131 mType == nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY;
134 void GetName(nsACString& aName, const mozilla::MutexAutoLock& aProofOfLock)
135 MOZ_REQUIRES(mMutex);
137 bool IsInTimerThread() const { return mIsInTimerThread; }
138 void SetIsInTimerThread(bool aIsInTimerThread) {
139 mIsInTimerThread = aIsInTimerThread;
142 nsCOMPtr<nsIEventTarget> mEventTarget;
144 void LogFiring(const Callback& aCallback, uint8_t aType, uint32_t aDelay);
146 nsresult InitWithClosureCallback(std::function<void(nsITimer*)>&& aCallback,
147 const mozilla::TimeDuration& aDelay,
148 uint32_t aType, const char* aNameString);
150 // Is this timer currently referenced from a TimerThread::Entry?
151 // Note: It is cleared before the Entry is destroyed. Take() also sets it to
152 // false, to indicate it's no longer in the TimerThread's list. This Take()
153 // call is NOT made under the nsTimerImpl's mutex (all other
154 // SetIsInTimerThread calls are under the mutex). However, ALL accesses to
155 // mIsInTimerThread are under the TimerThread's Monitor lock, so consistency
156 // is guaranteed by that.
157 bool mIsInTimerThread;
159 // These members are set by the initiating thread, when the timer's type is
160 // changed and during the period where it fires on that thread.
161 uint8_t mType;
163 // The generation number of this timer, re-generated each time the timer is
164 // initialized so one-shot timers can be canceled and re-initialized by the
165 // arming thread without any bad race conditions.
166 // Updated only after this timer has been removed from the timer thread.
167 int32_t mGeneration;
169 mozilla::TimeDuration mDelay MOZ_GUARDED_BY(mMutex);
170 // Never updated while in the TimerThread's timer list. Only updated
171 // before adding to that list or during nsTimerImpl::Fire(), when it has
172 // been removed from the TimerThread's list. TimerThread can access
173 // mTimeout of any timer in the list safely
174 mozilla::TimeStamp mTimeout;
176 RefPtr<nsITimer> mITimer MOZ_GUARDED_BY(mMutex);
177 mozilla::Mutex mMutex;
178 Callback mCallback MOZ_GUARDED_BY(mMutex);
179 // Counter because in rare cases we can Fire reentrantly
180 unsigned int mFiring MOZ_GUARDED_BY(mMutex);
182 static mozilla::StaticMutex sDeltaMutex;
183 static double sDeltaSum MOZ_GUARDED_BY(sDeltaMutex);
184 static double sDeltaSumSquared MOZ_GUARDED_BY(sDeltaMutex);
185 static double sDeltaNum MOZ_GUARDED_BY(sDeltaMutex);
188 class nsTimer final : public nsITimer {
189 explicit nsTimer(nsIEventTarget* aTarget)
190 : mImpl(new nsTimerImpl(this, aTarget)) {}
192 virtual ~nsTimer();
194 public:
195 friend class TimerThread;
196 friend class nsTimerEvent;
198 NS_DECL_THREADSAFE_ISUPPORTS
199 NS_FORWARD_SAFE_NSITIMER(mImpl);
201 // NOTE: This constructor is not exposed on `nsITimer` as NS_FORWARD_SAFE_
202 // does not support forwarding rvalue references.
203 nsresult InitWithClosureCallback(std::function<void(nsITimer*)>&& aCallback,
204 const mozilla::TimeDuration& aDelay,
205 uint32_t aType, const char* aNameString) {
206 return mImpl ? mImpl->InitWithClosureCallback(std::move(aCallback), aDelay,
207 aType, aNameString)
208 : NS_ERROR_NULL_POINTER;
211 // Create a timer targeting the given target. nullptr indicates that the
212 // current thread should be used as the timer's target.
213 static RefPtr<nsTimer> WithEventTarget(nsIEventTarget* aTarget);
215 static nsresult XPCOMConstructor(REFNSIID aIID, void** aResult);
217 private:
218 // nsTimerImpl holds a strong ref to us. When our refcount goes to 1, we will
219 // null this to break the cycle.
220 RefPtr<nsTimerImpl> mImpl;
223 class nsTimerManager final : public nsITimerManager {
224 public:
225 NS_DECL_ISUPPORTS
226 NS_DECL_NSITIMERMANAGER
227 private:
228 ~nsTimerManager() = default;
231 #endif /* nsTimerImpl_h___ */