Bug 1700051: part 49) Add some documentation to `Selection::GetRangesForInterval...
[gecko.git] / xpcom / threads / nsTimerImpl.h
blob61d4d6d0b2afcc0e647cc459b7b8ead337c876c5
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/TimeStamp.h"
19 #include "mozilla/Variant.h"
20 #include "mozilla/Logging.h"
22 #ifdef MOZ_TASK_TRACER
23 # include "TracedTaskCommon.h"
24 #endif
26 extern mozilla::LogModule* GetTimerLog();
28 #define NS_TIMER_CID \
29 { /* 5ff24248-1dd2-11b2-8427-fbab44f29bc8 */ \
30 0x5ff24248, 0x1dd2, 0x11b2, { \
31 0x84, 0x27, 0xfb, 0xab, 0x44, 0xf2, 0x9b, 0xc8 \
32 } \
35 class nsIObserver;
36 class nsTimerImplHolder;
38 namespace mozilla {
39 class LogModule;
42 // TimerThread, nsTimerEvent, and nsTimer have references to these. nsTimer has
43 // a separate lifecycle so we can Cancel() the underlying timer when the user of
44 // the nsTimer has let go of its last reference.
45 class nsTimerImpl {
46 ~nsTimerImpl() { MOZ_ASSERT(!mHolder); }
48 public:
49 typedef mozilla::TimeStamp TimeStamp;
51 nsTimerImpl(nsITimer* aTimer, nsIEventTarget* aTarget);
52 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsTimerImpl)
53 NS_DECL_NON_VIRTUAL_NSITIMER
55 static nsresult Startup();
56 static void Shutdown();
58 void SetDelayInternal(uint32_t aDelay, TimeStamp aBase = TimeStamp::Now());
59 void CancelImpl(bool aClearITimer);
61 void Fire(int32_t aGeneration);
63 #ifdef MOZ_TASK_TRACER
64 void GetTLSTraceInfo();
65 mozilla::tasktracer::TracedTaskCommon GetTracedTask();
66 #endif
68 int32_t GetGeneration() { return mGeneration; }
70 struct Callback {
71 Callback() : mType(Type::Unknown), mName(Nothing), mClosure(nullptr) {
72 mCallback.c = nullptr;
75 Callback(const Callback& other) : Callback() { *this = other; }
77 enum class Type : uint8_t {
78 Unknown = 0,
79 Interface = 1,
80 Function = 2,
81 Observer = 3,
84 Callback& operator=(const Callback& other) {
85 if (this != &other) {
86 clear();
87 mType = other.mType;
88 switch (mType) {
89 case Type::Unknown:
90 break;
91 case Type::Interface:
92 mCallback.i = other.mCallback.i;
93 NS_ADDREF(mCallback.i);
94 break;
95 case Type::Function:
96 mCallback.c = other.mCallback.c;
97 break;
98 case Type::Observer:
99 mCallback.o = other.mCallback.o;
100 NS_ADDREF(mCallback.o);
101 break;
103 mName = other.mName;
104 mClosure = other.mClosure;
106 return *this;
109 ~Callback() { clear(); }
111 void clear() {
112 if (mType == Type::Interface) {
113 NS_RELEASE(mCallback.i);
114 } else if (mType == Type::Observer) {
115 NS_RELEASE(mCallback.o);
117 mType = Type::Unknown;
120 void swap(Callback& other) {
121 std::swap(mType, other.mType);
122 std::swap(mCallback, other.mCallback);
123 std::swap(mName, other.mName);
124 std::swap(mClosure, other.mClosure);
127 Type mType;
129 union CallbackUnion {
130 nsTimerCallbackFunc c;
131 // These refcounted references are managed manually, as they are in a
132 // union
133 nsITimerCallback* MOZ_OWNING_REF i;
134 nsIObserver* MOZ_OWNING_REF o;
135 } mCallback;
137 // |Name| is a tagged union type representing one of (a) nothing, (b) a
138 // string, or (c) a function. mozilla::Variant doesn't naturally handle the
139 // "nothing" case, so we define a dummy type and value (which is unused and
140 // so the exact value doesn't matter) for it.
141 typedef const int NameNothing;
142 typedef const char* NameString;
143 typedef nsTimerNameCallbackFunc NameFunc;
144 typedef mozilla::Variant<NameNothing, NameString, NameFunc> Name;
145 static const NameNothing Nothing;
146 Name mName;
148 void* mClosure;
151 nsresult InitCommon(uint32_t aDelayMS, uint32_t aType,
152 Callback&& newCallback);
154 nsresult InitCommon(const mozilla::TimeDuration& aDelay, uint32_t aType,
155 Callback&& newCallback);
157 Callback& GetCallback() {
158 mMutex.AssertCurrentThreadOwns();
159 return mCallback;
162 bool IsRepeating() const {
163 static_assert(nsITimer::TYPE_ONE_SHOT < nsITimer::TYPE_REPEATING_SLACK,
164 "invalid ordering of timer types!");
165 static_assert(
166 nsITimer::TYPE_REPEATING_SLACK < nsITimer::TYPE_REPEATING_PRECISE,
167 "invalid ordering of timer types!");
168 static_assert(nsITimer::TYPE_REPEATING_PRECISE <
169 nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP,
170 "invalid ordering of timer types!");
171 return mType >= nsITimer::TYPE_REPEATING_SLACK &&
172 mType < nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY;
175 bool IsLowPriority() const {
176 return mType == nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY ||
177 mType == nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY;
180 bool IsSlack() const {
181 return mType == nsITimer::TYPE_REPEATING_SLACK ||
182 mType == nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY;
185 void GetName(nsACString& aName);
187 void SetHolder(nsTimerImplHolder* aHolder);
189 nsCOMPtr<nsIEventTarget> mEventTarget;
191 void LogFiring(const Callback& aCallback, uint8_t aType, uint32_t aDelay);
193 nsresult InitWithFuncCallbackCommon(nsTimerCallbackFunc aFunc, void* aClosure,
194 uint32_t aDelay, uint32_t aType,
195 const Callback::Name& aName);
197 // This weak reference must be cleared by the nsTimerImplHolder by calling
198 // SetHolder(nullptr) before the holder is destroyed.
199 nsTimerImplHolder* mHolder;
201 // These members are set by the initiating thread, when the timer's type is
202 // changed and during the period where it fires on that thread.
203 uint8_t mType;
205 // The generation number of this timer, re-generated each time the timer is
206 // initialized so one-shot timers can be canceled and re-initialized by the
207 // arming thread without any bad race conditions.
208 // Updated only after this timer has been removed from the timer thread.
209 int32_t mGeneration;
211 mozilla::TimeDuration mDelay;
212 // Updated only after this timer has been removed from the timer thread.
213 mozilla::TimeStamp mTimeout;
215 #ifdef MOZ_TASK_TRACER
216 mozilla::tasktracer::TracedTaskCommon mTracedTask;
217 #endif
219 static double sDeltaSum;
220 static double sDeltaSumSquared;
221 static double sDeltaNum;
222 RefPtr<nsITimer> mITimer;
223 mozilla::Mutex mMutex;
224 Callback mCallback;
225 // Counter because in rare cases we can Fire reentrantly
226 unsigned int mFiring;
229 class nsTimer final : public nsITimer {
230 explicit nsTimer(nsIEventTarget* aTarget)
231 : mImpl(new nsTimerImpl(this, aTarget)) {}
233 virtual ~nsTimer();
235 public:
236 friend class TimerThread;
237 friend class nsTimerEvent;
239 NS_DECL_THREADSAFE_ISUPPORTS
240 NS_FORWARD_SAFE_NSITIMER(mImpl);
242 virtual size_t SizeOfIncludingThis(
243 mozilla::MallocSizeOf aMallocSizeOf) const override;
245 // Create a timer targeting the given target. nullptr indicates that the
246 // current thread should be used as the timer's target.
247 static RefPtr<nsTimer> WithEventTarget(nsIEventTarget* aTarget);
249 static nsresult XPCOMConstructor(nsISupports* aOuter, REFNSIID aIID,
250 void** aResult);
252 private:
253 // nsTimerImpl holds a strong ref to us. When our refcount goes to 1, we will
254 // null this to break the cycle.
255 RefPtr<nsTimerImpl> mImpl;
258 // A class that holds on to an nsTimerImpl. This lets the nsTimerImpl object
259 // directly instruct its holder to forget the timer, avoiding list lookups.
260 class nsTimerImplHolder {
261 public:
262 explicit nsTimerImplHolder(nsTimerImpl* aTimerImpl) : mTimerImpl(aTimerImpl) {
263 if (mTimerImpl) {
264 mTimerImpl->SetHolder(this);
268 ~nsTimerImplHolder() {
269 if (mTimerImpl) {
270 mTimerImpl->SetHolder(nullptr);
274 void Forget(nsTimerImpl* aTimerImpl) {
275 if (MOZ_UNLIKELY(!mTimerImpl)) {
276 return;
278 MOZ_ASSERT(aTimerImpl == mTimerImpl);
279 mTimerImpl->SetHolder(nullptr);
280 mTimerImpl = nullptr;
283 protected:
284 RefPtr<nsTimerImpl> mTimerImpl;
287 #endif /* nsTimerImpl_h___ */