VirtualBox

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

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

libs/xpcom: Rmove unused code, bugref:10545

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