Back Contents Next

Event Handling

epoc.struct.events

Perhaps the most fundamental design decision in EPOC was to optimize the system for efficient event handling. Each native EPOC application or server is a single event-handling thread. Active objects are used to handle events non-preemptively.

In the old days, programs were written with a main() that was in control: every so often the program would deign to check for user input, and would then process it.

 

With GUI systems, though, the user is in control. As programmers, we have had to get used to this change of viewpoint: to invert our programming mentality to event-driven programming. It took some time in the programming community for this to sink in: most of the change took place over about a decade, from 1985 to 1995.

 

Arguably, this change of mindset hasn't yet happened at the deeper levels of most operating systems. Most operating systems put a lot of effort into supporting processes and threads, along with their associated synchronization paraphernalia — but very little effort into event handling, and event-based system design paradigms. Even Java, a very recent system design, uses threads at the fundamental level rather than an event-handling framework.

 

But it so happens that, when the overwhelming majority of your code is event-based, a system design optimized for event handling is much more efficient than one optimized for conventional multitasking. We'll briefly review EPOC's fundamental building blocks for event-handling systems — active objects and the client-server architecture. You won't need to understand them in any more detail than this, until you need to write your own active objects and servers. I cover those topics, quite thoroughly, much later in the book — in Chapters 20 and 21.

Perspectives on Event Handling

Say you are using the EPOC Word application. If you press a key, a small cascade of events will occur, which are handled by at least three EPOC threads:

 

 

Let's look at this cascade from a couple of perspectives. First, from the whole-system point of view:

 

q        The I/O device responsible for looking after the keyboard generates an interrupt

q        The kernel handles the event. It interrogates the device, works out what ASCII key code to assign, and creates an event for whichever program is interested in raw key events — and in any real EPOC system, that's the window server.

q        The window server then works out which application is currently receiving keystrokes, and sends the event to the application, in this case EPOC Word

q        EPOC Word then handles the key — perhaps by adding text to the document, and then updating the display

q        The window server updates the display, in response to the application's requests

 

From the power-management point of view, power is needed for the CPU only while it's doing something. Power is turned on to handle an interrupt, and turned off again when no more threads are eligible to run.

 

You can also look at the tasks in the diagram and ask, "What other events might this task have to handle?"

 

q        The keyboard driver handles an interrupt, does minimal processing, and notifies a user-mode thread — in this case, the window server. The keyboard driver must also handle requests from the window server for key events. So the keyboard driver is an event-handling task that handles two types of event: requests from a user-mode thread and hardware events from the keyboard.

q        The window server handles the key, does enough processing to identify the application that is currently taking keys, and then notifies the application. The window server, like the keyboard driver, also handles requests from the application for key presses. And the window server also performs screen drawing on behalf of all applications. So the window server is an event-handling task that handles these three event types (key events, requests to be notified about key events, and screen drawing) plus many more (for instance, pointer events, and requests to be notified about them).

q        The application is an event-handling task that handles key events (and more, for instance pointer events).

 

So each task is an event handler. In EPOC, events are handled using active objects.

Active Objects

All native EPOC threads are essentially event handlers, with a single active scheduler per thread cooperating with one or more active objects to handle events from devices and other programs.

 

Each active object has a virtual member function called RunL(). RunL() gets called when the event happens for which the particular active object is responsible, and must be implemented to handle the event. Usually, it starts with some pre-processing to analyze the event. It may complete the handling of the event without calling any other functions. But in a framework, RunL() will usually call one or more virtual functions that the programmer implements to provide specific behavior. The most important frameworks are for GUI applications and servers:

 

q        An application, such as the one in our example above, uses the CONE GUI framework. CONE analyzes input events, associates them with the correct control, and then calls virtual member functions such as OfferKeyEventL() to handle a key.

q        A server, such as the window server above, uses the server framework to handle requests from client applications — including requests to draw on the screen, or to be notified about key events. Client requests are turned into messages that are sent to the server. The server framework analyzes these messages, associates them with the correct client, and calls ServiceL() on the server-side object representing the client, to handle the client's request.

 

A server also uses its own active objects to handle events other than client requests — for instance, key events from the kernel.

 

Active objects make life very easy for application programmers. All you have to do is to implement the correct framework function. Unless you need active objects for some other reason, you don't need to understand how they work. All you need to know is that your code must complete quickly (say, within a couple of seconds) so that your application is able to handle other events without undue delay.

 

You will eventually want to understand active objects, so I explain them fully later in the book, in Chapter 20. That's quite a lot later in the book, which proves my point: I didn't need to get familiar with active objects until I got onto quite sophisticated programming.

 

Back Contents Next