The Symbian OS (779886), страница 20
Текст из файла (страница 20)
When the requested service completes and there is a result tobe handled, a local active scheduler invokes the active object’s Run()method to handle the completed event.An active scheduler is created by the UI Framework for each application. All active objects invoked by an application (but only thatapplication’s active objects) share a single thread, in which they are notpre-empted (i.e. they are scheduled in priority order by the scheduler).Active objects are a pervasive Symbian idiom and provide a nonpre-emptive multitasking alternative to explicitly creating multithreadedprograms (although that option remains available to developers), as asolution to the problem of managing multiple paths of execution withina program, in the context of an event-based, reactive application model.From the perspective of a GUI application developer they offer a mucheasier solution than multithreading, in effect handing off the awkwarddetails to the system.Charles Davies:Our model for events was very much asynchronous events and signals andrequests.
So what we had first of all, and it’s what other systems have too,is that you make one or more requests for events, and events include timersand serial events and all kind of events that can come out of anywhere, notjust user-originated events. So you just set off a large number of events andthen you wait for any one of them to come through. So things need to beable to respond to events from multiple sources.
Now Windows had a wayof handling this. There’s a Windows API, though it’s not very elegant. Theproblem is, it’s tied to the GUI programming model. In Windows you haveto run up the whole GUI to get the event model going, and we thought thatwas a real weakness in mobile devices. We thought that servers needed this aswell, that servers sit there waiting for events from multiple sources, events like‘my client has died’, which comes from a different source than the messagechannel saying ‘here’s the next request from the client’.The event-driven model is essentially a state-machine model.
But,except within niche areas such as communications programming, these74INTRODUCTION TO THE ARCHITECTURE OF SYMBIAN OSwere not widely used patterns, especially for applications programming.And except for those familiar with Windows at the time, or with otherGUI systems such as Amiga and Macintosh, the event-driven applicationmodel was not widely or well understood.Charles Davies:When I was interviewing people I used an example of a terminal emulationprogram.
Here is a program that indisputably gets events not just from theuser. The normal, naı̈ve way of writing an interactive application at that timewould be to wait for a keypress, see what keypress it was, and respond to it;was it a function key, was it any other key? You’d have some horrible casestatement responding to a keypress.
So I would ask, ‘How would you write anapplication where you don’t know whether your next input is coming throughthe serial port or from the keypress?’ And if they had a good answer to it theygot hired, and if they didn’t, they didn’t.Well we started off programming it the way that anybody would programit, you make asynchronous requests on whatever event sources you want torespond to. There are many pitfalls in doing that, for example if you don’tconsume that event in the right way. You end up with an event loop that’s quitemessy, and it’s pages long, and people were making mistakes.
Every eventloop was buggy, and horrible bugs too, so we said ‘Let’s make it modular.’Martin Tasker had the benefit of a background of programming IBMmainframes:Martin Tasker:I’ve written plenty of event-handling loops, in communications programsor command handlers where by definition you don’t know what’s going tohappen next. Every time I wrote one of these loops I remember thinking, ‘HaveI got this right?’ Dry running through every possibility, you used to have to tellpeople coming on to the team, ‘No, if you handle your loop that way you’reeither going to double-handle some event or fail to handle some event, oryou’re not going to handle event number 2 if event number 2 happens whileyou’re handling event number 1, or you’re not actually going to handle eventnumber 2 until event number 3 comes along.
. .’ These are all mistakes thateverybody makes when they’re writing event-handling programs. Over thelifetime of a program you tend to add in more and more events, or you removethem, and you change things around. And in those circumstances, when you’remodifying existing code, it’s tremendously difficult to get event-handling loopsright.Active objects were devised explicitly to solve such problems, bycreating an easy-to-understand and easy-to-use mechanism for firingSYMBIAN OS IDIOMS75off event handlers asynchronously, deliberately breaking the dependencies between events which are implied by the big, single-block switchstatement which is the typical implementation.
More generically, activeobjects enable multitasking within applications without the use of explicitmultithreading.Charles Davies:We could have done it with threads and created a multithreaded UI, whichby the way is what Java does. But the bad thing about threads is that youcan pre-empt at any time, and then you’ve got to protect the data, becauseyou have no idea when you’re processing one thread what state the data isin. The solution was active objects, for any program that responded to eventsfrom multiple sources. So it came about because people were getting it wrong,because the old way was so complicated. So what are active objects? They’rereally non-pre-emptive multitasking within an application.
And that is a verystrong pattern. But it is also something that throws people, because it wasn’tcopied. It was invented here, and it’s widely used, and it has been useful, butit is a particular strength of Symbian OS.Active objects are used widely throughout the operating system, aswell as providing a ready-made mechanism for developers creating nativeSymbian OS applications.Martin Tasker:Colly Myers was right, active objects are a fantastic solution.
For people whoknow they are dealing with event-handling programs, they are an absolute joy.And the whole single-threaded nature of an application process is also greatfor programmers. In an event-handling system, active objects are a naturalway of handling things, and they are easier for programmers to work with thanpretty much all of the alternatives.Cleanup, Leaving and Two-Phase ConstructionThe native Symbian OS error-recovery model evolved explicitly to handlethe kinds of errors that should be expected on resource-constrained andmobile devices: low-memory situations, low-power situations, suddenloss of power, loss of connectivity or intermittent connectivity, and eventhe sudden loss of a file system, for example when a removable mediacard is physically removed from the device without unmounting.
Theseare all likely or even daily occurrences in the mobile phone context,causing errors from which the system must recover gracefully. In contrast,for a large system these may be rare enough occurrences for systemfailure with an ‘unrecoverable error’ message to be acceptable.76INTRODUCTION TO THE ARCHITECTURE OF SYMBIAN OSThe Symbian OS model is proven, playing a large part in the unrivaledrobustness of the system, and going back to the earliest days of theoperating system, and indeed to Psion systems before it.Charles Davies:We had Enter() and Leave() in the 16-bit system, which was Kernighanand Ritchie inspired. When we went to C++, the standards for exception handling were still being written, so they certainly weren’t available in compilers.So we carried forward Leave() and Enter() rather than adopting nativeC++ exception handling, because at that time it consisted of longjump()and setjump().
It was very unstructured, and we didn’t like that. We likedEnter() and Leave(), and we stuck with it.In Symbian OS, Leave() is a system function (provided by the UserLibrary) which provides error propagation within a program. Typically,Leave() is used to guard any calls which can fail (for conditions such asout of memory, no network coverage and disk full). The system unwindsthe call stack until it finds a prior Leave() call wrapped by a TRAPmacro, at which point the TRAP is executed and the failure is handled bythe program in which it occurred.19Functions which may fail because of a leave, whether because theydirectly invoke the action which might fail or do so indirectly by callingsome other function that does, are described as ‘leaving’ functions.By convention, leaving functions are named with a trailing ‘L’, whichmakes it easy for programmers to see where they are invoked and trapappropriately.The second leg of the error-handling strategy uses the ‘cleanup stack’to store pointers to heap-allocated objects whose destructors will fail tobe called if the normal path of program execution is derailed by a leave.20As well as unwinding the call stack to handle the leave, the cleanup stackis also unwound and destructors are called on any pushed objects.The third leg of the strategy is ‘two-phase construction’, which guarantees that C++ construction of an object will always succeed, by movingany leaving calls out of the C++ constructor into a secondary constructor.