summaryrefslogtreecommitdiffstats
path: root/xpcom/threads/nsTimerImpl.h
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/threads/nsTimerImpl.h')
-rw-r--r--xpcom/threads/nsTimerImpl.h207
1 files changed, 207 insertions, 0 deletions
diff --git a/xpcom/threads/nsTimerImpl.h b/xpcom/threads/nsTimerImpl.h
new file mode 100644
index 000000000..5c731fbb4
--- /dev/null
+++ b/xpcom/threads/nsTimerImpl.h
@@ -0,0 +1,207 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsTimerImpl_h___
+#define nsTimerImpl_h___
+
+#include "nsITimer.h"
+#include "nsIEventTarget.h"
+#include "nsIObserver.h"
+
+#include "nsCOMPtr.h"
+
+#include "mozilla/Attributes.h"
+#include "mozilla/Logging.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/Variant.h"
+
+#ifdef MOZ_TASK_TRACER
+#include "TracedTaskCommon.h"
+#endif
+
+extern mozilla::LogModule* GetTimerLog();
+
+#define NS_TIMER_CID \
+{ /* 5ff24248-1dd2-11b2-8427-fbab44f29bc8 */ \
+ 0x5ff24248, \
+ 0x1dd2, \
+ 0x11b2, \
+ {0x84, 0x27, 0xfb, 0xab, 0x44, 0xf2, 0x9b, 0xc8} \
+}
+
+// TimerThread, nsTimerEvent, and nsTimer have references to these. nsTimer has
+// a separate lifecycle so we can Cancel() the underlying timer when the user of
+// the nsTimer has let go of its last reference.
+class nsTimerImpl
+{
+ ~nsTimerImpl() {}
+public:
+ typedef mozilla::TimeStamp TimeStamp;
+
+ explicit nsTimerImpl(nsITimer* aTimer);
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsTimerImpl)
+ NS_DECL_NON_VIRTUAL_NSITIMER
+
+ static nsresult Startup();
+ static void Shutdown();
+
+ void Fire(int32_t aGeneration);
+
+#ifdef MOZ_TASK_TRACER
+ void GetTLSTraceInfo();
+ mozilla::tasktracer::TracedTaskCommon GetTracedTask();
+#endif
+
+ int32_t GetGeneration()
+ {
+ return mGeneration;
+ }
+
+ nsresult InitCommon(uint32_t aDelay, uint32_t aType);
+
+ struct Callback {
+ Callback() :
+ mType(Type::Unknown),
+ mName(Nothing),
+ mClosure(nullptr)
+ {
+ mCallback.c = nullptr;
+ }
+
+ Callback(const Callback& other) = delete;
+ Callback& operator=(const Callback& other) = delete;
+
+ ~Callback()
+ {
+ if (mType == Type::Interface) {
+ NS_RELEASE(mCallback.i);
+ } else if (mType == Type::Observer) {
+ NS_RELEASE(mCallback.o);
+ }
+ }
+
+ void swap(Callback& other)
+ {
+ std::swap(mType, other.mType);
+ std::swap(mCallback, other.mCallback);
+ std::swap(mName, other.mName);
+ std::swap(mClosure, other.mClosure);
+ }
+
+ enum class Type : uint8_t {
+ Unknown = 0,
+ Interface = 1,
+ Function = 2,
+ Observer = 3,
+ };
+ Type mType;
+
+ union CallbackUnion
+ {
+ nsTimerCallbackFunc c;
+ // These refcounted references are managed manually, as they are in a union
+ nsITimerCallback* MOZ_OWNING_REF i;
+ nsIObserver* MOZ_OWNING_REF o;
+ } mCallback;
+
+ // |Name| is a tagged union type representing one of (a) nothing, (b) a
+ // string, or (c) a function. mozilla::Variant doesn't naturally handle the
+ // "nothing" case, so we define a dummy type and value (which is unused and
+ // so the exact value doesn't matter) for it.
+ typedef const int NameNothing;
+ typedef const char* NameString;
+ typedef nsTimerNameCallbackFunc NameFunc;
+ typedef mozilla::Variant<NameNothing, NameString, NameFunc> Name;
+ static const NameNothing Nothing;
+ Name mName;
+
+ void* mClosure;
+ };
+
+ Callback& GetCallback()
+ {
+ mMutex.AssertCurrentThreadOwns();
+ if (mCallback.mType == Callback::Type::Unknown) {
+ return mCallbackDuringFire;
+ }
+
+ return mCallback;
+ }
+
+ bool IsRepeating() const
+ {
+ static_assert(nsITimer::TYPE_ONE_SHOT < nsITimer::TYPE_REPEATING_SLACK,
+ "invalid ordering of timer types!");
+ static_assert(
+ nsITimer::TYPE_REPEATING_SLACK < nsITimer::TYPE_REPEATING_PRECISE,
+ "invalid ordering of timer types!");
+ static_assert(
+ nsITimer::TYPE_REPEATING_PRECISE <
+ nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP,
+ "invalid ordering of timer types!");
+ return mType >= nsITimer::TYPE_REPEATING_SLACK;
+ }
+
+ nsCOMPtr<nsIEventTarget> mEventTarget;
+
+ void LogFiring(const Callback& aCallback, uint8_t aType, uint32_t aDelay);
+
+ nsresult InitWithFuncCallbackCommon(nsTimerCallbackFunc aFunc,
+ void* aClosure,
+ uint32_t aDelay,
+ uint32_t aType,
+ Callback::Name aName);
+
+ // These members are set by the initiating thread, when the timer's type is
+ // changed and during the period where it fires on that thread.
+ uint8_t mType;
+
+ // The generation number of this timer, re-generated each time the timer is
+ // initialized so one-shot timers can be canceled and re-initialized by the
+ // arming thread without any bad race conditions.
+ // Updated only after this timer has been removed from the timer thread.
+ int32_t mGeneration;
+
+ uint32_t mDelay;
+ // Updated only after this timer has been removed from the timer thread.
+ TimeStamp mTimeout;
+
+#ifdef MOZ_TASK_TRACER
+ mozilla::tasktracer::TracedTaskCommon mTracedTask;
+#endif
+
+ static double sDeltaSum;
+ static double sDeltaSumSquared;
+ static double sDeltaNum;
+ const RefPtr<nsITimer> mITimer;
+ mozilla::Mutex mMutex;
+ Callback mCallback;
+ Callback mCallbackDuringFire;
+};
+
+class nsTimer final : public nsITimer
+{
+ virtual ~nsTimer();
+public:
+ nsTimer() : mImpl(new nsTimerImpl(this)) {}
+
+ friend class TimerThread;
+ friend class nsTimerEvent;
+ friend struct TimerAdditionComparator;
+
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_FORWARD_SAFE_NSITIMER(mImpl);
+
+ virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
+
+private:
+ // nsTimerImpl holds a strong ref to us. When our refcount goes to 1, we will
+ // null this to break the cycle.
+ RefPtr<nsTimerImpl> mImpl;
+};
+
+#endif /* nsTimerImpl_h___ */