VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/threads/plevent.h@ 28112

Last change on this file since 28112 was 11551, checked in by vboxsync, 16 years ago

API/xpcom: prefix any C symbols in VBoxXPCOM.so, to avoid namespace pollution. Enabled only on Linux at the moment.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.0 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/**********************************************************************
39NSPL Events
40
41Defining Events
42---------------
43
44Events are essentially structures that represent argument lists for a
45function that will run on another thread. All event structures you
46define must include a PLEvent struct as their first field:
47
48 typedef struct MyEventType {
49 PLEvent e;
50 // arguments follow...
51 int x;
52 char* y;
53 } MyEventType;
54
55It is also essential that you establish a model of ownership for each
56argument passed in an event record, i.e. whether particular arguments
57will be deleted by the event destruction callback, or whether they
58only loaned to the event handler callback, and guaranteed to persist
59until the time at which the handler is called.
60
61Sending Events
62--------------
63
64Events are initialized by PL_InitEvent and can be sent via
65PL_PostEvent or PL_PostSynchronousEvent. Events can also have an
66owner. The owner of an event can revoke all the events in a given
67event-queue by calling PL_RevokeEvents. An owner might want
68to do this if, for instance, it is being destroyed, and handling the
69events after the owner's destruction would cause an error (e.g. an
70MWContext).
71
72Since the act of initializing and posting an event must be coordinated
73with it's possible revocation, it is essential that the event-queue's
74monitor be entered surrounding the code that constructs, initializes
75and posts the event:
76
77 void postMyEvent(MyOwner* owner, int x, char* y)
78 {
79 MyEventType* event;
80
81 PL_ENTER_EVENT_QUEUE_MONITOR(myQueue);
82
83 // construct
84 event = PR_NEW(MyEventType);
85 if (event == NULL) goto done;
86
87 // initialize
88 PL_InitEvent(event, owner,
89 (PLHandleEventProc)handleMyEvent,
90 (PLDestroyEventProc)destroyMyEvent);
91 event->x = x;
92 event->y = strdup(y);
93
94 // post
95 PL_PostEvent(myQueue, &event->e);
96
97 done:
98 PL_EXIT_EVENT_QUEUE_MONITOR(myQueue);
99 }
100
101If you don't call PL_InitEvent and PL_PostEvent within the
102event-queue's monitor, you'll get a big red assert.
103
104Handling Events
105---------------
106
107To handle an event you must write a callback that is passed the event
108record you defined containing the event's arguments:
109
110 void* handleMyEvent(MyEventType* event)
111 {
112 doit(event->x, event->y);
113 return NULL; // you could return a value for a sync event
114 }
115
116Similarly for the destruction callback:
117
118 void destroyMyEvent(MyEventType* event)
119 {
120 free(event->y); // created by strdup
121 free(event);
122 }
123
124Processing Events in Your Event Loop
125------------------------------------
126
127If your main loop only processes events delivered to the event queue,
128things are rather simple. You just get the next event (which may
129block), and then handle it:
130
131 while (1) {
132 event = PL_GetEvent(myQueue);
133 PL_HandleEvent(event);
134 }
135
136However, if other things must be waited on, you'll need to obtain a
137file-descriptor that represents your event queue, and hand it to select:
138
139 fd = PL_GetEventQueueSelectFD(myQueue);
140 ...add fd to select set...
141 while (select(...)) {
142 if (...fd...) {
143 PL_ProcessPendingEvents(myQueue);
144 }
145 ...
146 }
147
148Of course, with Motif and Windows it's more complicated than that, and
149on Mac it's completely different, but you get the picture.
150
151Revoking Events
152---------------
153If at any time an owner of events is about to be destroyed, you must
154take steps to ensure that no one tries to use the event queue after
155the owner is gone (or a crash may result). You can do this by either
156processing all the events in the queue before destroying the owner:
157
158 {
159 ...
160 PL_ENTER_EVENT_QUEUE_MONITOR(myQueue);
161 PL_ProcessPendingEvents(myQueue);
162 DestroyMyOwner(owner);
163 PL_EXIT_EVENT_QUEUE_MONITOR(myQueue);
164 ...
165 }
166
167or by revoking the events that are in the queue for that owner. This
168removes them from the queue and calls their destruction callback:
169
170 {
171 ...
172 PL_ENTER_EVENT_QUEUE_MONITOR(myQueue);
173 PL_RevokeEvents(myQueue, owner);
174 DestroyMyOwner(owner);
175 PL_EXIT_EVENT_QUEUE_MONITOR(myQueue);
176 ...
177 }
178
179In either case it is essential that you be in the event-queue's monitor
180to ensure that all events are removed from the queue for that owner,
181and to ensure that no more events will be delivered for that owner.
182**********************************************************************/
183
184#ifndef plevent_h___
185#define plevent_h___
186
187#include "prtypes.h"
188#include "prclist.h"
189#include "prthread.h"
190#include "prlock.h"
191#include "prcvar.h"
192#include "prmon.h"
193
194/* For HWND */
195#if defined(XP_WIN32)
196#include <windef.h>
197#elif defined(XP_OS2)
198#define INCL_DOSMISC
199#define INCL_DOSPROCESS
200#define INCL_DOSERRORS
201#include <os2.h>
202#endif
203
204#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP
205#define PL_DestroyEvent VBoxNsplPL_DestroyEvent
206#define PL_HandleEvent VBoxNsplPL_HandleEvent
207#define PL_InitEvent VBoxNsplPL_InitEvent
208#define PL_CreateEventQueue VBoxNsplPL_CreateEventQueue
209#define PL_CreateMonitoredEventQueue VBoxNsplPL_CreateMonitoredEventQueue
210#define PL_CreateNativeEventQueue VBoxNsplPL_CreateNativeEventQueue
211#define PL_DequeueEvent VBoxNsplPL_DequeueEvent
212#define PL_DestroyEventQueue VBoxNsplPL_DestroyEventQueue
213#define PL_EventAvailable VBoxNsplPL_EventAvailable
214#define PL_EventLoop VBoxNsplPL_EventLoop
215#define PL_GetEvent VBoxNsplPL_GetEvent
216#define PL_GetEventOwner VBoxNsplPL_GetEventOwner
217#define PL_GetEventQueueMonitor VBoxNsplPL_GetEventQueueMonitor
218#define PL_GetEventQueueSelectFD VBoxNsplPL_GetEventQueueSelectFD
219#define PL_MapEvents VBoxNsplPL_MapEvents
220#define PL_PostEvent VBoxNsplPL_PostEvent
221#define PL_PostSynchronousEvent VBoxNsplPL_PostSynchronousEvent
222#define PL_ProcessEventsBeforeID VBoxNsplPL_ProcessEventsBeforeID
223#define PL_ProcessPendingEvents VBoxNsplPL_ProcessPendingEvents
224#define PL_RegisterEventIDFunc VBoxNsplPL_RegisterEventIDFunc
225#define PL_RevokeEvents VBoxNsplPL_RevokeEvents
226#define PL_UnregisterEventIDFunc VBoxNsplPL_UnregisterEventIDFunc
227#define PL_WaitForEvent VBoxNsplPL_WaitForEvent
228#define PL_IsQueueNative VBoxNsplPL_IsQueueNative
229#define PL_IsQueueOnCurrentThread VBoxNsplPL_IsQueueOnCurrentThread
230#define PL_FavorPerformanceHint VBoxNsplPL_FavorPerformanceHint
231#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */
232
233PR_BEGIN_EXTERN_C
234
235/* Typedefs */
236
237typedef struct PLEvent PLEvent;
238typedef struct PLEventQueue PLEventQueue;
239
240/*******************************************************************************
241 * Event Queue Operations
242 ******************************************************************************/
243
244/*
245** Creates a new event queue. Returns NULL on failure.
246*/
247PR_EXTERN(PLEventQueue*)
248PL_CreateEventQueue(const char* name, PRThread* handlerThread);
249
250
251/* -----------------------------------------------------------------------
252** FUNCTION: PL_CreateNativeEventQueue()
253**
254** DESCRIPTION:
255** PL_CreateNativeEventQueue() creates an event queue that
256** uses platform specific notify mechanisms.
257**
258** For Unix, the platform specific notify mechanism provides
259** an FD that may be extracted using the function
260** PL_GetEventQueueSelectFD(). The FD returned may be used in
261** a select() function call.
262**
263** For Windows, the platform specific notify mechanism
264** provides an event receiver window that is called by
265** Windows to process the event using the windows message
266** pump engine.
267**
268** INPUTS:
269** name: A name, as a diagnostic aid.
270**
271** handlerThread: A pointer to the PRThread structure for
272** the thread that will "handle" events posted to this event
273** queue.
274**
275** RETURNS:
276** A pointer to a PLEventQueue structure or NULL.
277**
278*/
279PR_EXTERN(PLEventQueue *)
280 PL_CreateNativeEventQueue(
281 const char *name,
282 PRThread *handlerThread
283 );
284
285/* -----------------------------------------------------------------------
286** FUNCTION: PL_CreateMonitoredEventQueue()
287**
288** DESCRIPTION:
289** PL_CreateMonitoredEventQueue() creates an event queue. No
290** platform specific notify mechanism is created with the
291** event queue.
292**
293** Users of this type of event queue must explicitly poll the
294** event queue to retreive and process events.
295**
296**
297** INPUTS:
298** name: A name, as a diagnostic aid.
299**
300** handlerThread: A pointer to the PRThread structure for
301** the thread that will "handle" events posted to this event
302** queue.
303**
304** RETURNS:
305** A pointer to a PLEventQueue structure or NULL.
306**
307*/
308PR_EXTERN(PLEventQueue *)
309 PL_CreateMonitoredEventQueue(
310 const char *name,
311 PRThread *handlerThread
312 );
313
314/*
315** Destroys an event queue.
316*/
317PR_EXTERN(void)
318PL_DestroyEventQueue(PLEventQueue* self);
319
320/*
321** Returns the monitor associated with an event queue. This monitor is
322** selectable. The monitor should be entered to protect against anyone
323** calling PL_RevokeEvents while the event is trying to be constructed
324** and delivered.
325*/
326PR_EXTERN(PRMonitor*)
327PL_GetEventQueueMonitor(PLEventQueue* self);
328
329#define PL_ENTER_EVENT_QUEUE_MONITOR(queue) \
330 PR_EnterMonitor(PL_GetEventQueueMonitor(queue))
331
332#define PL_EXIT_EVENT_QUEUE_MONITOR(queue) \
333 PR_ExitMonitor(PL_GetEventQueueMonitor(queue))
334
335/*
336** Posts an event to an event queue, waking up any threads waiting for an
337** event. If event is NULL, notification still occurs, but no event will
338** be available.
339**
340** Any events delivered by this routine will be destroyed by PL_HandleEvent
341** when it is called (by the event-handling thread).
342*/
343PR_EXTERN(PRStatus)
344PL_PostEvent(PLEventQueue* self, PLEvent* event);
345
346/*
347** Like PL_PostEvent, this routine posts an event to the event handling
348** thread, but does so synchronously, waiting for the result. The result
349** which is the value of the handler routine is returned.
350**
351** Any events delivered by this routine will be not be destroyed by
352** PL_HandleEvent, but instead will be destroyed just before the result is
353** returned (by the current thread).
354*/
355PR_EXTERN(void*)
356PL_PostSynchronousEvent(PLEventQueue* self, PLEvent* event);
357
358/*
359** Gets an event from an event queue. Returns NULL if no event is
360** available.
361*/
362PR_EXTERN(PLEvent*)
363PL_GetEvent(PLEventQueue* self);
364
365/*
366** Returns true if there is an event available for PL_GetEvent.
367*/
368PR_EXTERN(PRBool)
369PL_EventAvailable(PLEventQueue* self);
370
371/*
372** This is the type of the function that must be passed to PL_MapEvents
373** (see description below).
374*/
375typedef void
376(PR_CALLBACK *PLEventFunProc)(PLEvent* event, void* data, PLEventQueue* queue);
377
378/*
379** Applies a function to every event in the event queue. This can be used
380** to selectively handle, filter, or remove events. The data pointer is
381** passed to each invocation of the function fun.
382*/
383PR_EXTERN(void)
384PL_MapEvents(PLEventQueue* self, PLEventFunProc fun, void* data);
385
386/*
387** This routine walks an event queue and destroys any event whose owner is
388** the owner specified. The == operation is used to compare owners.
389*/
390PR_EXTERN(void)
391PL_RevokeEvents(PLEventQueue* self, void* owner);
392
393/*
394** This routine processes all pending events in the event queue. It can be
395** called from the thread's main event-processing loop whenever the event
396** queue's selectFD is ready (returned by PL_GetEventQueueSelectFD).
397*/
398PR_EXTERN(void)
399PL_ProcessPendingEvents(PLEventQueue* self);
400
401/*******************************************************************************
402 * Pure Event Queues
403 *
404 * For when you're only processing PLEvents and there is no native
405 * select, thread messages, or AppleEvents.
406 ******************************************************************************/
407
408/*
409** Blocks until an event can be returned from the event queue. This routine
410** may return NULL if the current thread is interrupted.
411*/
412PR_EXTERN(PLEvent*)
413PL_WaitForEvent(PLEventQueue* self);
414
415/*
416** One stop shopping if all you're going to do is process PLEvents. Just
417** call this and it loops forever processing events as they arrive. It will
418** terminate when your thread is interrupted or dies.
419*/
420PR_EXTERN(void)
421PL_EventLoop(PLEventQueue* self);
422
423/*******************************************************************************
424 * Native Event Queues
425 *
426 * For when you need to call select, or WaitNextEvent, and yet also want
427 * to handle PLEvents.
428 ******************************************************************************/
429
430/*
431** This routine allows you to grab the file descriptor associated with an
432** event queue and use it in the readFD set of select. Useful for platforms
433** that support select, and must wait on other things besides just PLEvents.
434*/
435PR_EXTERN(PRInt32)
436PL_GetEventQueueSelectFD(PLEventQueue* self);
437
438/*
439** This routine will allow you to check to see if the given eventQueue in
440** on the current thread. It will return PR_TRUE if so, else it will return
441** PR_FALSE
442*/
443PR_EXTERN(PRBool)
444 PL_IsQueueOnCurrentThread( PLEventQueue *queue );
445
446/*
447** Returns whether the queue is native (true) or monitored (false)
448*/
449PR_EXTERN(PRBool)
450PL_IsQueueNative(PLEventQueue *queue);
451
452/*******************************************************************************
453 * Event Operations
454 ******************************************************************************/
455
456/*
457** The type of an event handler function. This function is passed as an
458** initialization argument to PL_InitEvent, and called by
459** PL_HandleEvent. If the event is called synchronously, a void* result
460** may be returned (otherwise any result will be ignored).
461*/
462typedef void*
463(PR_CALLBACK *PLHandleEventProc)(PLEvent* self);
464
465/*
466** The type of an event destructor function. This function is passed as
467** an initialization argument to PL_InitEvent, and called by
468** PL_DestroyEvent.
469*/
470typedef void
471(PR_CALLBACK *PLDestroyEventProc)(PLEvent* self);
472
473/*
474** Initializes an event. Usually events are embedded in a larger event
475** structure which holds event-specific data, so this is an initializer
476** for that embedded part of the structure.
477*/
478PR_EXTERN(void)
479PL_InitEvent(PLEvent* self, void* owner,
480 PLHandleEventProc handler,
481 PLDestroyEventProc destructor);
482
483/*
484** Returns the owner of an event.
485*/
486PR_EXTERN(void*)
487PL_GetEventOwner(PLEvent* self);
488
489/*
490** Handles an event, calling the event's handler routine.
491*/
492PR_EXTERN(void)
493PL_HandleEvent(PLEvent* self);
494
495/*
496** Destroys an event, calling the event's destructor.
497*/
498PR_EXTERN(void)
499PL_DestroyEvent(PLEvent* self);
500
501/*
502** Removes an event from an event queue.
503*/
504PR_EXTERN(void)
505PL_DequeueEvent(PLEvent* self, PLEventQueue* queue);
506
507
508/*
509 * Give hint to native PL_Event notification mechanism. If the native
510 * platform needs to tradeoff performance vs. native event starvation
511 * this hint tells the native dispatch code which to favor.
512 * The default is to prevent event starvation.
513 *
514 * Calls to this function may be nested. When the number of calls that
515 * pass PR_TRUE is subtracted from the number of calls that pass PR_FALSE
516 * is greater than 0, performance is given precedence over preventing
517 * event starvation.
518 *
519 * The starvationDelay arg is only used when
520 * favorPerformanceOverEventStarvation is PR_FALSE. It is the
521 * amount of time in milliseconds to wait before the PR_FALSE actually
522 * takes effect.
523 */
524PR_EXTERN(void)
525PL_FavorPerformanceHint(PRBool favorPerformanceOverEventStarvation, PRUint32 starvationDelay);
526
527
528/*******************************************************************************
529 * Private Stuff
530 ******************************************************************************/
531
532struct PLEvent {
533 PRCList link;
534 PLHandleEventProc handler;
535 PLDestroyEventProc destructor;
536 void* owner;
537 void* synchronousResult;
538 PRLock* lock;
539 PRCondVar* condVar;
540 PRBool handled;
541#ifdef PL_POST_TIMINGS
542 PRIntervalTime postTime;
543#endif
544#ifdef XP_UNIX
545 unsigned long id;
546#endif /* XP_UNIX */
547 /* other fields follow... */
548};
549
550/******************************************************************************/
551
552/*
553** Returns the event queue associated with the main thread.
554**
555*/
556#if defined(XP_WIN) || defined(XP_OS2)
557/* -----------------------------------------------------------------------
558** FUNCTION: PL_GetNativeEventReceiverWindow()
559**
560** DESCRIPTION:
561** PL_GetNativeEventReceiverWindow() returns the windows
562** handle of the event receiver window associated with the
563** referenced PLEventQueue argument.
564**
565** INPUTS:
566** PLEventQueue pointer
567**
568** RETURNS:
569** event receiver window handle.
570**
571** RESTRICTIONS: MS-Windows ONLY.
572**
573*/
574PR_EXTERN(HWND)
575 PL_GetNativeEventReceiverWindow(
576 PLEventQueue *eqp
577 );
578#endif /* XP_WIN || XP_OS2 */
579
580#ifdef XP_UNIX
581/* -----------------------------------------------------------------------
582** FUNCTION: PL_ProcessEventsBeforeID()
583**
584** DESCRIPTION:
585**
586** PL_ProcessEventsBeforeID() will process events in a native event
587** queue that have an id that is older than the ID passed in.
588**
589** INPUTS:
590** PLEventQueue *aSelf
591** unsigned long aID
592**
593** RETURNS:
594** PRInt32 number of requests processed, -1 on error.
595**
596** RESTRICTIONS: Unix only (well, X based unix only)
597*/
598PR_EXTERN(PRInt32)
599PL_ProcessEventsBeforeID(PLEventQueue *aSelf, unsigned long aID);
600
601/* This prototype is a function that can be called when an event is
602 posted to stick an ID on it. */
603
604typedef unsigned long
605(PR_CALLBACK *PLGetEventIDFunc)(void *aClosure);
606
607
608/* -----------------------------------------------------------------------
609** FUNCTION: PL_RegisterEventIDFunc()
610**
611** DESCRIPTION:
612**
613** This function registers a function for getting the ID on unix for
614** this event queue.
615**
616** INPUTS:
617** PLEventQueue *aSelf
618** PLGetEventIDFunc func
619** void *aClosure
620**
621** RETURNS:
622** void
623**
624** RESTRICTIONS: Unix only (well, X based unix only) */
625PR_EXTERN(void)
626PL_RegisterEventIDFunc(PLEventQueue *aSelf, PLGetEventIDFunc aFunc,
627 void *aClosure);
628
629/* -----------------------------------------------------------------------
630** FUNCTION: PL_RegisterEventIDFunc()
631**
632** DESCRIPTION:
633**
634** This function unregisters a function for getting the ID on unix for
635** this event queue.
636**
637** INPUTS:
638** PLEventQueue *aSelf
639**
640** RETURNS:
641** void
642**
643** RESTRICTIONS: Unix only (well, X based unix only) */
644PR_EXTERN(void)
645PL_UnregisterEventIDFunc(PLEventQueue *aSelf);
646
647#endif /* XP_UNIX */
648
649
650/* ----------------------------------------------------------------------- */
651
652#if defined(NO_NSPR_10_SUPPORT)
653#else
654/********* ???????????????? FIX ME ??????????????????????????? *****/
655/********************** Some old definitions *****************************/
656
657/* Re: prevent.h->plevent.h */
658#define PREvent PLEvent
659#define PREventQueue PLEventQueue
660#define PR_CreateEventQueue PL_CreateEventQueue
661#define PR_DestroyEventQueue PL_DestroyEventQueue
662#define PR_GetEventQueueMonitor PL_GetEventQueueMonitor
663#define PR_ENTER_EVENT_QUEUE_MONITOR PL_ENTER_EVENT_QUEUE_MONITOR
664#define PR_EXIT_EVENT_QUEUE_MONITOR PL_EXIT_EVENT_QUEUE_MONITOR
665#define PR_PostEvent PL_PostEvent
666#define PR_PostSynchronousEvent PL_PostSynchronousEvent
667#define PR_GetEvent PL_GetEvent
668#define PR_EventAvailable PL_EventAvailable
669#define PREventFunProc PLEventFunProc
670#define PR_MapEvents PL_MapEvents
671#define PR_RevokeEvents PL_RevokeEvents
672#define PR_ProcessPendingEvents PL_ProcessPendingEvents
673#define PR_WaitForEvent PL_WaitForEvent
674#define PR_EventLoop PL_EventLoop
675#define PR_GetEventQueueSelectFD PL_GetEventQueueSelectFD
676#define PRHandleEventProc PLHandleEventProc
677#define PRDestroyEventProc PLDestroyEventProc
678#define PR_InitEvent PL_InitEvent
679#define PR_GetEventOwner PL_GetEventOwner
680#define PR_HandleEvent PL_HandleEvent
681#define PR_DestroyEvent PL_DestroyEvent
682#define PR_DequeueEvent PL_DequeueEvent
683#define PR_GetMainEventQueue PL_GetMainEventQueue
684
685/********* ????????????? End Fix me ?????????????????????????????? *****/
686#endif /* NO_NSPR_10_SUPPORT */
687
688PR_END_EXTERN_C
689
690#endif /* plevent_h___ */
Note: See TracBrowser for help on using the repository browser.

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