VirtualBox

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

Last change on this file since 101990 was 101990, checked in by vboxsync, 17 months ago

libs/xpcom: Convert plevent.c from PR_LOG to IPRT's logging infrastructure, bugref:10545

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

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