VirtualBox

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

Last change on this file since 106112 was 104486, checked in by vboxsync, 6 months ago

libs/xpcom: Some unused function/variable fixes, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.8 KB
Line 
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 Log(("$$$ waiting for event"));
635 PR_Wait(mon, RT_INDEFINITE_WAIT);
636 }
637
638 PR_ExitMonitor(mon);
639 return event;
640}
641
642PR_IMPLEMENT(void)
643PL_EventLoop(PLEventQueue* self)
644{
645 if (self == NULL)
646 return;
647
648 while (PR_TRUE) {
649 PLEvent* event = PL_WaitForEvent(self);
650 if (event == NULL) {
651 /* This can only happen if the current thread is interrupted */
652 return;
653 }
654
655 Log(("$$$ processing event"));
656 PL_HandleEvent(event);
657 Log(("$$$ done processing event"));
658 }
659}
660
661/*******************************************************************************
662 * Native Event Queues
663 *
664 * For when you need to call select, or WaitNextEvent, and yet also want
665 * to handle PLEvents.
666 ******************************************************************************/
667
668static PRStatus
669_pl_SetupNativeNotifier(PLEventQueue* self)
670{
671#if defined(XP_UNIX) && !defined(XP_MACOSX)
672 int err;
673 int flags;
674
675 self->idFunc = 0;
676 self->idFuncClosure = 0;
677
678 err = pipe(self->eventPipe);
679 if (err != 0) {
680 return PR_FAILURE;
681 }
682#ifdef VBOX
683 fcntl(self->eventPipe[0], F_SETFD, FD_CLOEXEC);
684 fcntl(self->eventPipe[1], F_SETFD, FD_CLOEXEC);
685#endif
686
687 /* make the pipe nonblocking */
688 flags = fcntl(self->eventPipe[0], F_GETFL, 0);
689 if (flags == -1) {
690 goto failed;
691 }
692 err = fcntl(self->eventPipe[0], F_SETFL, flags | O_NONBLOCK);
693 if (err == -1) {
694 goto failed;
695 }
696 flags = fcntl(self->eventPipe[1], F_GETFL, 0);
697 if (flags == -1) {
698 goto failed;
699 }
700 err = fcntl(self->eventPipe[1], F_SETFL, flags | O_NONBLOCK);
701 if (err == -1) {
702 goto failed;
703 }
704 return PR_SUCCESS;
705
706failed:
707 close(self->eventPipe[0]);
708 close(self->eventPipe[1]);
709 return PR_FAILURE;
710#else
711 return PR_SUCCESS;
712#endif
713}
714
715static void
716_pl_CleanupNativeNotifier(PLEventQueue* self)
717{
718#if defined(XP_UNIX) && !defined(XP_MACOSX)
719 close(self->eventPipe[0]);
720 close(self->eventPipe[1]);
721#elif defined(MAC_USE_CFRUNLOOPSOURCE)
722
723 CFRunLoopRemoveSource(self->mMainRunLoop, self->mRunLoopSource, kCFRunLoopCommonModes);
724 CFRunLoopRemoveSource(self->mMainRunLoop, self->mRunLoopSource, self->mRunLoopModeStr); /* vbox */
725 CFRelease(self->mRunLoopSource);
726 CFRelease(self->mMainRunLoop);
727 CFRelease(self->mRunLoopModeStr); /* vbox */
728#endif
729}
730
731#if defined(XP_UNIX) && !defined(XP_MACOSX)
732
733static PRStatus
734_pl_NativeNotify(PLEventQueue* self)
735{
736#define NOTIFY_TOKEN 0xFA
737 PRInt32 count;
738 unsigned char buf[] = { NOTIFY_TOKEN };
739
740# ifdef VBOX
741 /* Don't write two chars, because we'll only acknowledge one and that'll
742 cause trouble for anyone selecting/polling on the read descriptor. */
743 if (self->notified)
744 return PR_SUCCESS;
745# endif
746
747 Log(("_pl_NativeNotify: self=%p", self));
748 count = write(self->eventPipe[1], buf, 1);
749 if (count == 1)
750 return PR_SUCCESS;
751 if (count == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
752 return PR_SUCCESS;
753 return PR_FAILURE;
754}/* --- end _pl_NativeNotify() --- */
755#endif /* defined(XP_UNIX) && !defined(XP_MACOSX) */
756
757#if defined(XP_MACOSX)
758static PRStatus
759_pl_NativeNotify(PLEventQueue* self)
760{
761 CFRunLoopSourceSignal(self->mRunLoopSource);
762 CFRunLoopWakeUp(self->mMainRunLoop);
763 return PR_SUCCESS;
764}
765#endif /* defined(XP_MACOSX) */
766
767static PRStatus
768_pl_AcknowledgeNativeNotify(PLEventQueue* self)
769{
770#if defined(XP_UNIX) && !defined(XP_MACOSX)
771
772 PRInt32 count;
773 unsigned char c;
774 Log(("_pl_AcknowledgeNativeNotify: self=%p", self));
775 /* consume the byte NativeNotify put in our pipe: */
776 count = read(self->eventPipe[0], &c, 1);
777 if ((count == 1) && (c == NOTIFY_TOKEN))
778 return PR_SUCCESS;
779 if ((count == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
780 return PR_SUCCESS;
781 return PR_FAILURE;
782#elif defined(XP_MACOSX) /* vbox */
783 /* vbox */
784 CFRunLoopRunInMode(self->mRunLoopModeStr, 0.0, 1); /* vbox */
785 return PR_SUCCESS; /* vbox */
786#else
787 /* nothing to do on the other platforms */
788 return PR_SUCCESS;
789#endif
790}
791
792PR_IMPLEMENT(PRInt32)
793PL_GetEventQueueSelectFD(PLEventQueue* self)
794{
795 if (self == NULL)
796 return -1;
797
798#if defined(XP_UNIX) && !defined(XP_MACOSX)
799 return self->eventPipe[0];
800#else
801 return -1; /* other platforms don't handle this (yet) */
802#endif
803}
804
805PR_IMPLEMENT(PRBool)
806PL_IsQueueOnCurrentThread( PLEventQueue *queue )
807{
808 return queue->handlerThread == RTThreadSelf();
809}
810
811PR_EXTERN(PRBool)
812PL_IsQueueNative(PLEventQueue *queue)
813{
814 return queue->type == EventQueueIsNative ? PR_TRUE : PR_FALSE;
815}
816
817#if defined(XP_UNIX) && !defined(XP_MACOSX)
818/*
819** _md_CreateEventQueue() -- ModelDependent initializer
820*/
821static void _md_CreateEventQueue( PLEventQueue *eventQueue )
822{
823 /* there's really nothing special to do here,
824 ** the guts of the unix stuff is in the setupnativenotify
825 ** and related functions.
826 */
827 return;
828} /* end _md_CreateEventQueue() */
829#endif /* defined(XP_UNIX) && !defined(XP_MACOSX) */
830
831#if defined(XP_MACOSX)
832static void _md_EventReceiverProc(void *info)
833{
834 PLEventQueue *queue = (PLEventQueue*)info;
835 PL_ProcessPendingEvents(queue);
836}
837
838static void _md_CreateEventQueue( PLEventQueue *eventQueue )
839{
840 CFRunLoopSourceContext sourceContext = { 0 };
841 sourceContext.version = 0;
842 sourceContext.info = (void*)eventQueue;
843 sourceContext.perform = _md_EventReceiverProc;
844
845 /* make a run loop source */
846 eventQueue->mRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0 /* order */, &sourceContext);
847 Assert(eventQueue->mRunLoopSource);
848
849 eventQueue->mMainRunLoop = CFRunLoopGetCurrent();
850 CFRetain(eventQueue->mMainRunLoop);
851
852 /* and add it to the run loop */
853 CFRunLoopAddSource(eventQueue->mMainRunLoop, eventQueue->mRunLoopSource, kCFRunLoopCommonModes);
854
855 /* Add it again but with a unique mode name so we can acknowledge it
856 without processing any other message sources. */
857 { /* vbox */
858 char szModeName[80]; /* vbox */
859 snprintf(szModeName, sizeof(szModeName), "VBoxXPCOMQueueMode-%p", eventQueue); /* vbox */
860 eventQueue->mRunLoopModeStr = CFStringCreateWithCString(kCFAllocatorDefault, /* vbox */
861 szModeName, kCFStringEncodingASCII); /* vbox */
862 CFRunLoopAddSource(eventQueue->mMainRunLoop, /* vbox */
863 eventQueue->mRunLoopSource, eventQueue->mRunLoopModeStr); /* vbox */
864 } /* vbox */
865} /* end _md_CreateEventQueue() */
866#endif /* defined(XP_MACOSX) */
867
868/* extra functions for unix */
869
870#if defined(XP_UNIX) && !defined(XP_MACOSX)
871
872PR_IMPLEMENT(PRInt32)
873PL_ProcessEventsBeforeID(PLEventQueue *aSelf, unsigned long aID)
874{
875 PRInt32 count = 0;
876 PRInt32 fullCount;
877
878 if (aSelf == NULL)
879 return -1;
880
881 PR_EnterMonitor(aSelf->monitor);
882
883 if (aSelf->processingEvents) {
884 PR_ExitMonitor(aSelf->monitor);
885 return 0;
886 }
887
888 aSelf->processingEvents = PR_TRUE;
889
890 /* Only process the events that are already in the queue, and
891 * not any new events that get added. Do this by counting the
892 * number of events currently in the queue
893 */
894 fullCount = _pl_GetEventCount(aSelf);
895 Log(("$$$ fullCount is %d id is %ld\n", fullCount, aID));
896
897 if (fullCount == 0) {
898 aSelf->processingEvents = PR_FALSE;
899 PR_ExitMonitor(aSelf->monitor);
900 return 0;
901 }
902
903 PR_ExitMonitor(aSelf->monitor);
904
905 while (fullCount-- > 0) {
906 /* peek at the next event */
907 PLEvent *event = RTListGetFirst(&aSelf->queue, PLEvent, link);
908 if (event == NULL)
909 break;
910 Log(("$$$ processing event %ld\n", event->id));
911 if (event->id >= aID) {
912 Log(("$$$ skipping event and breaking"));
913 break;
914 }
915
916 event = PL_GetEvent(aSelf);
917 PL_HandleEvent(event);
918 Log(("$$$ done processing event"));
919 count++;
920 }
921
922 PR_EnterMonitor(aSelf->monitor);
923
924 /* if full count still had items left then there's still items left
925 in the queue. Let the native notify token stay. */
926
927 if (aSelf->type == EventQueueIsNative) {
928 fullCount = _pl_GetEventCount(aSelf);
929
930 if (fullCount <= 0) {
931 _pl_AcknowledgeNativeNotify(aSelf);
932 aSelf->notified = PR_FALSE;
933 }
934 }
935
936 aSelf->processingEvents = PR_FALSE;
937
938 PR_ExitMonitor(aSelf->monitor);
939
940 return count;
941}
942
943PR_IMPLEMENT(void)
944PL_RegisterEventIDFunc(PLEventQueue *aSelf, PLGetEventIDFunc aFunc,
945 void *aClosure)
946{
947 aSelf->idFunc = aFunc;
948 aSelf->idFuncClosure = aClosure;
949}
950
951PR_IMPLEMENT(void)
952PL_UnregisterEventIDFunc(PLEventQueue *aSelf)
953{
954 aSelf->idFunc = 0;
955 aSelf->idFuncClosure = 0;
956}
957
958#endif /* defined(XP_UNIX) && !defined(XP_MACOSX) */
959
960/* --- end plevent.c --- */
Note: See TracBrowser for help on using the repository browser.

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