VirtualBox

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

Last change on this file since 101992 was 101992, checked in by vboxsync, 19 months ago

libs/xpcom: Convert nsEventQueueService.cpp from PR_LOG to IPRT's logging infrastructure, bugref:10545

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.6 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 <VBox/log.h>
60
61static NS_DEFINE_CID(kEventQueueCID, NS_EVENTQUEUE_CID);
62
63nsEventQueueServiceImpl::nsEventQueueServiceImpl()
64{
65 mEventQMonitor = PR_NewMonitor();
66}
67
68PR_STATIC_CALLBACK(PLDHashOperator)
69hash_enum_remove_queues(const void *aThread_ptr,
70 nsCOMPtr<nsIEventQueue>& aEldestQueue,
71 void* closure)
72{
73 // 'aQueue' should be the eldest queue.
74 nsCOMPtr<nsPIEventQueueChain> pie(do_QueryInterface(aEldestQueue));
75 nsCOMPtr<nsIEventQueue> q;
76
77 // stop accepting events for youngest to oldest
78 pie->GetYoungest(getter_AddRefs(q));
79 while (q) {
80 q->StopAcceptingEvents();
81
82 nsCOMPtr<nsPIEventQueueChain> pq(do_QueryInterface(q));
83 pq->GetElder(getter_AddRefs(q));
84 }
85
86 return PL_DHASH_REMOVE;
87}
88
89nsEventQueueServiceImpl::~nsEventQueueServiceImpl()
90{
91 // XXX make it so we only enum over this once
92 mEventQTable.Enumerate(hash_enum_remove_queues, nsnull); // call StopAcceptingEvents on everything and clear out the hashtable
93
94 PR_DestroyMonitor(mEventQMonitor);
95}
96
97nsresult
98nsEventQueueServiceImpl::Init()
99{
100 NS_ENSURE_TRUE(mEventQMonitor, NS_ERROR_OUT_OF_MEMORY);
101
102 // This will only be called once on the main thread, so it's safe to
103 // not enter the monitor here.
104 if (!mEventQTable.Init()) {
105 return NS_ERROR_OUT_OF_MEMORY;
106 }
107
108 // ensure that a main thread event queue exists!
109 nsresult rv;
110 nsCOMPtr<nsIThread> mainThread;
111 rv = nsIThread::GetMainThread(getter_AddRefs(mainThread));
112 if (NS_SUCCEEDED(rv)) {
113 PRThread *thr;
114 rv = mainThread->GetPRThread(&thr);
115 if (NS_SUCCEEDED(rv))
116 rv = CreateEventQueue(thr, PR_TRUE);
117 }
118 return rv;
119}
120
121/* nsISupports interface implementation... */
122NS_IMPL_THREADSAFE_ISUPPORTS1(nsEventQueueServiceImpl, nsIEventQueueService)
123
124/* nsIEventQueueService interface implementation... */
125
126NS_IMETHODIMP
127nsEventQueueServiceImpl::CreateThreadEventQueue()
128{
129 return CreateEventQueue(PR_GetCurrentThread(), PR_TRUE);
130}
131
132NS_IMETHODIMP
133nsEventQueueServiceImpl::CreateMonitoredThreadEventQueue()
134{
135 return CreateEventQueue(PR_GetCurrentThread(), PR_FALSE);
136}
137
138NS_IMETHODIMP
139nsEventQueueServiceImpl::CreateFromIThread(nsIThread *aThread, PRBool aNative,
140 nsIEventQueue **aResult)
141{
142 nsresult rv;
143 PRThread *prThread;
144
145 rv = aThread->GetPRThread(&prThread);
146 if (NS_SUCCEEDED(rv)) {
147 rv = CreateEventQueue(prThread, aNative); // addrefs
148 if (NS_SUCCEEDED(rv))
149 rv = GetThreadEventQueue(prThread, aResult); // addrefs
150 }
151 return rv;
152}
153
154// private method
155NS_IMETHODIMP
156nsEventQueueServiceImpl::MakeNewQueue(PRThread* thread,
157 PRBool aNative,
158 nsIEventQueue **aQueue)
159{
160 nsresult rv;
161 nsCOMPtr<nsIEventQueue> queue = do_CreateInstance(kEventQueueCID, &rv);
162
163 if (NS_SUCCEEDED(rv)) {
164 rv = queue->InitFromPRThread(thread, aNative);
165 }
166 *aQueue = queue;
167 NS_IF_ADDREF(*aQueue);
168 return rv;
169}
170
171// private method
172NS_IMETHODIMP
173nsEventQueueServiceImpl::CreateEventQueue(PRThread *aThread, PRBool aNative)
174{
175 nsresult rv = NS_OK;
176 /* Enter the lock that protects the EventQ hashtable... */
177 PR_EnterMonitor(mEventQMonitor);
178
179 /* create only one event queue chain per thread... */
180 if (!mEventQTable.GetWeak(aThread)) {
181 nsCOMPtr<nsIEventQueue> queue;
182
183 // we don't have one in the table
184 rv = MakeNewQueue(aThread, aNative, getter_AddRefs(queue)); // create new queue
185 mEventQTable.Put(aThread, queue); // add to the table (initial addref)
186 }
187
188 // Release the EventQ lock...
189 PR_ExitMonitor(mEventQMonitor);
190 return rv;
191}
192
193
194NS_IMETHODIMP
195nsEventQueueServiceImpl::DestroyThreadEventQueue(void)
196{
197 nsresult rv = NS_OK;
198
199 /* Enter the lock that protects the EventQ hashtable... */
200 PR_EnterMonitor(mEventQMonitor);
201
202 PRThread* currentThread = PR_GetCurrentThread();
203 nsIEventQueue* queue = mEventQTable.GetWeak(currentThread);
204 if (queue) {
205 queue->StopAcceptingEvents(); // tell the queue to stop accepting events
206 queue = nsnull; // Queue may die on the next line
207 mEventQTable.Remove(currentThread); // remove nsIEventQueue from hash table (releases)
208 }
209
210 // Release the EventQ lock...
211 PR_ExitMonitor(mEventQMonitor);
212 return rv;
213}
214
215NS_IMETHODIMP
216nsEventQueueServiceImpl::CreateFromPLEventQueue(PLEventQueue* aPLEventQueue, nsIEventQueue** aResult)
217{
218 // Create our thread queue using the component manager
219 nsresult rv;
220 nsCOMPtr<nsIEventQueue> queue = do_CreateInstance(kEventQueueCID, &rv);
221 if (NS_FAILED(rv)) return rv;
222
223 rv = queue->InitFromPLQueue(aPLEventQueue);
224 if (NS_FAILED(rv)) return rv;
225
226 *aResult = queue;
227 NS_IF_ADDREF(*aResult);
228 return NS_OK;
229}
230
231
232// Return the active event queue on our chain
233/* inline */
234nsresult nsEventQueueServiceImpl::GetYoungestEventQueue(nsIEventQueue *queue, nsIEventQueue **aResult)
235{
236 nsCOMPtr<nsIEventQueue> answer;
237
238 if (queue) {
239 nsCOMPtr<nsPIEventQueueChain> ourChain(do_QueryInterface(queue));
240 if (ourChain)
241 ourChain->GetYoungestActive(getter_AddRefs(answer));
242 else
243 answer = queue;
244 }
245
246 *aResult = answer;
247 NS_IF_ADDREF(*aResult);
248 return NS_OK;
249}
250
251
252// create new event queue, append it to the current thread's chain of event queues.
253// return it, addrefed.
254NS_IMETHODIMP
255nsEventQueueServiceImpl::PushThreadEventQueue(nsIEventQueue **aNewQueue)
256{
257 nsresult rv = NS_OK;
258 PRThread* currentThread = PR_GetCurrentThread();
259 PRBool native = PR_TRUE; // native by default as per old comment
260
261
262 NS_ASSERTION(aNewQueue, "PushThreadEventQueue called with null param");
263
264 /* Enter the lock that protects the EventQ hashtable... */
265 PR_EnterMonitor(mEventQMonitor);
266
267 nsIEventQueue* queue = mEventQTable.GetWeak(currentThread);
268
269 NS_ASSERTION(queue, "pushed event queue on top of nothing");
270
271 if (queue) { // find out what kind of queue our relatives are
272 nsCOMPtr<nsIEventQueue> youngQueue;
273 GetYoungestEventQueue(queue, getter_AddRefs(youngQueue));
274 if (youngQueue) {
275 youngQueue->IsQueueNative(&native);
276 }
277 }
278
279 nsIEventQueue* newQueue = nsnull;
280 MakeNewQueue(currentThread, native, &newQueue); // create new queue; addrefs
281
282 if (!queue) {
283 // shouldn't happen. as a fallback, we guess you wanted a native queue
284 mEventQTable.Put(currentThread, newQueue);
285 }
286
287 // append to the event queue chain
288 nsCOMPtr<nsPIEventQueueChain> ourChain(do_QueryInterface(queue)); // QI the queue in the hash table
289 if (ourChain)
290 ourChain->AppendQueue(newQueue); // append new queue to it
291
292 *aNewQueue = newQueue;
293
294#ifdef LOG_ENABLED
295 PLEventQueue *equeue;
296 (*aNewQueue)->GetPLEventQueue(&equeue);
297 Log(("EventQueue: Service push queue [queue=%lx]",(long)equeue));
298#endif
299
300 // Release the EventQ lock...
301 PR_ExitMonitor(mEventQMonitor);
302 return rv;
303}
304
305// disable and release the given queue (though the last one won't be released)
306NS_IMETHODIMP
307nsEventQueueServiceImpl::PopThreadEventQueue(nsIEventQueue *aQueue)
308{
309 PRThread* currentThread = PR_GetCurrentThread();
310
311 /* Enter the lock that protects the EventQ hashtable... */
312 PR_EnterMonitor(mEventQMonitor);
313
314 nsCOMPtr<nsIEventQueue> eldestQueue;
315 mEventQTable.Get(currentThread, getter_AddRefs(eldestQueue));
316
317 // If we are popping the eldest queue, remove its mEventQTable entry.
318 if (aQueue == eldestQueue)
319 mEventQTable.Remove(currentThread);
320
321 // Exit the monitor before processing pending events to avoid deadlock.
322 // Our reference from the eldestQueue nsCOMPtr will keep that object alive.
323 // Since it is thread-private, no one else can race with us here.
324 PR_ExitMonitor(mEventQMonitor);
325 if (!eldestQueue)
326 return NS_ERROR_FAILURE;
327
328#ifdef LOG_ENABLED
329 PLEventQueue *equeue;
330 aQueue->GetPLEventQueue(&equeue);
331 Log(("EventQueue: Service pop queue [queue=%lx]",(long)equeue));
332#endif
333 aQueue->StopAcceptingEvents();
334 aQueue->ProcessPendingEvents(); // make sure we don't orphan any events
335
336 return NS_OK;
337}
338
339NS_IMETHODIMP
340nsEventQueueServiceImpl::GetThreadEventQueue(PRThread* aThread, nsIEventQueue** aResult)
341{
342 /* Parameter validation... */
343 if (NULL == aResult) return NS_ERROR_NULL_POINTER;
344
345 PRThread* keyThread = aThread;
346
347 if (keyThread == NS_CURRENT_THREAD)
348 {
349 keyThread = PR_GetCurrentThread();
350 }
351 else if (keyThread == NS_UI_THREAD)
352 {
353 nsCOMPtr<nsIThread> mainIThread;
354
355 // Get the primordial thread
356 nsresult rv = nsIThread::GetMainThread(getter_AddRefs(mainIThread));
357 if (NS_FAILED(rv)) return rv;
358
359 rv = mainIThread->GetPRThread(&keyThread);
360 if (NS_FAILED(rv)) return rv;
361 }
362
363 /* Enter the lock that protects the EventQ hashtable... */
364 PR_EnterMonitor(mEventQMonitor);
365
366 nsCOMPtr<nsIEventQueue> queue;
367 mEventQTable.Get(keyThread, getter_AddRefs(queue));
368
369 PR_ExitMonitor(mEventQMonitor);
370
371 if (queue) {
372 GetYoungestEventQueue(queue, aResult); // get the youngest active queue
373 } else {
374 *aResult = nsnull;
375 }
376 // XXX: Need error code for requesting an event queue when none exists...
377 if (!*aResult) {
378 return NS_ERROR_NOT_AVAILABLE;
379 }
380 return NS_OK;
381}
382
383
384NS_IMETHODIMP
385nsEventQueueServiceImpl::ResolveEventQueue(nsIEventQueue* queueOrConstant, nsIEventQueue* *resultQueue)
386{
387 if (queueOrConstant == NS_CURRENT_EVENTQ) {
388 return GetThreadEventQueue(NS_CURRENT_THREAD, resultQueue);
389 }
390 else if (queueOrConstant == NS_UI_THREAD_EVENTQ) {
391 return GetThreadEventQueue(NS_UI_THREAD, resultQueue);
392 }
393
394 *resultQueue = queueOrConstant;
395 NS_ADDREF(*resultQueue);
396 return NS_OK;
397}
398
399NS_IMETHODIMP
400nsEventQueueServiceImpl::GetSpecialEventQueue(PRInt32 aQueue,
401 nsIEventQueue* *_retval)
402{
403 nsresult rv;
404
405 // barf if someone gave us a zero pointer
406 //
407 if (!_retval) {
408 return NS_ERROR_NULL_POINTER;
409 }
410
411 // try and get the requested event queue, returning NS_ERROR_FAILURE if there
412 // is a problem. GetThreadEventQueue() does the AddRef() for us.
413 //
414 switch (aQueue) {
415 case CURRENT_THREAD_EVENT_QUEUE:
416 rv = GetThreadEventQueue(NS_CURRENT_THREAD, _retval);
417 if (NS_FAILED(rv)) {
418 return NS_ERROR_FAILURE;
419 }
420 break;
421
422 case UI_THREAD_EVENT_QUEUE:
423 rv = GetThreadEventQueue(NS_UI_THREAD, _retval);
424 if (NS_FAILED(rv)) {
425 return NS_ERROR_FAILURE;
426 }
427 break;
428
429 // somebody handed us a bogus constant
430 //
431 default:
432 return NS_ERROR_ILLEGAL_VALUE;
433 }
434
435 return NS_OK;
436}
437
Note: See TracBrowser for help on using the repository browser.

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