VirtualBox

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

Last change on this file since 102016 was 102016, checked in by vboxsync, 18 months ago

libs/xpcom/xpcom: Convert nsEventQueueService,nsEventQueue and plevent from PRThread/nsIThread to IPRT's thread API, 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 RTTHREAD 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 RTTHREAD 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, RTTHREAD handlerThread)
150{
151 return( _pl_CreateEventQueue( name, handlerThread, EventQueueIsNative ));
152}
153
154PR_EXTERN(PLEventQueue *)
155PL_CreateNativeEventQueue(const char *name, RTTHREAD handlerThread)
156{
157 return( _pl_CreateEventQueue( name, handlerThread, EventQueueIsNative ));
158}
159
160PR_EXTERN(PLEventQueue *)
161PL_CreateMonitoredEventQueue(const char *name, RTTHREAD 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 (RTThreadSelf() == 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 == RTThreadSelf());
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 return queue->handlerThread == RTThreadSelf();
817}
818
819PR_EXTERN(PRBool)
820PL_IsQueueNative(PLEventQueue *queue)
821{
822 return queue->type == EventQueueIsNative ? PR_TRUE : PR_FALSE;
823}
824
825#if defined(XP_UNIX) && !defined(XP_MACOSX)
826/*
827** _md_CreateEventQueue() -- ModelDependent initializer
828*/
829static void _md_CreateEventQueue( PLEventQueue *eventQueue )
830{
831 /* there's really nothing special to do here,
832 ** the guts of the unix stuff is in the setupnativenotify
833 ** and related functions.
834 */
835 return;
836} /* end _md_CreateEventQueue() */
837#endif /* defined(XP_UNIX) && !defined(XP_MACOSX) */
838
839static void _md_EventReceiverProc(void *info)
840{
841 PLEventQueue *queue = (PLEventQueue*)info;
842 PL_ProcessPendingEvents(queue);
843}
844
845#if defined(XP_MACOSX)
846static void _md_CreateEventQueue( PLEventQueue *eventQueue )
847{
848 CFRunLoopSourceContext sourceContext = { 0 };
849 sourceContext.version = 0;
850 sourceContext.info = (void*)eventQueue;
851 sourceContext.perform = _md_EventReceiverProc;
852
853 /* make a run loop source */
854 eventQueue->mRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0 /* order */, &sourceContext);
855 Assert(eventQueue->mRunLoopSource);
856
857 eventQueue->mMainRunLoop = CFRunLoopGetCurrent();
858 CFRetain(eventQueue->mMainRunLoop);
859
860 /* and add it to the run loop */
861 CFRunLoopAddSource(eventQueue->mMainRunLoop, eventQueue->mRunLoopSource, kCFRunLoopCommonModes);
862
863 /* Add it again but with a unique mode name so we can acknowledge it
864 without processing any other message sources. */
865 { /* vbox */
866 char szModeName[80]; /* vbox */
867 snprintf(szModeName, sizeof(szModeName), "VBoxXPCOMQueueMode-%p", eventQueue); /* vbox */
868 eventQueue->mRunLoopModeStr = CFStringCreateWithCString(kCFAllocatorDefault, /* vbox */
869 szModeName, kCFStringEncodingASCII); /* vbox */
870 CFRunLoopAddSource(eventQueue->mMainRunLoop, /* vbox */
871 eventQueue->mRunLoopSource, eventQueue->mRunLoopModeStr); /* vbox */
872 } /* vbox */
873} /* end _md_CreateEventQueue() */
874#endif /* defined(XP_MACOSX) */
875
876/* extra functions for unix */
877
878#if defined(XP_UNIX) && !defined(XP_MACOSX)
879
880PR_IMPLEMENT(PRInt32)
881PL_ProcessEventsBeforeID(PLEventQueue *aSelf, unsigned long aID)
882{
883 PRInt32 count = 0;
884 PRInt32 fullCount;
885
886 if (aSelf == NULL)
887 return -1;
888
889 PR_EnterMonitor(aSelf->monitor);
890
891 if (aSelf->processingEvents) {
892 PR_ExitMonitor(aSelf->monitor);
893 return 0;
894 }
895
896 aSelf->processingEvents = PR_TRUE;
897
898 /* Only process the events that are already in the queue, and
899 * not any new events that get added. Do this by counting the
900 * number of events currently in the queue
901 */
902 fullCount = _pl_GetEventCount(aSelf);
903 Log(("$$$ fullCount is %d id is %ld\n", fullCount, aID));
904
905 if (fullCount == 0) {
906 aSelf->processingEvents = PR_FALSE;
907 PR_ExitMonitor(aSelf->monitor);
908 return 0;
909 }
910
911 PR_ExitMonitor(aSelf->monitor);
912
913 while (fullCount-- > 0) {
914 /* peek at the next event */
915 PLEvent *event;
916 event = PR_EVENT_PTR(aSelf->queue.next);
917 if (event == NULL)
918 break;
919 Log(("$$$ processing event %ld\n", event->id));
920 if (event->id >= aID) {
921 Log(("$$$ skipping event and breaking"));
922 break;
923 }
924
925 event = PL_GetEvent(aSelf);
926 PL_HandleEvent(event);
927 Log(("$$$ done processing event"));
928 count++;
929 }
930
931 PR_EnterMonitor(aSelf->monitor);
932
933 /* if full count still had items left then there's still items left
934 in the queue. Let the native notify token stay. */
935
936 if (aSelf->type == EventQueueIsNative) {
937 fullCount = _pl_GetEventCount(aSelf);
938
939 if (fullCount <= 0) {
940 _pl_AcknowledgeNativeNotify(aSelf);
941 aSelf->notified = PR_FALSE;
942 }
943 }
944
945 aSelf->processingEvents = PR_FALSE;
946
947 PR_ExitMonitor(aSelf->monitor);
948
949 return count;
950}
951
952PR_IMPLEMENT(void)
953PL_RegisterEventIDFunc(PLEventQueue *aSelf, PLGetEventIDFunc aFunc,
954 void *aClosure)
955{
956 aSelf->idFunc = aFunc;
957 aSelf->idFuncClosure = aClosure;
958}
959
960PR_IMPLEMENT(void)
961PL_UnregisterEventIDFunc(PLEventQueue *aSelf)
962{
963 aSelf->idFunc = 0;
964 aSelf->idFuncClosure = 0;
965}
966
967#endif /* defined(XP_UNIX) && !defined(XP_MACOSX) */
968
969/* --- 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