michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsTimerImpl_h___ michael@0: #define nsTimerImpl_h___ michael@0: michael@0: //#define FORCE_PR_LOG /* Allow logging in the release build */ michael@0: michael@0: #include "nsITimer.h" michael@0: #include "nsIEventTarget.h" michael@0: #include "nsIObserver.h" michael@0: michael@0: #include "nsCOMPtr.h" michael@0: michael@0: #include "prlog.h" michael@0: #include "mozilla/TimeStamp.h" michael@0: #include "mozilla/Attributes.h" michael@0: michael@0: #ifdef MOZ_TASK_TRACER michael@0: #include "TracedTaskCommon.h" michael@0: #endif michael@0: michael@0: #if defined(PR_LOGGING) michael@0: extern PRLogModuleInfo *GetTimerLog(); michael@0: #define DEBUG_TIMERS 1 michael@0: #else michael@0: #undef DEBUG_TIMERS michael@0: #endif michael@0: michael@0: #define NS_TIMER_CID \ michael@0: { /* 5ff24248-1dd2-11b2-8427-fbab44f29bc8 */ \ michael@0: 0x5ff24248, \ michael@0: 0x1dd2, \ michael@0: 0x11b2, \ michael@0: {0x84, 0x27, 0xfb, 0xab, 0x44, 0xf2, 0x9b, 0xc8} \ michael@0: } michael@0: michael@0: enum { michael@0: CALLBACK_TYPE_UNKNOWN = 0, michael@0: CALLBACK_TYPE_INTERFACE = 1, michael@0: CALLBACK_TYPE_FUNC = 2, michael@0: CALLBACK_TYPE_OBSERVER = 3 michael@0: }; michael@0: michael@0: class nsTimerImpl MOZ_FINAL : public nsITimer michael@0: { michael@0: public: michael@0: typedef mozilla::TimeStamp TimeStamp; michael@0: michael@0: nsTimerImpl(); michael@0: michael@0: static NS_HIDDEN_(nsresult) Startup(); michael@0: static NS_HIDDEN_(void) Shutdown(); michael@0: michael@0: friend class TimerThread; michael@0: friend struct TimerAdditionComparator; michael@0: michael@0: void Fire(); michael@0: // If a failure is encountered, the reference is returned to the caller michael@0: static already_AddRefed PostTimerEvent( michael@0: already_AddRefed aTimerRef); michael@0: void SetDelayInternal(uint32_t aDelay); michael@0: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSITIMER michael@0: michael@0: int32_t GetGeneration() { return mGeneration; } michael@0: michael@0: #ifdef MOZ_TASK_TRACER michael@0: void DispatchTracedTask() michael@0: { michael@0: mTracedTask = mozilla::tasktracer::CreateFakeTracedTask(*(int**)(this)); michael@0: } michael@0: #endif michael@0: michael@0: private: michael@0: ~nsTimerImpl(); michael@0: nsresult InitCommon(uint32_t aType, uint32_t aDelay); michael@0: michael@0: void ReleaseCallback() michael@0: { michael@0: // if we're the last owner of the callback object, make michael@0: // sure that we don't recurse into ReleaseCallback in case michael@0: // the callback's destructor calls Cancel() or similar. michael@0: uint8_t cbType = mCallbackType; michael@0: mCallbackType = CALLBACK_TYPE_UNKNOWN; michael@0: michael@0: if (cbType == CALLBACK_TYPE_INTERFACE) michael@0: NS_RELEASE(mCallback.i); michael@0: else if (cbType == CALLBACK_TYPE_OBSERVER) michael@0: NS_RELEASE(mCallback.o); michael@0: } michael@0: michael@0: bool IsRepeating() const { michael@0: PR_STATIC_ASSERT(TYPE_ONE_SHOT < TYPE_REPEATING_SLACK); michael@0: PR_STATIC_ASSERT(TYPE_REPEATING_SLACK < TYPE_REPEATING_PRECISE); michael@0: PR_STATIC_ASSERT(TYPE_REPEATING_PRECISE < TYPE_REPEATING_PRECISE_CAN_SKIP); michael@0: return mType >= TYPE_REPEATING_SLACK; michael@0: } michael@0: michael@0: bool IsRepeatingPrecisely() const { michael@0: return mType >= TYPE_REPEATING_PRECISE; michael@0: } michael@0: michael@0: nsCOMPtr mEventTarget; michael@0: michael@0: void * mClosure; michael@0: michael@0: union CallbackUnion { michael@0: nsTimerCallbackFunc c; michael@0: nsITimerCallback * i; michael@0: nsIObserver * o; michael@0: } mCallback; michael@0: michael@0: // Some callers expect to be able to access the callback while the michael@0: // timer is firing. michael@0: nsCOMPtr mTimerCallbackWhileFiring; michael@0: michael@0: // These members are set by Init (called from NS_NewTimer) and never reset. michael@0: uint8_t mCallbackType; michael@0: michael@0: // These members are set by the initiating thread, when the timer's type is michael@0: // changed and during the period where it fires on that thread. michael@0: uint8_t mType; michael@0: bool mFiring; michael@0: michael@0: michael@0: // Use a bool (int) here to isolate loads and stores of these two members michael@0: // done on various threads under the protection of TimerThread::mLock, from michael@0: // loads and stores done on the initiating/type-changing/timer-firing thread michael@0: // to the above uint8_t/bool members. michael@0: bool mArmed; michael@0: bool mCanceled; michael@0: michael@0: // The generation number of this timer, re-generated each time the timer is michael@0: // initialized so one-shot timers can be canceled and re-initialized by the michael@0: // arming thread without any bad race conditions. michael@0: int32_t mGeneration; michael@0: michael@0: uint32_t mDelay; michael@0: TimeStamp mTimeout; michael@0: michael@0: #ifdef MOZ_TASK_TRACER michael@0: nsAutoPtr mTracedTask; michael@0: #endif michael@0: michael@0: #ifdef DEBUG_TIMERS michael@0: TimeStamp mStart, mStart2; michael@0: static double sDeltaSum; michael@0: static double sDeltaSumSquared; michael@0: static double sDeltaNum; michael@0: #endif michael@0: michael@0: }; michael@0: michael@0: #endif /* nsTimerImpl_h___ */