Sponsored Link •
|
Summary
The main job of a phone, after all, is to behave in a phone-like manner: always connected, always on and always available. If application failure could preempt these canonical device behaviors, we’d have, um..Windows. But we don’t. Thus, an incorruptible safety net is required, and we get this from the Symbian Leave architecture.
Advertisement
|
In Symbian, Leaving is the mechanism by which we mediate conditions that prevent apps from performing as intended. Whether precipitated by pilot error or a simple inability on the part of the device to perform as hoped, fault conditions on a phone are materially different than those on other types of devices. The main job of a phone, after all, is to behave in a phone-like manner: always connected, always on and always available. If application failure could preempt these canonical device behaviors, we’d have, um..Windows. But we don’t. Thus, an incorruptible safety net is required, and we get this from the Symbian Leave architecture.
Why This Isn’t Vanilla C++
Most programmers have, at the very least, a curiosity about why things are like they are. It naturally follows, since we are using C++, that one might wonder why Symbian has its own unique error recovery scheme. After all, one of C++’s notable strengths is its built-in error handling facility, the exception mechanism.
At the time Symbian was under development, C++ exception handling had not yet achieved standardization or full compiler integration. Later, when exception handling behavior was well defined, this infrastructure came at the price of considerable overhead in terms of code size, application memory footprint and execution performance. C++ exceptions, while a good big- and medium-sized programming technology, simply didn’t fit in the available space on a mobile device. Think of it as being more or less analogous to the fact that on an airliner, you get to eat micro pretzels, but at the movies you can buy and enjoy a cubic yard of popcorn. In both cases, you’re occupying a seat, but it’s what’s containing that seat that dictates the menu.
So. Leaves and the Clean Up Stack. Learn to love them and the whole landscape of Symbian programming spreads itself out at your feet.
A Peek Inside The Oyster
Leaves occur when a program makes requests for resources that the system can’t satisfy. Very often, these are a result of memory allocation failures. Low memory is, after all, the default operating condition on well designed embedded systems. Leaving offers us a very light weight, yet well defined, exception handling mechanism. Here are the basics:
• Leaves propagate program execution errors to logic that can handle them.
• Execution is suspended where the Leave occurs.
• Execution resumes at the point where the Leave is TRAPped.
• Respectively, these are equivalent to setjmp() and longjmp().
An application’s actual implementation of Leave behavior relies on these User class functions:
• User::Leave() Leaves unconditionally, carrying the integer passed to it as a Leave code
• User::LeaveIfNoMemory() Leaves unconditionally, but passes a hard-coded Leave value of KErrNoMemory.
• User::LeaveIfNull() tests a pointer parameter and Leaves with a KErrNoMemory if the pointer is NULL.
• User::LeaveIfError() tests an integer parameter and Leaves if the value is less than zero.
And where, you might be wondering, do we Leave to? Leaves land in a corresponding TRAP macro. There are two forms of the TRAP macro, but they behave in exactly the same fashion:
TRAP( ReturnStatusCode, MightBeALeaver() );
if(ReturnStatusCode==NOT_SO_GOOD)
{ //Do something about it... }
The TRAP macros work recursively, which is to say they TRAP Leaves from any functions called by the one named in the macro. They may be nested. By default, all Symbian programs have at least one TRAP macro, which is provided by the app framework. TRAPs are, however, extremely expensive, and so you must balance their necessary uses against their considerable processor and memory consumption. Every TRAP entry and exit switches user app code into privileged mode, in order to access kernel resources. Also, TRAPs cause allocation of storage for a backup copy of the thread’s stack. In the event a Leave actually occurs, the previous system state is restored from this snapshot. The Take Home Lesson:
Used together, Leaves and TRAPs detect recoverable error and redirect execution to remediate.
Given the preceding, there are some basic, hard and fast rules about Leaves that we currently know enough to digest.
• You can’t Leave in a constructor or a destructor, because this would very likely leak heap memory. Constructions which aren’t Leave safe are always done in two phases so that the first phase, the actual constructor, is Leave safe.
• You should never Leave and return an error. These are mutually exclusive behaviors in the Symbian context.
• We don’t use Leaves to direct the normal flow of program logic.
One reason the Symbian error handling model is far more lightweight than C++ exception handling is that while Leaving functions deallocate all local objects, they call no destructors. For this reason, were Leaves the only mechanism for handling runtime errors, we’d have a fairly serious problem. A Leave could deallocate locally stored (stack based) pointers to heap based objects, orphaning objects on the heap and causing memory leakage. This undesirable side effect is prevented by the use of the Clean Up Stack.
The Clean Up Stack
When I think about the mechanics of the Clean Up Stack, it seems a little like this is the place where Symbian programming is actually assembly language cross dressing as C++. There are two basic things to understand about this tool: First you need to have a definite, specific grasp of what does and does not go on the Clean Up Stack; And second, pushing and popping objects has to happen in a definite, particular order. This last is ordinary stack behavior, but if you haven’t had hands on experience with this data structure, it may seem intimidating. Fear not. In this post we are going to do a flyover of the Clean Up stack, its conventions and its uses. We will return to this topic at least twice more, to explore its operations in thoroughly meticulous fashion and completely illuminate its relationship to Symbian data typing. For now, we examine key principles of the Clean Up Stack architecture:
The Clean Up Stack provides a way to ensure that heap based objects are properly deallocated if a function Leaves before it can delete or destruct them normally. Much in the same fashion that the TRAP macro stores a copy of a thread’s stack in order to correctly restore state in the event of a Leave, the Clean Up Stack ensures the integrity of the heap.
Pointers to objects that are not Leave safe must be pushed onto the Clean Up Stack. An item is not "Leave safe" if it’s deletion would cause heap memory to be leaked.
It works like the plate dispenser in the cafeteria. "Pop" removes the topmost element and "Push" adds an element at the topmost position. Since in this case, the items we are shoving around point to heap space allocations, it is very important to keep track of the order in which they come and go. Otherwise, we create the potential for double deletion, deleting things in the wrong order or leaking heap memory.
The Clean Up Stack Push operations are, themselves, Leave safe. Clean Up Stack architecture makes it impossible to orphan an object passed in to it for a PUSH operation. We’ll explore why this is so at a later point in time. The important thing here is that as an app programmer, you have no responsibility for managing the integrity of underlying Clean Up Stack data structures or functionality.
Symbian’s overall system of ensuring heap integrity relies on two things: Appropriate use of the Clean Up Stack and adherence to Symbian data type conventions. Put another way, this comes down to the first rule of good programming practice, as related to me by my sister decades ago, when we were in college. Rule of thumb: Always know where your space is coming from.
Looking Ahead:
A "whole cloth" understanding of the Symbian programming model relies on the interweaving of safety mechanisms (Leaves and the Clean Up Stack) and the conventional use of Symbian Data Types. After you understand these two things, both individually and in relation to one another, you have a solid foundation on which to build just about any sort of app. So next, we look at data types.
Have an opinion? Readers have already posted 5 comments about this weblog entry. Why not add yours?
If you'd like to be notified whenever Nancy Nicolaisen adds a new entry to her weblog, subscribe to her RSS feed.
Nancy Nicolaisen has authored three books on C++ programming topics; hundreds of articles for print magazines including Byte, Dr. Dobbs and PC Magazine; and was the chief contributor to codeguru.com's Windows CE Zone. Former researcher and Computer Science Professor, she specializes in small device and embedded systems programming. |
Sponsored Links
|