The Event Management Framework
Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation
The Event Management Framework is a central facility for registering all events of an application. Such a registration facilitates grouping of various application events and waiting on multiple events in a single event-processing loop. This facility is used by the Replication Framework and by DSOM to wait on their respective events of interest. The Event Management Framework must also be used by any interactive application that contains DSOM or replicated objects.
Event Management Basics
The Event Management Framework consists of an Event Manager (EMan) class, a Registration Data class and several Event classes. It provides a way to organize various application events into groups and to process all events in a single event-processing loop. The need for this kind of facility is seen very clearly in interactive applications that also need to process some background events (say, messages arriving from a remote process). Such applications must maintain contact with the user while responding to events coming from other sources.
One solution in a multi-threaded environment is to have a different thread service each different source of events. For a single-threaded environment it should be possible to recognize and process all events of interest in a single main loop. EMan offers precisely this capability. EMan can be useful even when multiple threads are available, because of its simple programming model. It avoids contention for common data objects between EMan event processing and other main-loop processing activity.
Model of EMan usage
The programming model of EMan is similar to that of many GUI toolkits. The main program initializes EMan and then registers interest in various types of events. The main program ends by calling a non-returning function of EMan that waits for events and dispatches them as and when they occur. In short, the model includes steps that:
- Initialize the Event Manager,
- Register with EMan for all events of interest, and
- Hand over control to EMan to loop forever and to dispatch events.
The Event Manager is a SOM object and is an instance of the SOMEEMan class. Since any application requires only one instance of this object, the SOMEEMan class is an instance of the SOMMSingleInstance class. Creation and initialization of the Event Manager is accomplished by a function call to SOMEEmanNew.
Currently, EMan supports the four kinds of events described in the following topic. An application can register or unregister for events in a callback routine (explained below) even after control has been turned over to EMan.
Event types
Event types are categorized as follows:
- Timer events
- These can be either one-time timers or interval timers.
- Sink events (sockets, file descriptors, and message queues)
- On AIX, this includes file descriptors for input/output files, sockets, pipes, and message queues. On OS/2 and Windows, only TCP/IP sockets are supported.
- Note:On OS/2 and Windows, the Sockets classes for NetBIOS (NBSockets) and Novell IPX/SPX (IPXSockets) are primarily intended for use by DSOM and the Replication Framework, not for general application programming. (The Replication Framework is available as part of the full-capability SOMobjects Developer Toolkit.)
- Client events (any event that the application wants to queue with EMan)
- These events are defined, created, processed, and destroyed by the application. EMan simply acts as a place to queue these events for processing. EMan dispatches these client events whenever it sees them. Typically, this happens immediately after the event is queued.
- Work procedure events (procedures that can be called when there is no other event)
- These are typically background procedures that the application intends to execute when there are spare processor cycles. When there are no other events to process, EMan calls all registered work procedures. A work procedure event is called only after all other higher priority events have been called. A work procedure event is not called if there are no other events to be processed.
The Event Management Framework is extendible (that is, other event types can be added to it) through subclassing. The event types currently supported by EMan are at a sufficiently low level so as to enable building other higher level application events on top of them. For example, you can build an X-event handler by simply registering the file descriptor for the X connection with EMan and getting notified when any X-event occurs.
Registration
This topic illustrates how to register for an event type.
Callbacks
The programmer decides what processing needs to be done when an event occurs and then places the appropriate code either in a procedure or in a method of an object. This procedure or method is called a callback. (The callback is provided to EMan at the time of registration and is called by EMan when a registered event occurs.) The signature of a callback is fixed by the framework and must have one of the following three signatures:
void SOMLINK EMRegProc(SOMEEvent, void *); void SOMLINK EMMethodProc(SOMObject, SOMEEvent, void *); void SOMLINK EMMethodProcEv(SOMObject, Environment *Ev, SOMEEvent, void *); /* On OS/2, they all use "system" linkage */ /* On Windows, the SOMLINK keyword is Not included if the * application is intended to support multiple instances. */
The three specified prototypes correspond to a simple callback procedure, a callback method using OIDL call style, and a callback method using IDL call style. The parameter type SOMEEvent refers to an event object passed by EMan to the callback. Event objects are described below.
NOTE: When the callbacks are methods, EMan calls these methods using Name-lookup Resolution (see Chapter 5 Section 5.3 on Method Resolution). One of the implications is that at the time of registration EMan queries the target object's class object to provide a method pointer for the method name supplied to it. Eman uses this pointer for making event callbacks.
Event classes
All event objects are instances of either the SOMEEvent class or a subclass of it. The hierarchy of event classes is as follows:
SOMObject─────────SOMEEvent─────────┼──────────SOMETimerEvent ├──────────SOMEClientEvent ├──────────SOMESinkEvent ├──────────SOMEWorkProcEvent
When called by EMan, a callback expects the appropriate event instance as a parameter. For example, a callback registered for a timer event expects a SOMETimerEvent instance from EMan.
EMan parameters
Several method calls in the Event Management Framework make use of bit masks and constants as parameters (for example, EMSinkEvent or EMInputReadMask). These methods are defined in the include file "eventmsk.h". When a user plans to extend the Event Management Framework, care must be taken to avoid name and value collisions with the definitions in "eventmsk.h". For convenience, the contents of the "eventmsk.h" file are shown below.
#ifndef H_EVENTMASKDEF #define H_EVENTMASKDEF /* Event Types */ #define EMTimerEvent 54 #define EMSignalEvent 55 #define EMSinkEvent 56 #define EMWorkProcEvent 57 #define EMClientEvent 58 #define EMMsgQEvent 59 /* Sink input/output condition mask */ #define EMInputReadMask (1L<0) #define EMInputWriteMask (1L<1) #define EMInputExceptMask (1L<2) /* Process Event mask */ #define EMProcessTimerEvent (1L<0) #define EMProcessSinkEvent (1L<1) #define EMProcessWorkProcEvent (1L<2) #define EMProcessClientEvent (1L<3) #define EMProcessAllEvents (1L<6) #endif /* H_EVENTMASKDEF */
Registering for events
In addition to the event classes, the Event Management Framework uses a registration data class (SOMEEMRegisterData) to capture all event-related registration information. The procedure for registering interest in an event is as follows:
1.Create an instance of the SOMEEMRegisterData class (this will be referred to as a "RegData" object).
2.Set the event type of "RegData."
3.Set the various fields of "RegData" to supply information about the particular event for which an interest is being registered.
4.Call the registration method of EMan, using "RegData" and the callback method information as parameters. The callback information varies, depending upon whether it is a simple procedure, a method called using OIDL call style, or a method called using IDL call style.
The following code segment illustrates how to register input interest in a socket "sock" and provide a callback procedure "ReadMsg".
data = SOMEEMRegisterDataNew( ); /* create a RegData object */ _someClearRegData(data, Ev); _someSetRegDataEventMask(data,Ev,EMSinkEvent,NULL); /* Event type */ _someSetRegDataSink(data, Ev, sock); /* provide the socket id */ _someSetRegDataSinkMask(data,Ev, EMInputReadMask ); /*input interest */ regId = _someRegisterProc(some_gEMan,Ev,data,ReadMsg,"UserData" ); /* some_gEMan points to EMan. The last parameter "userData" is any data the user wants to be passed to the callback procedure as a second parameter */
Unregistering for events
One can unregister interest in a given event type at any time. To unregister, you must provide the registration id returned by EMan at the time of registration. Unregistering a non-existent event (such as, an invalid registration id) is a no-op. The following example unregisters the socket registered above:
_someUnRegister(some_gEMan, Ev, regId);
An example callback procedure
The following code segment illustrates how to write a callback procedure:
void SOMLINK ReadMsg( SOMEEvent event, void *targetData ) { int sock; printf( "Data = %s\n", targetData ); switch( _somevGetEventType( event )) { case EMSinkEvent: printf("callback: Perceived Sink Event\n"); sock = _somevGetEventSink(event); /* code to read the message off the socket */ break; default: printf("Unknown Event type in socket callback\n"); } } /* On OS/2, "system" linkage is also required. */ /* On Windows, callbacks do not use the SOMLINK keyword if * the application is intended to support multiple instances. */
Generating client events
While the other events are caused by the operating system (for example, Timer), by I/O devices, or by external processes, client events are caused by the application itself. The application creates these events and enqueues them with EMan. When client events are dispatched, they are processed in a callback routine just like any other event. The following code segment illustrates how to create and enqueue client events.
clientEvent1 = SOMEClientEventNew(); /* create a client event */ _somevSetEventClientType( clientEvent1, Ev, "MyClientType" ); _somevSetEventClientData( clientEvent1, Ev, "I can give any data here"); /* assuming that "MyClientType" is already registered with EMan */ /* enqueue the above event with EMan */ _someQueueEvent(some_gEMan, Ev, clientEvent1);
Examples of using other events
The sample program shipped with the Event Management Framework illustrates the tasks listed below. (Due to its large size, the source code is not included here.)
- Registering and unregistering for Timer events.
- Registering and unregistering for Workproc events.
- Registering an AIX Message Queue, sending messages on it, and unregistering the Message Queue.
- Registering a stream socket that listens to incoming connection requests. Also, sockets connecting, accepting a connection, and sending/receiving messages through EMan.
- Registering a file descriptor on AIX and reading one line of the file at a time in a callback.
Processing events
After all registrations are finished, an application typically turns over control to EMan and is completely event driven thereafter. Typically, an application main program ends with the following call to EMan:
_someProcessEvents(some_gEMan, Ev);
An equivalent way to process events is to write a main loop and call someProcessEvent from inside the main loop, as indicated:
while (1) { /* do forever */ _someProcessEvent( some_gEMan, Ev, EMProcessTimerEvent Æ EMProcessSinkEvent Æ EMProcessClientEvent Æ EMProcessWorkProcEvent ); /*** Do other main loop work, as needed. ***/ }
The second way allows more precise control over what type of events to process in each call. The example above enables all four types to be processed. The required subset is formed by logically OR'ing the appropriate bit constants (these are defined in "eventmsk.h)". Another difference is that the second way is a non-blocking call to EMan. That is, if there are no events to process, control returns to the main loop immediately, whereas someProcessEvents is a non-returning blocking call. For most applications, the first way of calling EMan is better, since it does not waste processor cycles when there are no events to process.
Interactive applications
Interactive applications need special attention when coupled with EMan. Once control is turned over to EMan by calling someProcessEvents, a single-threaded application (for example, on AIX) has no way of responding to keyboard input. The user must register interest in "stdin" with EMan and provide a callback function that handles keyboard input. In a multi-threaded environment (for example, OS/2), this problem can be solved by spawning a thread to execute someProcessEvents and another to handle keyboard input. (These two options are illustrated in the sample program shipped with the Event Management Framework.)