VirtualBox

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

最後變更 在這個檔案從36233是 1,由 vboxsync 提交於 55 年 前

import

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

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