VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/threads/plevent.c@ 103140

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

libs/xpcom: Convert the PR_Wait() function to take the timeout in milliseconds and get rid of PR_Interval* and use RTTime*, bugref:10545 [2nd attempt]

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 25.8 KB
 
1/* -*- Mode: C++; tab-width: 4; 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.org 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 "nspr.h"
39#include "plevent.h"
40
41#include <errno.h>
42#include <stddef.h>
43#include <unistd.h>
44/* for fcntl */
45#include <sys/types.h>
46#include <fcntl.h>
47
48#if defined(XP_MACOSX)
49# include <CoreFoundation/CoreFoundation.h>
50#endif
51
52#include <iprt/assert.h>
53#include <iprt/errcore.h>
54#include <VBox/log.h>
55
56/*******************************************************************************
57 * Private Stuff
58 ******************************************************************************/
59
60/*
61** EventQueueType -- Defines notification type for an event queue
62**
63*/
64typedef enum {
65 EventQueueIsNative = 1,
66 EventQueueIsMonitored = 2
67} EventQueueType;
68
69
70struct PLEventQueue {
71 const char* name;
72 RTLISTANCHOR queue;
73 PRMonitor* monitor;
74 RTTHREAD handlerThread;
75 EventQueueType type;
76 PRPackedBool processingEvents;
77 PRPackedBool notified;
78
79#if defined(XP_UNIX) && !defined(XP_MACOSX)
80 PRInt32 eventPipe[2];
81 PLGetEventIDFunc idFunc;
82 void* idFuncClosure;
83#elif defined(XP_MACOSX)
84 CFRunLoopSourceRef mRunLoopSource;
85 CFRunLoopRef mMainRunLoop;
86 CFStringRef mRunLoopModeStr; /* vbox */
87#endif
88};
89
90#define PR_EVENT_PTR(_qp) \
91 ((PLEvent*) ((char*) (_qp) - offsetof(PLEvent, link)))
92
93static PRStatus _pl_SetupNativeNotifier(PLEventQueue* self);
94static void _pl_CleanupNativeNotifier(PLEventQueue* self);
95static PRStatus _pl_NativeNotify(PLEventQueue* self);
96static PRStatus _pl_AcknowledgeNativeNotify(PLEventQueue* self);
97static void _md_CreateEventQueue( PLEventQueue *eventQueue );
98static PRInt32 _pl_GetEventCount(PLEventQueue* self);
99
100
101/*******************************************************************************
102 * Event Queue Operations
103 ******************************************************************************/
104
105/*
106** _pl_CreateEventQueue() -- Create the event queue
107**
108**
109*/
110static PLEventQueue * _pl_CreateEventQueue(const char *name,
111 RTTHREAD handlerThread,
112 EventQueueType qtype)
113{
114 PRStatus err;
115 PLEventQueue* self = NULL;
116 PRMonitor* mon = NULL;
117
118 self = PR_NEWZAP(PLEventQueue);
119 if (self == NULL) return NULL;
120
121 mon = PR_NewNamedMonitor(name);
122 if (mon == NULL) goto error;
123
124 self->name = name;
125 self->monitor = mon;
126 self->handlerThread = handlerThread;
127 self->processingEvents = PR_FALSE;
128 self->type = qtype;
129 self->notified = PR_FALSE;
130
131 RTListInit(&self->queue);
132 if ( qtype == EventQueueIsNative ) {
133 err = _pl_SetupNativeNotifier(self);
134 if (err) goto error;
135 _md_CreateEventQueue( self );
136 }
137 return self;
138
139 error:
140 if (mon != NULL)
141 PR_DestroyMonitor(mon);
142 PR_DELETE(self);
143 return NULL;
144}
145
146PR_IMPLEMENT(PLEventQueue*)
147PL_CreateEventQueue(const char* name, RTTHREAD handlerThread)
148{
149 return( _pl_CreateEventQueue( name, handlerThread, EventQueueIsNative ));
150}
151
152PR_EXTERN(PLEventQueue *)
153PL_CreateNativeEventQueue(const char *name, RTTHREAD handlerThread)
154{
155 return( _pl_CreateEventQueue( name, handlerThread, EventQueueIsNative ));
156}
157
158PR_EXTERN(PLEventQueue *)
159PL_CreateMonitoredEventQueue(const char *name, RTTHREAD handlerThread)
160{
161 return( _pl_CreateEventQueue( name, handlerThread, EventQueueIsMonitored ));
162}
163
164PR_IMPLEMENT(PRMonitor*)
165PL_GetEventQueueMonitor(PLEventQueue* self)
166{
167 return self->monitor;
168}
169
170static void PR_CALLBACK
171_pl_destroyEvent(PLEvent* event, void* data, PLEventQueue* queue)
172{
173 PL_DequeueEvent(event, queue);
174 PL_DestroyEvent(event);
175}
176
177PR_IMPLEMENT(void)
178PL_DestroyEventQueue(PLEventQueue* self)
179{
180 PR_EnterMonitor(self->monitor);
181
182 /* destroy undelivered events */
183 PL_MapEvents(self, _pl_destroyEvent, NULL);
184
185 if ( self->type == EventQueueIsNative )
186 _pl_CleanupNativeNotifier(self);
187
188 /* destroying the monitor also destroys the name */
189 PR_ExitMonitor(self->monitor);
190 PR_DestroyMonitor(self->monitor);
191 PR_DELETE(self);
192
193}
194
195PR_IMPLEMENT(PRStatus)
196PL_PostEvent(PLEventQueue* self, PLEvent* event)
197{
198 PRStatus err = PR_SUCCESS;
199 PRMonitor* mon;
200
201 if (self == NULL)
202 return PR_FAILURE;
203
204 mon = self->monitor;
205 PR_EnterMonitor(mon);
206
207#if defined(XP_UNIX) && !defined(XP_MACOSX)
208 if (self->idFunc && event)
209 event->id = self->idFunc(self->idFuncClosure);
210#endif
211
212 /* insert event into thread's event queue: */
213 if (event != NULL) {
214 RTListAppend(&self->queue, &event->link);
215 }
216
217 if (self->type == EventQueueIsNative && !self->notified) {
218 err = _pl_NativeNotify(self);
219
220 if (err != PR_SUCCESS)
221 goto error;
222
223 self->notified = PR_TRUE;
224 }
225
226 /*
227 * This may fall on deaf ears if we're really notifying the native
228 * thread, and no one has called PL_WaitForEvent (or PL_EventLoop):
229 */
230 err = PR_Notify(mon);
231
232error:
233 PR_ExitMonitor(mon);
234 return err;
235}
236
237PR_IMPLEMENT(void*)
238PL_PostSynchronousEvent(PLEventQueue* self, PLEvent* event)
239{
240 void* result;
241
242 if (self == NULL)
243 return NULL;
244
245 Assert(event != NULL);
246
247 if (RTThreadSelf() == self->handlerThread) {
248 /* Handle the case where the thread requesting the event handling
249 * is also the thread that's supposed to do the handling. */
250 result = event->handler(event);
251 }
252 else {
253 int i, entryCount;
254
255 int vrc = RTCritSectInit(&event->lock);
256 if (RT_FAILURE(vrc)) {
257 return NULL;
258 }
259
260 vrc = RTSemEventCreate(&event->condVar);
261 if(RT_FAILURE(vrc))
262 {
263 RTCritSectDelete(&event->lock);
264 return NULL;
265 }
266
267 RTCritSectEnter(&event->lock);
268
269 entryCount = PR_GetMonitorEntryCount(self->monitor);
270
271 event->synchronousResult = (void*)PR_TRUE;
272
273 PL_PostEvent(self, event);
274
275 /* We need temporarily to give up our event queue monitor if
276 we're holding it, otherwise, the thread we're going to wait
277 for notification from won't be able to enter it to process
278 the event. */
279 if (entryCount) {
280 for (i = 0; i < entryCount; i++)
281 PR_ExitMonitor(self->monitor);
282 }
283
284 event->handled = PR_FALSE;
285
286 while (!event->handled) {
287 /* wait for event to be handled or destroyed */
288 RTCritSectLeave(&event->lock);
289 RTSemEventWait(event->condVar, RT_INDEFINITE_WAIT);
290 RTCritSectEnter(&event->lock);
291 }
292
293 if (entryCount) {
294 for (i = 0; i < entryCount; i++)
295 PR_EnterMonitor(self->monitor);
296 }
297
298 result = event->synchronousResult;
299 event->synchronousResult = NULL;
300 RTCritSectLeave(&event->lock);
301 }
302
303 /* For synchronous events, they're destroyed here on the caller's
304 thread before the result is returned. See PL_HandleEvent. */
305 PL_DestroyEvent(event);
306
307 return result;
308}
309
310PR_IMPLEMENT(PLEvent*)
311PL_GetEvent(PLEventQueue* self)
312{
313 PLEvent* event = NULL;
314 PRStatus err = PR_SUCCESS;
315
316 if (self == NULL)
317 return NULL;
318
319 PR_EnterMonitor(self->monitor);
320
321 if (!RTListIsEmpty(&self->queue)) {
322 if ( self->type == EventQueueIsNative &&
323 self->notified &&
324 !self->processingEvents &&
325 0 == _pl_GetEventCount(self) )
326 {
327 err = _pl_AcknowledgeNativeNotify(self);
328 self->notified = PR_FALSE;
329 }
330 if (err)
331 goto done;
332
333 /* then grab the event and return it: */
334 event = RTListGetFirst(&self->queue, PLEvent, link);
335 RTListNodeRemove(&event->link);
336 RTListInit(&event->link);
337 }
338
339 done:
340 PR_ExitMonitor(self->monitor);
341 return event;
342}
343
344PR_IMPLEMENT(PRBool)
345PL_EventAvailable(PLEventQueue* self)
346{
347 PRBool result = PR_FALSE;
348
349 if (self == NULL)
350 return PR_FALSE;
351
352 PR_EnterMonitor(self->monitor);
353
354 if (!RTListIsEmpty(&self->queue))
355 result = PR_TRUE;
356
357 PR_ExitMonitor(self->monitor);
358 return result;
359}
360
361PR_IMPLEMENT(void)
362PL_MapEvents(PLEventQueue* self, PLEventFunProc fun, void* data)
363{
364 if (self == NULL)
365 return;
366
367 PR_EnterMonitor(self->monitor);
368 PLEvent *pIt, *pItNext;
369 RTListForEachSafe(&self->queue, pIt, pItNext, PLEvent, link)
370 {
371 (*fun)(pIt, data, self);
372 }
373 PR_ExitMonitor(self->monitor);
374}
375
376static void PR_CALLBACK
377_pl_DestroyEventForOwner(PLEvent* event, void* owner, PLEventQueue* queue)
378{
379 Assert(PR_GetMonitorEntryCount(queue->monitor) > 0);
380 if (event->owner == owner) {
381 Log(("$$$ \tdestroying event %0x for owner %0x", event, owner));
382 PL_DequeueEvent(event, queue);
383
384 if (event->synchronousResult == (void*)PR_TRUE) {
385 RTCritSectEnter(&event->lock);
386 event->synchronousResult = NULL;
387 event->handled = PR_TRUE;
388 RTSemEventSignal(event->condVar);
389 RTCritSectLeave(&event->lock);
390 }
391 else {
392 PL_DestroyEvent(event);
393 }
394 }
395 else {
396 Log(("$$$ \tskipping event %0x for owner %0x", event, owner));
397 }
398}
399
400PR_IMPLEMENT(void)
401PL_RevokeEvents(PLEventQueue* self, void* owner)
402{
403 if (self == NULL)
404 return;
405
406 Log(("$$$ revoking events for owner %0x", owner));
407
408 /*
409 ** First we enter the monitor so that no one else can post any events
410 ** to the queue:
411 */
412 PR_EnterMonitor(self->monitor);
413 Log(("$$$ owner %0x, entered monitor", owner));
414
415 /*
416 ** Discard any pending events for this owner:
417 */
418 PL_MapEvents(self, _pl_DestroyEventForOwner, owner);
419
420#ifdef DEBUG
421 {
422 PLEvent *pIt;
423 RTListForEach(&self->queue, pIt, PLEvent, link)
424 {
425 Assert(pIt->owner != owner);
426 }
427 }
428#endif /* DEBUG */
429
430 PR_ExitMonitor(self->monitor);
431
432 Log(("$$$ revoking events for owner %0x", owner));
433}
434
435static PRInt32
436_pl_GetEventCount(PLEventQueue* self)
437{
438 PRInt32 count = 0;
439
440 PR_EnterMonitor(self->monitor);
441 PLEvent *pIt;
442 RTListForEach(&self->queue, pIt, PLEvent, link)
443 {
444 count++;
445 }
446 PR_ExitMonitor(self->monitor);
447
448 return count;
449}
450
451PR_IMPLEMENT(void)
452PL_ProcessPendingEvents(PLEventQueue* self)
453{
454 PRInt32 count;
455
456 if (self == NULL)
457 return;
458
459
460 PR_EnterMonitor(self->monitor);
461
462 if (self->processingEvents) {
463 _pl_AcknowledgeNativeNotify(self);
464 self->notified = PR_FALSE;
465 PR_ExitMonitor(self->monitor);
466 return;
467 }
468 self->processingEvents = PR_TRUE;
469
470 /* Only process the events that are already in the queue, and
471 * not any new events that get added. Do this by counting the
472 * number of events currently in the queue
473 */
474 count = _pl_GetEventCount(self);
475 PR_ExitMonitor(self->monitor);
476
477 while (count-- > 0) {
478 PLEvent* event = PL_GetEvent(self);
479 if (event == NULL)
480 break;
481
482 Log(("$$$ processing event"));
483 PL_HandleEvent(event);
484 Log(("$$$ done processing event"));
485 }
486
487 PR_EnterMonitor(self->monitor);
488
489 if (self->type == EventQueueIsNative) {
490 count = _pl_GetEventCount(self);
491
492 if (count <= 0) {
493 _pl_AcknowledgeNativeNotify(self);
494 self->notified = PR_FALSE;
495 }
496 else {
497 _pl_NativeNotify(self);
498 self->notified = PR_TRUE;
499 }
500
501 }
502 self->processingEvents = PR_FALSE;
503
504 PR_ExitMonitor(self->monitor);
505}
506
507/*******************************************************************************
508 * Event Operations
509 ******************************************************************************/
510
511PR_IMPLEMENT(void)
512PL_InitEvent(PLEvent* self, void* owner,
513 PLHandleEventProc handler,
514 PLDestroyEventProc destructor)
515{
516 RTListInit(&self->link);
517 self->handler = handler;
518 self->destructor = destructor;
519 self->owner = owner;
520 self->synchronousResult = NULL;
521 self->handled = PR_FALSE;
522 self->condVar = NIL_RTSEMEVENT;
523#if defined(XP_UNIX) && !defined(XP_MACOSX)
524 self->id = 0;
525#endif
526}
527
528PR_IMPLEMENT(void*)
529PL_GetEventOwner(PLEvent* self)
530{
531 return self->owner;
532}
533
534PR_IMPLEMENT(void)
535PL_HandleEvent(PLEvent* self)
536{
537 void* result;
538 if (self == NULL)
539 return;
540
541 /* This event better not be on an event queue anymore. */
542 Assert(RTListIsEmpty(&self->link));
543
544 result = self->handler(self);
545 if (NULL != self->synchronousResult) {
546 RTCritSectEnter(&self->lock);
547 self->synchronousResult = result;
548 self->handled = PR_TRUE;
549 RTSemEventSignal(self->condVar);
550 RTCritSectLeave(&self->lock);
551 }
552 else {
553 /* For asynchronous events, they're destroyed by the event-handler
554 thread. See PR_PostSynchronousEvent. */
555 PL_DestroyEvent(self);
556 }
557}
558
559PR_IMPLEMENT(void)
560PL_DestroyEvent(PLEvent* self)
561{
562 if (self == NULL)
563 return;
564
565 /* This event better not be on an event queue anymore. */
566 Assert(RTListIsEmpty(&self->link));
567
568 if(self->condVar != NIL_RTSEMEVENT)
569 RTSemEventDestroy(self->condVar);
570 if(RTCritSectIsInitialized(&self->lock))
571 RTCritSectDelete(&self->lock);
572
573 self->destructor(self);
574}
575
576PR_IMPLEMENT(void)
577PL_DequeueEvent(PLEvent* self, PLEventQueue* queue)
578{
579 if (self == NULL)
580 return;
581
582 /* Only the owner is allowed to dequeue events because once the
583 client has put it in the queue, they have no idea whether it's
584 been processed and destroyed or not. */
585
586 Assert(queue->handlerThread == RTThreadSelf());
587
588 PR_EnterMonitor(queue->monitor);
589
590 Assert(!RTListIsEmpty(&self->link));
591
592#if 0
593 /* I do not think that we need to do this anymore.
594 if we do not acknowledge and this is the only
595 only event in the queue, any calls to process
596 the eventQ will be effective noop.
597 */
598 if (queue->type == EventQueueIsNative)
599 _pl_AcknowledgeNativeNotify(queue);
600#endif
601
602 RTListNodeRemove(&self->link);
603 RTListInit(&self->link);
604
605 PR_ExitMonitor(queue->monitor);
606}
607
608PR_IMPLEMENT(void)
609PL_FavorPerformanceHint(PRBool favorPerformanceOverEventStarvation,
610 PRUint32 starvationDelay)
611{
612}
613
614/*******************************************************************************
615 * Pure Event Queues
616 *
617 * For when you're only processing PLEvents and there is no native
618 * select, thread messages, or AppleEvents.
619 ******************************************************************************/
620
621PR_IMPLEMENT(PLEvent*)
622PL_WaitForEvent(PLEventQueue* self)
623{
624 PLEvent* event;
625 PRMonitor* mon;
626
627 if (self == NULL)
628 return NULL;
629
630 mon = self->monitor;
631 PR_EnterMonitor(mon);
632
633 while ((event = PL_GetEvent(self)) == NULL) {
634 PRStatus err;
635 Log(("$$$ waiting for event"));
636 err = PR_Wait(mon, RT_INDEFINITE_WAIT);
637 }
638
639 PR_ExitMonitor(mon);
640 return event;
641}
642
643PR_IMPLEMENT(void)
644PL_EventLoop(PLEventQueue* self)
645{
646 if (self == NULL)
647 return;
648
649 while (PR_TRUE) {
650 PLEvent* event = PL_WaitForEvent(self);
651 if (event == NULL) {
652 /* This can only happen if the current thread is interrupted */
653 return;
654 }
655
656 Log(("$$$ processing event"));
657 PL_HandleEvent(event);
658 Log(("$$$ done processing event"));
659 }
660}
661
662/*******************************************************************************
663 * Native Event Queues
664 *
665 * For when you need to call select, or WaitNextEvent, and yet also want
666 * to handle PLEvents.
667 ******************************************************************************/
668
669static PRStatus
670_pl_SetupNativeNotifier(PLEventQueue* self)
671{
672#if defined(XP_UNIX) && !defined(XP_MACOSX)
673 int err;
674 int flags;
675
676 self->idFunc = 0;
677 self->idFuncClosure = 0;
678
679 err = pipe(self->eventPipe);
680 if (err != 0) {
681 return PR_FAILURE;
682 }
683#ifdef VBOX
684 fcntl(self->eventPipe[0], F_SETFD, FD_CLOEXEC);
685 fcntl(self->eventPipe[1], F_SETFD, FD_CLOEXEC);
686#endif
687
688 /* make the pipe nonblocking */
689 flags = fcntl(self->eventPipe[0], F_GETFL, 0);
690 if (flags == -1) {
691 goto failed;
692 }
693 err = fcntl(self->eventPipe[0], F_SETFL, flags | O_NONBLOCK);
694 if (err == -1) {
695 goto failed;
696 }
697 flags = fcntl(self->eventPipe[1], F_GETFL, 0);
698 if (flags == -1) {
699 goto failed;
700 }
701 err = fcntl(self->eventPipe[1], F_SETFL, flags | O_NONBLOCK);
702 if (err == -1) {
703 goto failed;
704 }
705 return PR_SUCCESS;
706
707failed:
708 close(self->eventPipe[0]);
709 close(self->eventPipe[1]);
710 return PR_FAILURE;
711#else
712 return PR_SUCCESS;
713#endif
714}
715
716static void
717_pl_CleanupNativeNotifier(PLEventQueue* self)
718{
719#if defined(XP_UNIX) && !defined(XP_MACOSX)
720 close(self->eventPipe[0]);
721 close(self->eventPipe[1]);
722#elif defined(MAC_USE_CFRUNLOOPSOURCE)
723
724 CFRunLoopRemoveSource(self->mMainRunLoop, self->mRunLoopSource, kCFRunLoopCommonModes);
725 CFRunLoopRemoveSource(self->mMainRunLoop, self->mRunLoopSource, self->mRunLoopModeStr); /* vbox */
726 CFRelease(self->mRunLoopSource);
727 CFRelease(self->mMainRunLoop);
728 CFRelease(self->mRunLoopModeStr); /* vbox */
729#endif
730}
731
732#if defined(XP_UNIX) && !defined(XP_MACOSX)
733
734static PRStatus
735_pl_NativeNotify(PLEventQueue* self)
736{
737#define NOTIFY_TOKEN 0xFA
738 PRInt32 count;
739 unsigned char buf[] = { NOTIFY_TOKEN };
740
741# ifdef VBOX
742 /* Don't write two chars, because we'll only acknowledge one and that'll
743 cause trouble for anyone selecting/polling on the read descriptor. */
744 if (self->notified)
745 return PR_SUCCESS;
746# endif
747
748 Log(("_pl_NativeNotify: self=%p", self));
749 count = write(self->eventPipe[1], buf, 1);
750 if (count == 1)
751 return PR_SUCCESS;
752 if (count == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
753 return PR_SUCCESS;
754 return PR_FAILURE;
755}/* --- end _pl_NativeNotify() --- */
756#endif /* defined(XP_UNIX) && !defined(XP_MACOSX) */
757
758#if defined(XP_MACOSX)
759static PRStatus
760_pl_NativeNotify(PLEventQueue* self)
761{
762 CFRunLoopSourceSignal(self->mRunLoopSource);
763 CFRunLoopWakeUp(self->mMainRunLoop);
764 return PR_SUCCESS;
765}
766#endif /* defined(XP_MACOSX) */
767
768static PRStatus
769_pl_AcknowledgeNativeNotify(PLEventQueue* self)
770{
771#if defined(XP_UNIX) && !defined(XP_MACOSX)
772
773 PRInt32 count;
774 unsigned char c;
775 Log(("_pl_AcknowledgeNativeNotify: self=%p", self));
776 /* consume the byte NativeNotify put in our pipe: */
777 count = read(self->eventPipe[0], &c, 1);
778 if ((count == 1) && (c == NOTIFY_TOKEN))
779 return PR_SUCCESS;
780 if ((count == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
781 return PR_SUCCESS;
782 return PR_FAILURE;
783#elif defined(XP_MACOSX) /* vbox */
784 /* vbox */
785 CFRunLoopRunInMode(self->mRunLoopModeStr, 0.0, 1); /* vbox */
786 return PR_SUCCESS; /* vbox */
787#else
788 /* nothing to do on the other platforms */
789 return PR_SUCCESS;
790#endif
791}
792
793PR_IMPLEMENT(PRInt32)
794PL_GetEventQueueSelectFD(PLEventQueue* self)
795{
796 if (self == NULL)
797 return -1;
798
799#if defined(XP_UNIX) && !defined(XP_MACOSX)
800 return self->eventPipe[0];
801#else
802 return -1; /* other platforms don't handle this (yet) */
803#endif
804}
805
806PR_IMPLEMENT(PRBool)
807PL_IsQueueOnCurrentThread( PLEventQueue *queue )
808{
809 return queue->handlerThread == RTThreadSelf();
810}
811
812PR_EXTERN(PRBool)
813PL_IsQueueNative(PLEventQueue *queue)
814{
815 return queue->type == EventQueueIsNative ? PR_TRUE : PR_FALSE;
816}
817
818#if defined(XP_UNIX) && !defined(XP_MACOSX)
819/*
820** _md_CreateEventQueue() -- ModelDependent initializer
821*/
822static void _md_CreateEventQueue( PLEventQueue *eventQueue )
823{
824 /* there's really nothing special to do here,
825 ** the guts of the unix stuff is in the setupnativenotify
826 ** and related functions.
827 */
828 return;
829} /* end _md_CreateEventQueue() */
830#endif /* defined(XP_UNIX) && !defined(XP_MACOSX) */
831
832static void _md_EventReceiverProc(void *info)
833{
834 PLEventQueue *queue = (PLEventQueue*)info;
835 PL_ProcessPendingEvents(queue);
836}
837
838#if defined(XP_MACOSX)
839static void _md_CreateEventQueue( PLEventQueue *eventQueue )
840{
841 CFRunLoopSourceContext sourceContext = { 0 };
842 sourceContext.version = 0;
843 sourceContext.info = (void*)eventQueue;
844 sourceContext.perform = _md_EventReceiverProc;
845
846 /* make a run loop source */
847 eventQueue->mRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0 /* order */, &sourceContext);
848 Assert(eventQueue->mRunLoopSource);
849
850 eventQueue->mMainRunLoop = CFRunLoopGetCurrent();
851 CFRetain(eventQueue->mMainRunLoop);
852
853 /* and add it to the run loop */
854 CFRunLoopAddSource(eventQueue->mMainRunLoop, eventQueue->mRunLoopSource, kCFRunLoopCommonModes);
855
856 /* Add it again but with a unique mode name so we can acknowledge it
857 without processing any other message sources. */
858 { /* vbox */
859 char szModeName[80]; /* vbox */
860 snprintf(szModeName, sizeof(szModeName), "VBoxXPCOMQueueMode-%p", eventQueue); /* vbox */
861 eventQueue->mRunLoopModeStr = CFStringCreateWithCString(kCFAllocatorDefault, /* vbox */
862 szModeName, kCFStringEncodingASCII); /* vbox */
863 CFRunLoopAddSource(eventQueue->mMainRunLoop, /* vbox */
864 eventQueue->mRunLoopSource, eventQueue->mRunLoopModeStr); /* vbox */
865 } /* vbox */
866} /* end _md_CreateEventQueue() */
867#endif /* defined(XP_MACOSX) */
868
869/* extra functions for unix */
870
871#if defined(XP_UNIX) && !defined(XP_MACOSX)
872
873PR_IMPLEMENT(PRInt32)
874PL_ProcessEventsBeforeID(PLEventQueue *aSelf, unsigned long aID)
875{
876 PRInt32 count = 0;
877 PRInt32 fullCount;
878
879 if (aSelf == NULL)
880 return -1;
881
882 PR_EnterMonitor(aSelf->monitor);
883
884 if (aSelf->processingEvents) {
885 PR_ExitMonitor(aSelf->monitor);
886 return 0;
887 }
888
889 aSelf->processingEvents = PR_TRUE;
890
891 /* Only process the events that are already in the queue, and
892 * not any new events that get added. Do this by counting the
893 * number of events currently in the queue
894 */
895 fullCount = _pl_GetEventCount(aSelf);
896 Log(("$$$ fullCount is %d id is %ld\n", fullCount, aID));
897
898 if (fullCount == 0) {
899 aSelf->processingEvents = PR_FALSE;
900 PR_ExitMonitor(aSelf->monitor);
901 return 0;
902 }
903
904 PR_ExitMonitor(aSelf->monitor);
905
906 while (fullCount-- > 0) {
907 /* peek at the next event */
908 PLEvent *event = RTListGetFirst(&aSelf->queue, PLEvent, link);
909 if (event == NULL)
910 break;
911 Log(("$$$ processing event %ld\n", event->id));
912 if (event->id >= aID) {
913 Log(("$$$ skipping event and breaking"));
914 break;
915 }
916
917 event = PL_GetEvent(aSelf);
918 PL_HandleEvent(event);
919 Log(("$$$ done processing event"));
920 count++;
921 }
922
923 PR_EnterMonitor(aSelf->monitor);
924
925 /* if full count still had items left then there's still items left
926 in the queue. Let the native notify token stay. */
927
928 if (aSelf->type == EventQueueIsNative) {
929 fullCount = _pl_GetEventCount(aSelf);
930
931 if (fullCount <= 0) {
932 _pl_AcknowledgeNativeNotify(aSelf);
933 aSelf->notified = PR_FALSE;
934 }
935 }
936
937 aSelf->processingEvents = PR_FALSE;
938
939 PR_ExitMonitor(aSelf->monitor);
940
941 return count;
942}
943
944PR_IMPLEMENT(void)
945PL_RegisterEventIDFunc(PLEventQueue *aSelf, PLGetEventIDFunc aFunc,
946 void *aClosure)
947{
948 aSelf->idFunc = aFunc;
949 aSelf->idFuncClosure = aClosure;
950}
951
952PR_IMPLEMENT(void)
953PL_UnregisterEventIDFunc(PLEventQueue *aSelf)
954{
955 aSelf->idFunc = 0;
956 aSelf->idFuncClosure = 0;
957}
958
959#endif /* defined(XP_UNIX) && !defined(XP_MACOSX) */
960
961/* --- end plevent.c --- */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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