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/. */
6 
7 #ifndef TimerThread_h___
8 #define TimerThread_h___
9 
10 #include "nsIObserver.h"
11 #include "nsIRunnable.h"
12 #include "nsIThread.h"
13 
14 #include "nsTimerImpl.h"
15 #include "nsThreadUtils.h"
16 
17 #include "nsTArray.h"
18 
19 #include "mozilla/Atomics.h"
20 #include "mozilla/Attributes.h"
21 #include "mozilla/Monitor.h"
22 #include "mozilla/UniquePtr.h"
23 
24 #include <algorithm>
25 
26 namespace mozilla {
27 class TimeStamp;
28 }  // namespace mozilla
29 
30 class TimerThread final : public mozilla::Runnable, public nsIObserver {
31  public:
32   typedef mozilla::Monitor Monitor;
33   typedef mozilla::TimeStamp TimeStamp;
34   typedef mozilla::TimeDuration TimeDuration;
35 
36   TimerThread();
37   nsresult InitLocks();
38 
39   NS_DECL_ISUPPORTS_INHERITED
40   NS_DECL_NSIRUNNABLE
41   NS_DECL_NSIOBSERVER
42 
43   nsresult Shutdown();
44 
45   nsresult AddTimer(nsTimerImpl* aTimer);
46   nsresult RemoveTimer(nsTimerImpl* aTimer);
47   TimeStamp FindNextFireTimeForCurrentThread(TimeStamp aDefault,
48                                              uint32_t aSearchBound);
49 
50   void DoBeforeSleep();
51   void DoAfterSleep();
52 
IsOnTimerThread()53   bool IsOnTimerThread() const {
54     return mThread->SerialEventTarget()->IsOnCurrentThread();
55   }
56 
57   uint32_t AllowedEarlyFiringMicroseconds() const;
58 
59  private:
60   ~TimerThread();
61 
62   bool mInitialized;
63 
64   // These internal helper methods must be called while mMonitor is held.
65   // AddTimerInternal returns false if the insertion failed.
66   bool AddTimerInternal(nsTimerImpl* aTimer);
67   bool RemoveTimerInternal(nsTimerImpl* aTimer);
68   void RemoveLeadingCanceledTimersInternal();
69   void RemoveFirstTimerInternal();
70   nsresult Init();
71 
72   already_AddRefed<nsTimerImpl> PostTimerEvent(
73       already_AddRefed<nsTimerImpl> aTimerRef);
74 
75   nsCOMPtr<nsIThread> mThread;
76   Monitor mMonitor;
77 
78   bool mShutdown;
79   bool mWaiting;
80   bool mNotified;
81   bool mSleeping;
82 
83   class Entry final : public nsTimerImplHolder {
84     const TimeStamp mTimeout;
85 
86    public:
Entry(const TimeStamp & aMinTimeout,const TimeStamp & aTimeout,nsTimerImpl * aTimerImpl)87     Entry(const TimeStamp& aMinTimeout, const TimeStamp& aTimeout,
88           nsTimerImpl* aTimerImpl)
89         : nsTimerImplHolder(aTimerImpl),
90           mTimeout(std::max(aMinTimeout, aTimeout)) {}
91 
Value()92     nsTimerImpl* Value() const { return mTimerImpl; }
93 
Take()94     already_AddRefed<nsTimerImpl> Take() {
95       if (mTimerImpl) {
96         mTimerImpl->SetHolder(nullptr);
97       }
98       return mTimerImpl.forget();
99     }
100 
UniquePtrLessThan(mozilla::UniquePtr<Entry> & aLeft,mozilla::UniquePtr<Entry> & aRight)101     static bool UniquePtrLessThan(mozilla::UniquePtr<Entry>& aLeft,
102                                   mozilla::UniquePtr<Entry>& aRight) {
103       // This is reversed because std::push_heap() sorts the "largest" to
104       // the front of the heap.  We want that to be the earliest timer.
105       return aRight->mTimeout < aLeft->mTimeout;
106     }
107 
Timeout()108     TimeStamp Timeout() const { return mTimeout; }
109   };
110 
111   nsTArray<mozilla::UniquePtr<Entry>> mTimers;
112   uint32_t mAllowedEarlyFiringMicroseconds;
113 };
114 
115 #endif /* TimerThread_h___ */
116