VirtualBox

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

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

libs/xpcom: Replace remaining APIs from prprf.h with IPRT equivalents, bugref:10545

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 15.3 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 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
35 *
36 * ***** END LICENSE BLOCK ***** */
37
38#include "nsCOMPtr.h"
39#include "nsEventQueue.h"
40#include "nsIEventQueueService.h"
41
42#include "nsIServiceManager.h"
43#include "nsIObserverService.h"
44
45#include "nsString.h"
46
47#ifdef NS_DEBUG
48#include <iprt/string.h>
49#endif
50
51#include <VBox/log.h>
52
53// in a real system, these would be members in a header class...
54static const char gActivatedNotification[] = "nsIEventQueueActivated";
55static const char gDestroyedNotification[] = "nsIEventQueueDestroyed";
56
57nsEventQueueImpl::nsEventQueueImpl()
58{
59 NS_ADDREF_THIS();
60 /* The slightly weird ownership model for eventqueues goes like this:
61
62 General:
63 There's an addref from the factory generally held by whoever asked for
64 the queue. The queue addrefs itself (right here) and releases itself
65 after someone calls StopAcceptingEvents() on the queue and when it is
66 dark and empty (in CheckForDeactivation()).
67
68 Chained queues:
69
70 Eldest queue:
71 The eldest queue in a chain is held on to by the EventQueueService
72 in a hash table, so it is possible that the eldest queue may not be
73 released until the EventQueueService is shutdown.
74 You may not call StopAcceptingEvents() on this queue until you have
75 done so on all younger queues.
76
77 General:
78 Each queue holds a reference to their immediate elder link and a weak
79 reference to their immediate younger link. Because you must shut down
80 queues from youngest to eldest, all the references will be removed.
81
82 It happens something like:
83 queue->StopAcceptingEvents()
84 {
85 CheckForDeactivation()
86 {
87 -- hopefully we are able to shutdown now --
88 Unlink()
89 {
90 -- remove the reference we hold to our elder queue --
91 -- NULL out our elder queues weak reference to us --
92 }
93 RELEASE ourself (to balance the ADDREF here in the constructor)
94 -- and we should go away. --
95 }
96 }
97
98
99 Notes:
100 A dark queue no longer accepts events. An empty queue simply has no events.
101 */
102
103 Log(("EventQueue: Created [queue=%lx]\n",(long)mEventQueue));
104
105 mYoungerQueue = nsnull;
106 mEventQueue = nsnull;
107 mAcceptingEvents = PR_TRUE;
108 mCouldHaveEvents = PR_TRUE;
109}
110
111nsEventQueueImpl::~nsEventQueueImpl()
112{
113 Unlink();
114
115 Log(("EventQueue: Destroyed [queue=%lx]\n",(long)mEventQueue));
116
117 if (mEventQueue) {
118 NotifyObservers(gDestroyedNotification);
119 PL_DestroyEventQueue(mEventQueue);
120 }
121}
122
123NS_IMETHODIMP
124nsEventQueueImpl::Init(PRBool aNative)
125{
126 RTTHREAD hThread = RTThreadSelf();
127 if (aNative)
128 mEventQueue = PL_CreateNativeEventQueue("Thread event queue...", hThread);
129 else
130 mEventQueue = PL_CreateMonitoredEventQueue("Thread event queue...", hThread);
131 NotifyObservers(gActivatedNotification);
132 return NS_OK;
133}
134
135NS_IMETHODIMP
136nsEventQueueImpl::InitFromPRThread(RTTHREAD hThread, PRBool aNative)
137{
138 if (hThread == NS_CURRENT_THREAD)
139 {
140 hThread = RTThreadSelf();
141 }
142 else if (hThread == NS_UI_THREAD)
143 {
144 // Get the primordial thread
145 nsresult rv = NS_GetMainThread(&hThread);
146 if (NS_FAILED(rv)) return rv;
147 }
148
149 if (aNative)
150 mEventQueue = PL_CreateNativeEventQueue("Thread event queue...", hThread);
151 else
152 mEventQueue = PL_CreateMonitoredEventQueue("Thread event queue...", hThread);
153 NotifyObservers(gActivatedNotification);
154 return NS_OK;
155}
156
157NS_IMETHODIMP
158nsEventQueueImpl::InitFromPLQueue(PLEventQueue* aQueue)
159{
160 mEventQueue = aQueue;
161 NotifyObservers(gActivatedNotification);
162 return NS_OK;
163}
164
165/* nsISupports interface implementation... */
166NS_IMPL_THREADSAFE_ISUPPORTS3(nsEventQueueImpl,
167 nsIEventQueue,
168 nsIEventTarget,
169 nsPIEventQueueChain)
170
171/* nsIEventQueue interface implementation... */
172
173NS_IMETHODIMP
174nsEventQueueImpl::StopAcceptingEvents()
175{
176 // this assertion is bogus. I should be able to shut down the eldest queue,
177 // as long as there are no younger children
178
179
180 NS_ASSERTION(mElderQueue || !mYoungerQueue, "attempted to disable eldest queue in chain");
181 mAcceptingEvents = PR_FALSE;
182 CheckForDeactivation();
183
184 Log(("EventQueue: StopAccepting [queue=%lx, accept=%d, could=%d]\n",
185 (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
186 return NS_OK;
187}
188
189// utility funtion to send observers a notification
190void
191nsEventQueueImpl::NotifyObservers(const char *aTopic)
192{
193 nsresult rv;
194
195 nsCOMPtr<nsIObserverService> os = do_GetService("@mozilla.org/observer-service;1", &rv);
196 if (NS_SUCCEEDED(rv)) {
197 nsCOMPtr<nsIEventQueue> kungFuDeathGrip(this);
198 nsCOMPtr<nsISupports> us(do_QueryInterface(kungFuDeathGrip));
199 os->NotifyObservers(us, aTopic, NULL);
200 }
201}
202
203
204NS_IMETHODIMP
205nsEventQueueImpl::InitEvent(PLEvent* aEvent,
206 void* owner,
207 PLHandleEventProc handler,
208 PLDestroyEventProc destructor)
209{
210 PL_InitEvent(aEvent, owner, handler, destructor);
211 return NS_OK;
212}
213
214
215NS_IMETHODIMP
216nsEventQueueImpl::PostEvent(PLEvent* aEvent)
217{
218 if (!mAcceptingEvents) {
219
220 Log(("EventQueue: Punt posted event [queue=%lx, accept=%d, could=%d]\n",
221 (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
222
223 nsresult rv = NS_ERROR_FAILURE;
224 NS_ASSERTION(mElderQueue, "event dropped because event chain is dead");
225 if (mElderQueue) {
226 nsCOMPtr<nsIEventQueue> elder(do_QueryInterface(mElderQueue));
227 if (elder)
228 rv = elder->PostEvent(aEvent);
229 }
230 return rv;
231 }
232
233 Log(("EventQueue: Posting event [queue=%lx]\n", (long)mEventQueue));
234 return PL_PostEvent(mEventQueue, aEvent) == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE;
235}
236
237NS_IMETHODIMP
238nsEventQueueImpl::PostSynchronousEvent(PLEvent* aEvent, void** aResult)
239{
240 if (!mAcceptingEvents) {
241 Log(("EventQueue: Punt posted synchronous event [queue=%lx, accept=%d, could=%d]\n",
242 (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
243
244 nsresult rv = NS_ERROR_NO_INTERFACE;
245 NS_ASSERTION(mElderQueue, "event dropped because event chain is dead");
246 if (mElderQueue) {
247 nsCOMPtr<nsIEventQueue> elder(do_QueryInterface(mElderQueue));
248 if (elder)
249 rv = elder->PostSynchronousEvent(aEvent, aResult);
250 return rv;
251 }
252 return NS_ERROR_ABORT;
253 }
254
255 Log(("EventQueue: Posting synchronous event [queue=%lx]\n", (long)mEventQueue));
256 void* result = PL_PostSynchronousEvent(mEventQueue, aEvent);
257 if (aResult)
258 *aResult = result;
259
260 return NS_OK;
261}
262
263NS_IMETHODIMP
264nsEventQueueImpl::EnterMonitor()
265{
266 PL_ENTER_EVENT_QUEUE_MONITOR(mEventQueue);
267 return NS_OK;
268}
269
270NS_IMETHODIMP
271nsEventQueueImpl::ExitMonitor()
272{
273 PL_EXIT_EVENT_QUEUE_MONITOR(mEventQueue);
274 return NS_OK;
275}
276
277
278NS_IMETHODIMP
279nsEventQueueImpl::RevokeEvents(void* owner)
280{
281 PL_RevokeEvents(mEventQueue, owner);
282 if (mElderQueue) {
283 nsCOMPtr<nsIEventQueue> elder(do_QueryInterface(mElderQueue));
284 if (elder)
285 elder->RevokeEvents(owner);
286 }
287 return NS_OK;
288}
289
290
291NS_IMETHODIMP
292nsEventQueueImpl::GetPLEventQueue(PLEventQueue** aEventQueue)
293{
294 if (!mEventQueue)
295 return NS_ERROR_NULL_POINTER;
296
297 *aEventQueue = mEventQueue;
298 return NS_OK;
299}
300
301NS_IMETHODIMP
302nsEventQueueImpl::IsOnCurrentThread(PRBool *aResult)
303{
304 *aResult = PL_IsQueueOnCurrentThread( mEventQueue );
305 return NS_OK;
306}
307
308
309NS_IMETHODIMP
310nsEventQueueImpl::IsQueueNative(PRBool *aResult)
311{
312 *aResult = PL_IsQueueNative(mEventQueue);
313 return NS_OK;
314}
315
316NS_IMETHODIMP
317nsEventQueueImpl::PendingEvents(PRBool *aResult)
318{
319 *aResult = PL_EventAvailable(mEventQueue);
320 if (!*aResult && mElderQueue) {
321 nsCOMPtr<nsIEventQueue> elder(do_QueryInterface(mElderQueue));
322 if (elder)
323 return elder->EventAvailable(*aResult);
324 }
325 return NS_OK;
326}
327
328
329NS_IMETHODIMP
330nsEventQueueImpl::ProcessPendingEvents()
331{
332 PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue);
333
334 NS_ASSERTION(correctThread, "attemping to process events on the wrong thread");
335
336 if (!correctThread)
337 return NS_ERROR_FAILURE;
338
339 Log(("EventQueue: Process pending [queue=%lx, accept=%d, could=%d]\n",
340 (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
341 PL_ProcessPendingEvents(mEventQueue);
342
343 // if we're no longer accepting events and there are still events in the
344 // queue, then process remaining events.
345 if (!mAcceptingEvents && PL_EventAvailable(mEventQueue))
346 PL_ProcessPendingEvents(mEventQueue);
347
348 CheckForDeactivation();
349
350 if (mElderQueue) {
351 nsCOMPtr<nsIEventQueue> elder(do_QueryInterface(mElderQueue));
352 if (elder)
353 elder->ProcessPendingEvents();
354 }
355
356 return NS_OK;
357}
358
359NS_IMETHODIMP
360nsEventQueueImpl::EventLoop()
361{
362 PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue);
363
364 NS_ASSERTION(correctThread, "attemping to process events on the wrong thread");
365
366 if (!correctThread)
367 return NS_ERROR_FAILURE;
368
369 PL_EventLoop(mEventQueue);
370 return NS_OK;
371}
372
373NS_IMETHODIMP
374nsEventQueueImpl::EventAvailable(PRBool& aResult)
375{
376 aResult = PL_EventAvailable(mEventQueue);
377 return NS_OK;
378}
379
380NS_IMETHODIMP
381nsEventQueueImpl::GetEvent(PLEvent** aResult)
382{
383 *aResult = PL_GetEvent(mEventQueue);
384 CheckForDeactivation();
385 return NS_OK;
386}
387
388NS_IMETHODIMP
389nsEventQueueImpl::HandleEvent(PLEvent* aEvent)
390{
391 PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue);
392 NS_ASSERTION(correctThread, "attemping to process events on the wrong thread");
393 if (!correctThread)
394 return NS_ERROR_FAILURE;
395
396 Log(("EventQueue: handle event [queue=%lx, accept=%d, could=%d]\n",
397 (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
398
399 PL_HandleEvent(aEvent);
400 return NS_OK;
401}
402
403NS_IMETHODIMP
404nsEventQueueImpl::WaitForEvent(PLEvent** aResult)
405{
406 PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue);
407 NS_ASSERTION(correctThread, "attemping to process events on the wrong thread");
408 if (!correctThread)
409 return NS_ERROR_FAILURE;
410
411 Log(("EventQueue: wait for event [queue=%lx, accept=%d, could=%d]\n",
412 (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents));
413
414 *aResult = PL_WaitForEvent(mEventQueue);
415 CheckForDeactivation();
416 return NS_OK;
417}
418
419NS_IMETHODIMP_(PRInt32)
420nsEventQueueImpl::GetEventQueueSelectFD()
421{
422 return PL_GetEventQueueSelectFD(mEventQueue);
423}
424
425NS_METHOD
426nsEventQueueImpl::Create(nsISupports *aOuter,
427 REFNSIID aIID,
428 void **aResult)
429{
430 nsEventQueueImpl* evt = new nsEventQueueImpl();
431 if (evt == NULL)
432 return NS_ERROR_OUT_OF_MEMORY;
433 nsresult rv = evt->QueryInterface(aIID, aResult);
434 if (NS_FAILED(rv)) {
435 delete evt;
436 }
437 return rv;
438}
439
440// ---------------- nsPIEventQueueChain -----------------
441
442NS_IMETHODIMP
443nsEventQueueImpl::AppendQueue(nsIEventQueue *aQueue)
444{
445 nsresult rv;
446 nsCOMPtr<nsIEventQueue> end;
447 nsCOMPtr<nsPIEventQueueChain> queueChain(do_QueryInterface(aQueue));
448
449 if (!aQueue)
450 return NS_ERROR_NO_INTERFACE;
451
452/* this would be nice
453 NS_ASSERTION(aQueue->mYoungerQueue == NULL && aQueue->mElderQueue == NULL,
454 "event queue repeatedly appended to queue chain");
455*/
456 rv = NS_ERROR_NO_INTERFACE;
457
458#ifdef NS_DEBUG
459 int depth = 0;
460 nsEventQueueImpl *next = this;
461 while (next && depth < 100) {
462 next = NS_STATIC_CAST(nsEventQueueImpl *, next->mYoungerQueue);
463 ++depth;
464 }
465 if (depth > 5) {
466 char warning[80];
467 RTStrPrintf2(warning, sizeof(warning),
468 "event queue chain length is %d. this is almost certainly a leak.", depth);
469 NS_WARNING(warning);
470 }
471#endif
472
473 // (be careful doing this outside nsEventQueueService's mEventQMonitor)
474
475 GetYoungest(getter_AddRefs(end));
476 nsCOMPtr<nsPIEventQueueChain> endChain(do_QueryInterface(end));
477 if (endChain) {
478 endChain->SetYounger(queueChain);
479 queueChain->SetElder(endChain);
480 rv = NS_OK;
481 }
482 return rv;
483}
484
485NS_IMETHODIMP
486nsEventQueueImpl::Unlink()
487{
488 nsCOMPtr<nsPIEventQueueChain> young = mYoungerQueue,
489 old = mElderQueue;
490
491 Log(("EventQueue: unlink [queue=%lx, younger=%lx, elder=%lx]\n",
492 (long)mEventQueue,(long)mYoungerQueue, (long)mElderQueue.get()));
493
494 // this is probably OK, but shouldn't happen by design, so tell me if it does
495 NS_ASSERTION(!mYoungerQueue, "event queue chain broken in middle");
496
497 // break links early in case the Release cascades back onto us
498 mYoungerQueue = nsnull;
499 mElderQueue = nsnull;
500
501 if (young)
502 young->SetElder(old);
503 if (old) {
504 old->SetYounger(young);
505 }
506 return NS_OK;
507}
508
509NS_IMETHODIMP
510nsEventQueueImpl::GetYoungest(nsIEventQueue **aQueue)
511{
512 if (mYoungerQueue)
513 return mYoungerQueue->GetYoungest(aQueue);
514
515 nsIEventQueue *answer = NS_STATIC_CAST(nsIEventQueue *, this);
516 NS_ADDREF(answer);
517 *aQueue = answer;
518 return NS_OK;
519}
520
521NS_IMETHODIMP
522nsEventQueueImpl::GetYoungestActive(nsIEventQueue **aQueue)
523{
524 nsCOMPtr<nsIEventQueue> answer;
525
526 if (mYoungerQueue)
527 mYoungerQueue->GetYoungestActive(getter_AddRefs(answer));
528 if (!answer) {
529 if (mAcceptingEvents && mCouldHaveEvents)
530 answer = NS_STATIC_CAST(nsIEventQueue *, this);
531 }
532 *aQueue = answer;
533 NS_IF_ADDREF(*aQueue);
534 return NS_OK;
535}
536
537NS_IMETHODIMP
538nsEventQueueImpl::SetYounger(nsPIEventQueueChain *aQueue)
539{
540 mYoungerQueue = aQueue;
541 return NS_OK;
542}
543
544NS_IMETHODIMP
545nsEventQueueImpl::SetElder(nsPIEventQueueChain *aQueue)
546{
547 mElderQueue = aQueue;
548 return NS_OK;
549}
550
551NS_IMETHODIMP
552nsEventQueueImpl::GetYounger(nsIEventQueue **aQueue)
553{
554 if (!mYoungerQueue) {
555 *aQueue = nsnull;
556 return NS_OK;
557 }
558 return mYoungerQueue->QueryInterface(NS_GET_IID(nsIEventQueue), (void**)&aQueue);
559}
560
561NS_IMETHODIMP
562nsEventQueueImpl::GetElder(nsIEventQueue **aQueue)
563{
564 if (!mElderQueue) {
565 *aQueue = nsnull;
566 return NS_OK;
567 }
568 return mElderQueue->QueryInterface(NS_GET_IID(nsIEventQueue), (void**)&aQueue);
569}
570
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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