VirtualBox

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

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

libs/xpcom: Convert plevent.{c,h} to IPRT critical sections and event semaphores, bugref:10545

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