Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set ts=2 et sw=2 tw=80: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #ifndef mozilla_lazyidlethread_h__ |
michael@0 | 8 | #define mozilla_lazyidlethread_h__ |
michael@0 | 9 | |
michael@0 | 10 | #ifndef MOZILLA_INTERNAL_API |
michael@0 | 11 | #error "This header is only usable from within libxul (MOZILLA_INTERNAL_API)." |
michael@0 | 12 | #endif |
michael@0 | 13 | |
michael@0 | 14 | #include "nsIObserver.h" |
michael@0 | 15 | #include "nsIThreadInternal.h" |
michael@0 | 16 | #include "nsITimer.h" |
michael@0 | 17 | |
michael@0 | 18 | #include "mozilla/Mutex.h" |
michael@0 | 19 | #include "nsCOMPtr.h" |
michael@0 | 20 | #include "nsTArray.h" |
michael@0 | 21 | #include "nsString.h" |
michael@0 | 22 | #include "mozilla/Attributes.h" |
michael@0 | 23 | |
michael@0 | 24 | #define IDLE_THREAD_TOPIC "thread-shutting-down" |
michael@0 | 25 | |
michael@0 | 26 | namespace mozilla { |
michael@0 | 27 | |
michael@0 | 28 | /** |
michael@0 | 29 | * This class provides a basic event target that creates its thread lazily and |
michael@0 | 30 | * destroys its thread after a period of inactivity. It may be created on any |
michael@0 | 31 | * thread but it may only be used from the thread on which it is created. If it |
michael@0 | 32 | * is created on the main thread then it will automatically join its thread on |
michael@0 | 33 | * XPCOM shutdown using the Observer Service. |
michael@0 | 34 | */ |
michael@0 | 35 | class LazyIdleThread MOZ_FINAL : public nsIThread, |
michael@0 | 36 | public nsITimerCallback, |
michael@0 | 37 | public nsIThreadObserver, |
michael@0 | 38 | public nsIObserver |
michael@0 | 39 | { |
michael@0 | 40 | public: |
michael@0 | 41 | NS_DECL_THREADSAFE_ISUPPORTS |
michael@0 | 42 | NS_DECL_NSIEVENTTARGET |
michael@0 | 43 | NS_DECL_NSITHREAD |
michael@0 | 44 | NS_DECL_NSITIMERCALLBACK |
michael@0 | 45 | NS_DECL_NSITHREADOBSERVER |
michael@0 | 46 | NS_DECL_NSIOBSERVER |
michael@0 | 47 | |
michael@0 | 48 | enum ShutdownMethod { |
michael@0 | 49 | AutomaticShutdown = 0, |
michael@0 | 50 | ManualShutdown |
michael@0 | 51 | }; |
michael@0 | 52 | |
michael@0 | 53 | /** |
michael@0 | 54 | * Create a new LazyIdleThread that will destroy its thread after the given |
michael@0 | 55 | * number of milliseconds. |
michael@0 | 56 | */ |
michael@0 | 57 | LazyIdleThread(uint32_t aIdleTimeoutMS, |
michael@0 | 58 | const nsCSubstring& aName, |
michael@0 | 59 | ShutdownMethod aShutdownMethod = AutomaticShutdown, |
michael@0 | 60 | nsIObserver* aIdleObserver = nullptr); |
michael@0 | 61 | |
michael@0 | 62 | /** |
michael@0 | 63 | * Add an observer that will be notified when the thread is idle and about to |
michael@0 | 64 | * be shut down. The aSubject argument can be QueryInterface'd to an nsIThread |
michael@0 | 65 | * that can be used to post cleanup events. The aTopic argument will be |
michael@0 | 66 | * IDLE_THREAD_TOPIC, and aData will be null. The LazyIdleThread does not add |
michael@0 | 67 | * a reference to the observer to avoid circular references as it is assumed |
michael@0 | 68 | * to be the owner. It is the caller's responsibility to clear this observer |
michael@0 | 69 | * if the pointer becomes invalid. |
michael@0 | 70 | */ |
michael@0 | 71 | void SetWeakIdleObserver(nsIObserver* aObserver); |
michael@0 | 72 | |
michael@0 | 73 | /** |
michael@0 | 74 | * Disable the idle timeout for this thread. No effect if the timeout is |
michael@0 | 75 | * already disabled. |
michael@0 | 76 | */ |
michael@0 | 77 | void DisableIdleTimeout(); |
michael@0 | 78 | |
michael@0 | 79 | /** |
michael@0 | 80 | * Enable the idle timeout. No effect if the timeout is already enabled. |
michael@0 | 81 | */ |
michael@0 | 82 | void EnableIdleTimeout(); |
michael@0 | 83 | |
michael@0 | 84 | private: |
michael@0 | 85 | /** |
michael@0 | 86 | * Calls Shutdown(). |
michael@0 | 87 | */ |
michael@0 | 88 | ~LazyIdleThread(); |
michael@0 | 89 | |
michael@0 | 90 | /** |
michael@0 | 91 | * Called just before dispatching to mThread. |
michael@0 | 92 | */ |
michael@0 | 93 | void PreDispatch(); |
michael@0 | 94 | |
michael@0 | 95 | /** |
michael@0 | 96 | * Makes sure a valid thread lives in mThread. |
michael@0 | 97 | */ |
michael@0 | 98 | nsresult EnsureThread(); |
michael@0 | 99 | |
michael@0 | 100 | /** |
michael@0 | 101 | * Called on mThread to set up the thread observer. |
michael@0 | 102 | */ |
michael@0 | 103 | void InitThread(); |
michael@0 | 104 | |
michael@0 | 105 | /** |
michael@0 | 106 | * Called on mThread to clean up the thread observer. |
michael@0 | 107 | */ |
michael@0 | 108 | void CleanupThread(); |
michael@0 | 109 | |
michael@0 | 110 | /** |
michael@0 | 111 | * Called on the main thread when mThread believes itself to be idle. Sets up |
michael@0 | 112 | * the idle timer. |
michael@0 | 113 | */ |
michael@0 | 114 | void ScheduleTimer(); |
michael@0 | 115 | |
michael@0 | 116 | /** |
michael@0 | 117 | * Called when we are shutting down mThread. |
michael@0 | 118 | */ |
michael@0 | 119 | nsresult ShutdownThread(); |
michael@0 | 120 | |
michael@0 | 121 | /** |
michael@0 | 122 | * Deletes this object. Used to delay calling mThread->Shutdown() during the |
michael@0 | 123 | * final release (during a GC, for instance). |
michael@0 | 124 | */ |
michael@0 | 125 | void SelfDestruct(); |
michael@0 | 126 | |
michael@0 | 127 | /** |
michael@0 | 128 | * Returns true if events should be queued rather than immediately dispatched |
michael@0 | 129 | * to mThread. Currently only happens when the thread is shutting down. |
michael@0 | 130 | */ |
michael@0 | 131 | bool UseRunnableQueue() { |
michael@0 | 132 | return !!mQueuedRunnables; |
michael@0 | 133 | } |
michael@0 | 134 | |
michael@0 | 135 | /** |
michael@0 | 136 | * Protects data that is accessed on both threads. |
michael@0 | 137 | */ |
michael@0 | 138 | mozilla::Mutex mMutex; |
michael@0 | 139 | |
michael@0 | 140 | /** |
michael@0 | 141 | * Touched on both threads but set before mThread is created. Used to direct |
michael@0 | 142 | * timer events to the owning thread. |
michael@0 | 143 | */ |
michael@0 | 144 | nsCOMPtr<nsIThread> mOwningThread; |
michael@0 | 145 | |
michael@0 | 146 | /** |
michael@0 | 147 | * Only accessed on the owning thread. Set by EnsureThread(). |
michael@0 | 148 | */ |
michael@0 | 149 | nsCOMPtr<nsIThread> mThread; |
michael@0 | 150 | |
michael@0 | 151 | /** |
michael@0 | 152 | * Protected by mMutex. Created when mThread has no pending events and fired |
michael@0 | 153 | * at mOwningThread. Any thread that dispatches to mThread will take ownership |
michael@0 | 154 | * of the timer and fire a separate cancel event to the owning thread. |
michael@0 | 155 | */ |
michael@0 | 156 | nsCOMPtr<nsITimer> mIdleTimer; |
michael@0 | 157 | |
michael@0 | 158 | /** |
michael@0 | 159 | * Idle observer. Called when the thread is about to be shut down. Released |
michael@0 | 160 | * only when Shutdown() is called. |
michael@0 | 161 | */ |
michael@0 | 162 | nsIObserver* mIdleObserver; |
michael@0 | 163 | |
michael@0 | 164 | /** |
michael@0 | 165 | * Temporary storage for events that happen to be dispatched while we're in |
michael@0 | 166 | * the process of shutting down our real thread. |
michael@0 | 167 | */ |
michael@0 | 168 | nsTArray<nsCOMPtr<nsIRunnable> >* mQueuedRunnables; |
michael@0 | 169 | |
michael@0 | 170 | /** |
michael@0 | 171 | * The number of milliseconds a thread should be idle before dying. |
michael@0 | 172 | */ |
michael@0 | 173 | const uint32_t mIdleTimeoutMS; |
michael@0 | 174 | |
michael@0 | 175 | /** |
michael@0 | 176 | * The number of events that are pending on mThread. A nonzero value means |
michael@0 | 177 | * that the thread cannot be cleaned up. |
michael@0 | 178 | */ |
michael@0 | 179 | uint32_t mPendingEventCount; |
michael@0 | 180 | |
michael@0 | 181 | /** |
michael@0 | 182 | * The number of times that mThread has dispatched an idle notification. Any |
michael@0 | 183 | * timer that fires while this count is nonzero can safely be ignored as |
michael@0 | 184 | * another timer will be on the way. |
michael@0 | 185 | */ |
michael@0 | 186 | uint32_t mIdleNotificationCount; |
michael@0 | 187 | |
michael@0 | 188 | /** |
michael@0 | 189 | * Whether or not the thread should automatically shutdown. If the owner |
michael@0 | 190 | * specified ManualShutdown at construction time then the owner should take |
michael@0 | 191 | * care to call Shutdown() manually when appropriate. |
michael@0 | 192 | */ |
michael@0 | 193 | ShutdownMethod mShutdownMethod; |
michael@0 | 194 | |
michael@0 | 195 | /** |
michael@0 | 196 | * Only accessed on the owning thread. Set to true when Shutdown() has been |
michael@0 | 197 | * called and prevents EnsureThread() from recreating mThread. |
michael@0 | 198 | */ |
michael@0 | 199 | bool mShutdown; |
michael@0 | 200 | |
michael@0 | 201 | /** |
michael@0 | 202 | * Set from CleanupThread and lasting until the thread has shut down. Prevents |
michael@0 | 203 | * further idle notifications during the shutdown process. |
michael@0 | 204 | */ |
michael@0 | 205 | bool mThreadIsShuttingDown; |
michael@0 | 206 | |
michael@0 | 207 | /** |
michael@0 | 208 | * Whether or not the idle timeout is enabled. |
michael@0 | 209 | */ |
michael@0 | 210 | bool mIdleTimeoutEnabled; |
michael@0 | 211 | |
michael@0 | 212 | /** |
michael@0 | 213 | * Name of the thread, set on the actual thread after it gets created. |
michael@0 | 214 | */ |
michael@0 | 215 | nsCString mName; |
michael@0 | 216 | }; |
michael@0 | 217 | |
michael@0 | 218 | } // namespace mozilla |
michael@0 | 219 | |
michael@0 | 220 | #endif // mozilla_lazyidlethread_h__ |