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