VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.cpp@ 28321

Last change on this file since 28321 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.0 KB
Line 
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is Mozilla Communicator client code.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 * Rick Potts <rpotts@netscape.com>
24 * Ramiro Estrugo <ramiro@netscape.com>
25 * Warren Harris <warren@netscape.com>
26 * Leaf Nunes <leaf@mozilla.org>
27 * David Matiskella <davidm@netscape.com>
28 * David Hyatt <hyatt@netscape.com>
29 * Seth Spitzer <sspitzer@netscape.com>
30 * Suresh Duddi <dp@netscape.com>
31 * Bruce Mitchener <bruce@cybersight.com>
32 * Scott Collins <scc@netscape.com>
33 * Daniel Matejka <danm@netscape.com>
34 * Doug Turner <dougt@netscape.com>
35 * Stuart Parmenter <pavlov@netscape.com>
36 * Mike Kaply <mkaply@us.ibm.com>
37 * Dan Mosedale <dmose@mozilla.org>
38 *
39 * Alternatively, the contents of this file may be used under the terms of
40 * either of the GNU General Public License Version 2 or later (the "GPL"),
41 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
42 * in which case the provisions of the GPL or the LGPL are applicable instead
43 * of those above. If you wish to allow use of your version of this file only
44 * under the terms of either the GPL or the LGPL, and not to allow others to
45 * use your version of this file under the terms of the MPL, indicate your
46 * decision by deleting the provisions above and replace them with the notice
47 * and other provisions required by the GPL or the LGPL. If you do not delete
48 * the provisions above, a recipient may use your version of this file under
49 * the terms of any one of the MPL, the GPL or the LGPL.
50 *
51 * ***** END LICENSE BLOCK ***** */
52
53#include "nsEventQueueService.h"
54#include "prmon.h"
55#include "nsIComponentManager.h"
56#include "nsIThread.h"
57#include "nsPIEventQueueChain.h"
58
59#include "prlog.h"
60
61#if defined(PR_LOGGING) || defined(DEBUG_danm)
62extern PRLogModuleInfo* gEventQueueLog;
63extern PRUint32 gEventQueueLogCount;
64#endif
65
66static NS_DEFINE_CID(kEventQueueCID, NS_EVENTQUEUE_CID);
67
68nsEventQueueServiceImpl::nsEventQueueServiceImpl()
69{
70 mEventQMonitor = PR_NewMonitor();
71#if defined(PR_LOGGING) && defined(DEBUG_danm)
72 if (!gEventQueueLog)
73 gEventQueueLog = PR_NewLogModule("nseventqueue");
74#endif
75}
76
77PR_STATIC_CALLBACK(PLDHashOperator)
78hash_enum_remove_queues(const void *aThread_ptr,
79 nsCOMPtr<nsIEventQueue>& aEldestQueue,
80 void* closure)
81{
82 // 'aQueue' should be the eldest queue.
83 nsCOMPtr<nsPIEventQueueChain> pie(do_QueryInterface(aEldestQueue));
84 nsCOMPtr<nsIEventQueue> q;
85
86 // stop accepting events for youngest to oldest
87 pie->GetYoungest(getter_AddRefs(q));
88 while (q) {
89 q->StopAcceptingEvents();
90
91 nsCOMPtr<nsPIEventQueueChain> pq(do_QueryInterface(q));
92 pq->GetElder(getter_AddRefs(q));
93 }
94
95 return PL_DHASH_REMOVE;
96}
97
98nsEventQueueServiceImpl::~nsEventQueueServiceImpl()
99{
100 // XXX make it so we only enum over this once
101 mEventQTable.Enumerate(hash_enum_remove_queues, nsnull); // call StopAcceptingEvents on everything and clear out the hashtable
102
103 PR_DestroyMonitor(mEventQMonitor);
104}
105
106nsresult
107nsEventQueueServiceImpl::Init()
108{
109 NS_ENSURE_TRUE(mEventQMonitor, NS_ERROR_OUT_OF_MEMORY);
110
111 // This will only be called once on the main thread, so it's safe to
112 // not enter the monitor here.
113 if (!mEventQTable.Init()) {
114 return NS_ERROR_OUT_OF_MEMORY;
115 }
116
117 // ensure that a main thread event queue exists!
118 nsresult rv;
119 nsCOMPtr<nsIThread> mainThread;
120 rv = nsIThread::GetMainThread(getter_AddRefs(mainThread));
121 if (NS_SUCCEEDED(rv)) {
122 PRThread *thr;
123 rv = mainThread->GetPRThread(&thr);
124 if (NS_SUCCEEDED(rv))
125 rv = CreateEventQueue(thr, PR_TRUE);
126 }
127 return rv;
128}
129
130/* nsISupports interface implementation... */
131NS_IMPL_THREADSAFE_ISUPPORTS1(nsEventQueueServiceImpl, nsIEventQueueService)
132
133/* nsIEventQueueService interface implementation... */
134
135NS_IMETHODIMP
136nsEventQueueServiceImpl::CreateThreadEventQueue()
137{
138 return CreateEventQueue(PR_GetCurrentThread(), PR_TRUE);
139}
140
141NS_IMETHODIMP
142nsEventQueueServiceImpl::CreateMonitoredThreadEventQueue()
143{
144 return CreateEventQueue(PR_GetCurrentThread(), PR_FALSE);
145}
146
147NS_IMETHODIMP
148nsEventQueueServiceImpl::CreateFromIThread(nsIThread *aThread, PRBool aNative,
149 nsIEventQueue **aResult)
150{
151 nsresult rv;
152 PRThread *prThread;
153
154 rv = aThread->GetPRThread(&prThread);
155 if (NS_SUCCEEDED(rv)) {
156 rv = CreateEventQueue(prThread, aNative); // addrefs
157 if (NS_SUCCEEDED(rv))
158 rv = GetThreadEventQueue(prThread, aResult); // addrefs
159 }
160 return rv;
161}
162
163// private method
164NS_IMETHODIMP
165nsEventQueueServiceImpl::MakeNewQueue(PRThread* thread,
166 PRBool aNative,
167 nsIEventQueue **aQueue)
168{
169 nsresult rv;
170 nsCOMPtr<nsIEventQueue> queue = do_CreateInstance(kEventQueueCID, &rv);
171
172 if (NS_SUCCEEDED(rv)) {
173 rv = queue->InitFromPRThread(thread, aNative);
174 }
175 *aQueue = queue;
176 NS_IF_ADDREF(*aQueue);
177 return rv;
178}
179
180// private method
181NS_IMETHODIMP
182nsEventQueueServiceImpl::CreateEventQueue(PRThread *aThread, PRBool aNative)
183{
184 nsresult rv = NS_OK;
185 /* Enter the lock that protects the EventQ hashtable... */
186 PR_EnterMonitor(mEventQMonitor);
187
188 /* create only one event queue chain per thread... */
189 if (!mEventQTable.GetWeak(aThread)) {
190 nsCOMPtr<nsIEventQueue> queue;
191
192 // we don't have one in the table
193 rv = MakeNewQueue(aThread, aNative, getter_AddRefs(queue)); // create new queue
194 mEventQTable.Put(aThread, queue); // add to the table (initial addref)
195 }
196
197 // Release the EventQ lock...
198 PR_ExitMonitor(mEventQMonitor);
199 return rv;
200}
201
202
203NS_IMETHODIMP
204nsEventQueueServiceImpl::DestroyThreadEventQueue(void)
205{
206 nsresult rv = NS_OK;
207
208 /* Enter the lock that protects the EventQ hashtable... */
209 PR_EnterMonitor(mEventQMonitor);
210
211 PRThread* currentThread = PR_GetCurrentThread();
212 nsIEventQueue* queue = mEventQTable.GetWeak(currentThread);
213 if (queue) {
214 queue->StopAcceptingEvents(); // tell the queue to stop accepting events
215 queue = nsnull; // Queue may die on the next line
216 mEventQTable.Remove(currentThread); // remove nsIEventQueue from hash table (releases)
217 }
218
219 // Release the EventQ lock...
220 PR_ExitMonitor(mEventQMonitor);
221 return rv;
222}
223
224NS_IMETHODIMP
225nsEventQueueServiceImpl::CreateFromPLEventQueue(PLEventQueue* aPLEventQueue, nsIEventQueue** aResult)
226{
227 // Create our thread queue using the component manager
228 nsresult rv;
229 nsCOMPtr<nsIEventQueue> queue = do_CreateInstance(kEventQueueCID, &rv);
230 if (NS_FAILED(rv)) return rv;
231
232 rv = queue->InitFromPLQueue(aPLEventQueue);
233 if (NS_FAILED(rv)) return rv;
234
235 *aResult = queue;
236 NS_IF_ADDREF(*aResult);
237 return NS_OK;
238}
239
240
241// Return the active event queue on our chain
242/* inline */
243nsresult nsEventQueueServiceImpl::GetYoungestEventQueue(nsIEventQueue *queue, nsIEventQueue **aResult)
244{
245 nsCOMPtr<nsIEventQueue> answer;
246
247 if (queue) {
248 nsCOMPtr<nsPIEventQueueChain> ourChain(do_QueryInterface(queue));
249 if (ourChain)
250 ourChain->GetYoungestActive(getter_AddRefs(answer));
251 else
252 answer = queue;
253 }
254
255 *aResult = answer;
256 NS_IF_ADDREF(*aResult);
257 return NS_OK;
258}
259
260
261// create new event queue, append it to the current thread's chain of event queues.
262// return it, addrefed.
263NS_IMETHODIMP
264nsEventQueueServiceImpl::PushThreadEventQueue(nsIEventQueue **aNewQueue)
265{
266 nsresult rv = NS_OK;
267 PRThread* currentThread = PR_GetCurrentThread();
268 PRBool native = PR_TRUE; // native by default as per old comment
269
270
271 NS_ASSERTION(aNewQueue, "PushThreadEventQueue called with null param");
272
273 /* Enter the lock that protects the EventQ hashtable... */
274 PR_EnterMonitor(mEventQMonitor);
275
276 nsIEventQueue* queue = mEventQTable.GetWeak(currentThread);
277
278 NS_ASSERTION(queue, "pushed event queue on top of nothing");
279
280 if (queue) { // find out what kind of queue our relatives are
281 nsCOMPtr<nsIEventQueue> youngQueue;
282 GetYoungestEventQueue(queue, getter_AddRefs(youngQueue));
283 if (youngQueue) {
284 youngQueue->IsQueueNative(&native);
285 }
286 }
287
288 nsIEventQueue* newQueue = nsnull;
289 MakeNewQueue(currentThread, native, &newQueue); // create new queue; addrefs
290
291 if (!queue) {
292 // shouldn't happen. as a fallback, we guess you wanted a native queue
293 mEventQTable.Put(currentThread, newQueue);
294 }
295
296 // append to the event queue chain
297 nsCOMPtr<nsPIEventQueueChain> ourChain(do_QueryInterface(queue)); // QI the queue in the hash table
298 if (ourChain)
299 ourChain->AppendQueue(newQueue); // append new queue to it
300
301 *aNewQueue = newQueue;
302
303#if defined(PR_LOGGING) && defined(DEBUG_danm)
304 PLEventQueue *equeue;
305 (*aNewQueue)->GetPLEventQueue(&equeue);
306 PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
307 ("EventQueue: Service push queue [queue=%lx]",(long)equeue));
308 ++gEventQueueLogCount;
309#endif
310
311 // Release the EventQ lock...
312 PR_ExitMonitor(mEventQMonitor);
313 return rv;
314}
315
316// disable and release the given queue (though the last one won't be released)
317NS_IMETHODIMP
318nsEventQueueServiceImpl::PopThreadEventQueue(nsIEventQueue *aQueue)
319{
320 PRThread* currentThread = PR_GetCurrentThread();
321
322 /* Enter the lock that protects the EventQ hashtable... */
323 PR_EnterMonitor(mEventQMonitor);
324
325 nsCOMPtr<nsIEventQueue> eldestQueue;
326 mEventQTable.Get(currentThread, getter_AddRefs(eldestQueue));
327
328 // If we are popping the eldest queue, remove its mEventQTable entry.
329 if (aQueue == eldestQueue)
330 mEventQTable.Remove(currentThread);
331
332 // Exit the monitor before processing pending events to avoid deadlock.
333 // Our reference from the eldestQueue nsCOMPtr will keep that object alive.
334 // Since it is thread-private, no one else can race with us here.
335 PR_ExitMonitor(mEventQMonitor);
336 if (!eldestQueue)
337 return NS_ERROR_FAILURE;
338
339#if defined(PR_LOGGING) && defined(DEBUG_danm)
340 PLEventQueue *equeue;
341 aQueue->GetPLEventQueue(&equeue);
342 PR_LOG(gEventQueueLog, PR_LOG_DEBUG,
343 ("EventQueue: Service pop queue [queue=%lx]",(long)equeue));
344 ++gEventQueueLogCount;
345#endif
346 aQueue->StopAcceptingEvents();
347 aQueue->ProcessPendingEvents(); // make sure we don't orphan any events
348
349 return NS_OK;
350}
351
352NS_IMETHODIMP
353nsEventQueueServiceImpl::GetThreadEventQueue(PRThread* aThread, nsIEventQueue** aResult)
354{
355 /* Parameter validation... */
356 if (NULL == aResult) return NS_ERROR_NULL_POINTER;
357
358 PRThread* keyThread = aThread;
359
360 if (keyThread == NS_CURRENT_THREAD)
361 {
362 keyThread = PR_GetCurrentThread();
363 }
364 else if (keyThread == NS_UI_THREAD)
365 {
366 nsCOMPtr<nsIThread> mainIThread;
367
368 // Get the primordial thread
369 nsresult rv = nsIThread::GetMainThread(getter_AddRefs(mainIThread));
370 if (NS_FAILED(rv)) return rv;
371
372 rv = mainIThread->GetPRThread(&keyThread);
373 if (NS_FAILED(rv)) return rv;
374 }
375
376 /* Enter the lock that protects the EventQ hashtable... */
377 PR_EnterMonitor(mEventQMonitor);
378
379 nsCOMPtr<nsIEventQueue> queue;
380 mEventQTable.Get(keyThread, getter_AddRefs(queue));
381
382 PR_ExitMonitor(mEventQMonitor);
383
384 if (queue) {
385 GetYoungestEventQueue(queue, aResult); // get the youngest active queue
386 } else {
387 *aResult = nsnull;
388 }
389 // XXX: Need error code for requesting an event queue when none exists...
390 if (!*aResult) {
391 return NS_ERROR_NOT_AVAILABLE;
392 }
393 return NS_OK;
394}
395
396
397NS_IMETHODIMP
398nsEventQueueServiceImpl::ResolveEventQueue(nsIEventQueue* queueOrConstant, nsIEventQueue* *resultQueue)
399{
400 if (queueOrConstant == NS_CURRENT_EVENTQ) {
401 return GetThreadEventQueue(NS_CURRENT_THREAD, resultQueue);
402 }
403 else if (queueOrConstant == NS_UI_THREAD_EVENTQ) {
404 return GetThreadEventQueue(NS_UI_THREAD, resultQueue);
405 }
406
407 *resultQueue = queueOrConstant;
408 NS_ADDREF(*resultQueue);
409 return NS_OK;
410}
411
412NS_IMETHODIMP
413nsEventQueueServiceImpl::GetSpecialEventQueue(PRInt32 aQueue,
414 nsIEventQueue* *_retval)
415{
416 nsresult rv;
417
418 // barf if someone gave us a zero pointer
419 //
420 if (!_retval) {
421 return NS_ERROR_NULL_POINTER;
422 }
423
424 // try and get the requested event queue, returning NS_ERROR_FAILURE if there
425 // is a problem. GetThreadEventQueue() does the AddRef() for us.
426 //
427 switch (aQueue) {
428 case CURRENT_THREAD_EVENT_QUEUE:
429 rv = GetThreadEventQueue(NS_CURRENT_THREAD, _retval);
430 if (NS_FAILED(rv)) {
431 return NS_ERROR_FAILURE;
432 }
433 break;
434
435 case UI_THREAD_EVENT_QUEUE:
436 rv = GetThreadEventQueue(NS_UI_THREAD, _retval);
437 if (NS_FAILED(rv)) {
438 return NS_ERROR_FAILURE;
439 }
440 break;
441
442 // somebody handed us a bogus constant
443 //
444 default:
445 return NS_ERROR_ILLEGAL_VALUE;
446 }
447
448 return NS_OK;
449}
450
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette