VirtualBox

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

最後變更 在這個檔案從103140是 102057,由 vboxsync 提交於 15 月 前

libs/xpcom: Convert nsEventQueueService to use a IPRT fast mutex instead of a PRMonitor, bugref:10545

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

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