VirtualBox

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

Last change on this file since 102030 was 102016, checked in by vboxsync, 17 months ago

libs/xpcom/xpcom: Convert nsEventQueueService,nsEventQueue and plevent from PRThread/nsIThread to IPRT's thread API, bugref:10545

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