1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 et sw=2 tw=80: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Indexed Database.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * The Mozilla Foundation.
20 : * Portions created by the Initial Developer are Copyright (C) 2010
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Ben Turner <bent.mozilla@gmail.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #ifndef mozilla_lazyidlethread_h__
41 : #define mozilla_lazyidlethread_h__
42 :
43 : #ifndef MOZILLA_INTERNAL_API
44 : #error "This header is only usable from within libxul (MOZILLA_INTERNAL_API)."
45 : #endif
46 :
47 : #include "nsIObserver.h"
48 : #include "nsIThreadInternal.h"
49 : #include "nsITimer.h"
50 :
51 : #include "mozilla/Mutex.h"
52 : #include "nsCOMPtr.h"
53 : #include "nsTArray.h"
54 :
55 : #define IDLE_THREAD_TOPIC "thread-shutting-down"
56 :
57 : namespace mozilla {
58 :
59 : /**
60 : * This class provides a basic event target that creates its thread lazily and
61 : * destroys its thread after a period of inactivity. It may be created on any
62 : * thread but it may only be used from the thread on which it is created. If it
63 : * is created on the main thread then it will automatically join its thread on
64 : * XPCOM shutdown using the Observer Service.
65 : */
66 : class LazyIdleThread : public nsIThread,
67 : public nsITimerCallback,
68 : public nsIThreadObserver,
69 : public nsIObserver
70 : {
71 : public:
72 : NS_DECL_ISUPPORTS
73 : NS_DECL_NSIEVENTTARGET
74 : NS_DECL_NSITHREAD
75 : NS_DECL_NSITIMERCALLBACK
76 : NS_DECL_NSITHREADOBSERVER
77 : NS_DECL_NSIOBSERVER
78 :
79 : enum ShutdownMethod {
80 : AutomaticShutdown = 0,
81 : ManualShutdown
82 : };
83 :
84 : /**
85 : * Create a new LazyIdleThread that will destroy its thread after the given
86 : * number of milliseconds.
87 : */
88 : LazyIdleThread(PRUint32 aIdleTimeoutMS,
89 : ShutdownMethod aShutdownMethod = AutomaticShutdown,
90 : nsIObserver* aIdleObserver = nsnull);
91 :
92 : /**
93 : * Add an observer that will be notified when the thread is idle and about to
94 : * be shut down. The aSubject argument can be QueryInterface'd to an nsIThread
95 : * that can be used to post cleanup events. The aTopic argument will be
96 : * IDLE_THREAD_TOPIC, and aData will be null. The LazyIdleThread does not add
97 : * a reference to the observer to avoid circular references as it is assumed
98 : * to be the owner. It is the caller's responsibility to clear this observer
99 : * if the pointer becomes invalid.
100 : */
101 : void SetWeakIdleObserver(nsIObserver* aObserver);
102 :
103 : /**
104 : * Disable the idle timeout for this thread. No effect if the timeout is
105 : * already disabled.
106 : */
107 : void DisableIdleTimeout();
108 :
109 : /**
110 : * Enable the idle timeout. No effect if the timeout is already enabled.
111 : */
112 : void EnableIdleTimeout();
113 :
114 : private:
115 : /**
116 : * Calls Shutdown().
117 : */
118 : ~LazyIdleThread();
119 :
120 : /**
121 : * Called just before dispatching to mThread.
122 : */
123 : void PreDispatch();
124 :
125 : /**
126 : * Makes sure a valid thread lives in mThread.
127 : */
128 : nsresult EnsureThread();
129 :
130 : /**
131 : * Called on mThread to set up the thread observer.
132 : */
133 : void InitThread();
134 :
135 : /**
136 : * Called on mThread to clean up the thread observer.
137 : */
138 : void CleanupThread();
139 :
140 : /**
141 : * Called on the main thread when mThread believes itself to be idle. Sets up
142 : * the idle timer.
143 : */
144 : void ScheduleTimer();
145 :
146 : /**
147 : * Called when we are shutting down mThread.
148 : */
149 : nsresult ShutdownThread();
150 :
151 : /**
152 : * Deletes this object. Used to delay calling mThread->Shutdown() during the
153 : * final release (during a GC, for instance).
154 : */
155 : void SelfDestruct();
156 :
157 : /**
158 : * Returns true if events should be queued rather than immediately dispatched
159 : * to mThread. Currently only happens when the thread is shutting down.
160 : */
161 84 : bool UseRunnableQueue() {
162 84 : return !!mQueuedRunnables;
163 : }
164 :
165 : /**
166 : * Protects data that is accessed on both threads.
167 : */
168 : mozilla::Mutex mMutex;
169 :
170 : /**
171 : * Touched on both threads but set before mThread is created. Used to direct
172 : * timer events to the owning thread.
173 : */
174 : nsCOMPtr<nsIThread> mOwningThread;
175 :
176 : /**
177 : * Only accessed on the owning thread. Set by EnsureThread().
178 : */
179 : nsCOMPtr<nsIThread> mThread;
180 :
181 : /**
182 : * Protected by mMutex. Created when mThread has no pending events and fired
183 : * at mOwningThread. Any thread that dispatches to mThread will take ownership
184 : * of the timer and fire a separate cancel event to the owning thread.
185 : */
186 : nsCOMPtr<nsITimer> mIdleTimer;
187 :
188 : /**
189 : * Idle observer. Called when the thread is about to be shut down. Released
190 : * only when Shutdown() is called.
191 : */
192 : nsIObserver* mIdleObserver;
193 :
194 : /**
195 : * Temporary storage for events that happen to be dispatched while we're in
196 : * the process of shutting down our real thread.
197 : */
198 : nsTArray<nsCOMPtr<nsIRunnable> >* mQueuedRunnables;
199 :
200 : /**
201 : * The number of milliseconds a thread should be idle before dying.
202 : */
203 : const PRUint32 mIdleTimeoutMS;
204 :
205 : /**
206 : * The number of events that are pending on mThread. A nonzero value means
207 : * that the thread cannot be cleaned up.
208 : */
209 : PRUint32 mPendingEventCount;
210 :
211 : /**
212 : * The number of times that mThread has dispatched an idle notification. Any
213 : * timer that fires while this count is nonzero can safely be ignored as
214 : * another timer will be on the way.
215 : */
216 : PRUint32 mIdleNotificationCount;
217 :
218 : /**
219 : * Whether or not the thread should automatically shutdown. If the owner
220 : * specified ManualShutdown at construction time then the owner should take
221 : * care to call Shutdown() manually when appropriate.
222 : */
223 : ShutdownMethod mShutdownMethod;
224 :
225 : /**
226 : * Only accessed on the owning thread. Set to true when Shutdown() has been
227 : * called and prevents EnsureThread() from recreating mThread.
228 : */
229 : bool mShutdown;
230 :
231 : /**
232 : * Set from CleanupThread and lasting until the thread has shut down. Prevents
233 : * further idle notifications during the shutdown process.
234 : */
235 : bool mThreadIsShuttingDown;
236 :
237 : /**
238 : * Whether or not the idle timeout is enabled.
239 : */
240 : bool mIdleTimeoutEnabled;
241 : };
242 :
243 : } // namespace mozilla
244 :
245 : #endif // mozilla_lazyidlethread_h__
|