- •Contents
- •1.1 Fundamental Types
- •1.2 T Classes
- •1.3 C Classes
- •1.4 R Classes
- •1.5 M Classes
- •1.6 Static Classes
- •1.7 Buyer Beware
- •1.8 Summary
- •2 Leaves: Symbian OS Exceptions
- •2.1 Leaving Functions
- •2.3 Constructors and Destructors
- •2.4 Working with Leaving Functions
- •2.5 Trapping a Leave Using TRAP and TRAPD
- •2.6 LeaveScan
- •2.7 Summary
- •3 The Cleanup Stack
- •3.1 Using the Cleanup Stack
- •3.2 How Does the Cleanup Stack Work?
- •3.4 Using TCleanupItem for Customized Cleanup
- •3.5 Portability
- •3.6 An Incidental Note on the Use of Casts
- •3.7 Summary
- •5 Descriptors: Symbian OS Strings
- •5.3 Pointer Descriptors
- •5.4 Stack-Based Buffer Descriptors
- •5.5 Heap-Based Buffer Descriptors
- •5.6 Literal Descriptors
- •5.7 Summary
- •6 Good Descriptor Style
- •6.1 Descriptors as Parameters and Return Types
- •6.2 Common Descriptor Methods
- •6.3 The Use of HBufC Heap Descriptors
- •6.4 Externalizing and Internalizing Descriptors
- •6.5 The Overuse of TFileName
- •6.6 Useful Classes for Descriptor Manipulation
- •6.7 Summary
- •7 Dynamic Arrays and Buffers
- •7.1 CArrayX Classes
- •7.3 Why Use RArray Instead of CArrayX?
- •7.4 Dynamic Descriptor Arrays
- •7.5 Fixed-Length Arrays
- •7.6 Dynamic Buffers
- •7.7 Summary
- •8.1 Multitasking Basics
- •8.2 Event-Driven Multitasking
- •8.3 Working with Active Objects
- •8.4 Example Code
- •8.5 Threads Without an Active Scheduler
- •8.6 Application Code and Active Objects
- •8.7 Summary
- •9 Active Objects under the Hood
- •9.1 Active Object Basics
- •9.2 Responsibilities of an Active Object
- •9.3 Responsibilities of an Asynchronous Service Provider
- •9.4 Responsibilities of the Active Scheduler
- •9.5 Starting the Active Scheduler
- •9.6 Nesting the Active Scheduler
- •9.7 Extending the Active Scheduler
- •9.8 Cancellation
- •9.9 Request Completion
- •9.10 State Machines
- •9.11 Long-Running Tasks
- •9.14 Common Mistakes
- •9.15 Summary
- •10 Symbian OS Threads and Processes
- •10.2 Thread Priorities
- •10.3 Stopping a Running Thread
- •10.5 Exception Handling
- •10.6 Processes
- •10.7 Summary
- •11.2 How Do the Client and Server Fit Together?
- •11.3 How Do the Client and Server Communicate?
- •11.5 How Do Synchronous and Asynchronous Requests Differ?
- •11.6 How Is a Server Started?
- •11.7 How Many Connections Can a Client Have?
- •11.8 What Happens When a Client Disconnects?
- •11.9 What Happens If a Client Dies?
- •11.10 What Happens If a Server Dies?
- •11.15 How Many Outstanding Requests Can a Client Make to a Server?
- •11.16 Can Server Functionality Be Extended?
- •11.17 Example Code
- •11.18 Summary
- •12.2 Client Boilerplate Code
- •12.3 Starting the Server and Connecting to It from the Client
- •12.4 Server Startup Code
- •12.5 Server Classes
- •12.6 Server Shutdown
- •12.7 Accessing the Server
- •12.8 Summary
- •13 Binary Types
- •13.1 Symbian OS EXEs
- •13.2 Symbian OS DLLs
- •13.3 Writable Static Data
- •13.4 Thread-Local Storage
- •13.5 The DLL Loader
- •13.6 UIDs
- •13.8 Summary
- •14 ECOM
- •14.1 ECOM Architecture
- •14.2 Features of an ECOM Interface
- •14.3 Factory Methods
- •14.4 Implementing an ECOM Interface
- •14.5 Resource Files
- •14.6 Example Client Code
- •14.7 Summary
- •15 Panics
- •15.2 Good Panic Style
- •15.3 Symbian OS Panic Categories
- •15.4 Panicking Another Thread
- •15.5 Faults, Leaves and Panics
- •15.6 Summary
- •16 Bug Detection Using Assertions
- •16.3 Summary
- •17 Debug Macros and Test Classes
- •17.1 Heap-Checking Macros
- •17.2 Object Invariance Macros
- •17.3 Console Tests Using RTest
- •17.4 Summary
- •18 Compatibility
- •18.1 Forward and Backward Compatibility
- •18.2 Source Compatibility
- •18.3 Binary Compatibility
- •18.4 Preventing Compatibility Breaks
- •18.5 What Can I Change Without Breaking Binary Compatibility?
- •18.6 Best Practice: Planning for Future Changes
- •18.7 Compatibility and the Symbian OS Class Types
- •18.8 Summary
- •19 Thin Templates
- •20.1 Class Layout
- •20.3 Parameters and Return Values
- •20.4 Member Data and Functional Abstraction
- •20.5 Choosing Class, Method and Parameter Names
- •20.7 Summary
- •21 Good Code Style
- •21.1 Reduce the Size of Program Code
- •21.2 Use Heap Memory Carefully
- •21.3 Use Stack Memory Carefully
- •21.5 Optimize Late
- •21.6 Summary
- •Glossary
- •Bibliography and Online Resources
- •Index
15
Panics
We experience moments absolutely free from worry. These brief respites are called panic
Cullen Hightower
One dictionary definition of panic is ”a sudden overpowering fright; sudden unreasoning terror often accompanied by mass flight”. The word panic itself derives from Pan, the Greek god of nature and goatherds, who was half man and half goat. He was considered by some to represent an image of the devil. Panic was said to resemble the mental or emotional state induced by him.
On Symbian OS, when a thread is panicked, the code in it stops running. Panics are used to highlight a programming error in the most noticeable way, stopping the thread to ensure that the code is fixed, rather than potentially causing serious problems by continuing to run. There is no recovery from a panic. Unlike a leave, a panic can’t be trapped. A panic is terminal.
If a panic occurs in the main thread of a process, the entire process in which the thread runs will terminate. If a panic occurs in a secondary thread, it is only that thread which closes. However, on hardware, if any thread is deemed to be a system thread, i.e. essential for the system to run, a panic in the thread will reboot the phone.1 Otherwise, if it’s not a system thread, on target hardware and in release builds on the Windows emulator, the end result of a panic is seen as a ”Program closed” message box, which displays the process name, along with a panic category and error code. In debug emulator builds, you can choose to break into the code to debug the cause of the panic – this is known as just-in-time debugging.
1 Forcing a reboot if a system-critical thread panics is a policy decision rather than a shortcoming of the operating system.
248 |
PANICS |
Panics are used to highlight programming errors by terminating the thread (and, if it is the main thread, the process in which it runs).
15.1Just-In-Time Debugging
On the Windows emulator, in debug builds, you can use the User::SetJustInTime() system function to choose whether a panic kills just the thread or the whole emulator. By default, just-in-time debugging is enabled and a panic will terminate the entire program and enter the debugger. You can disable this by calling User::SetJustInTime(EFalse), whereupon the panic will appear as it does in release builds and simply terminate the thread in which it occurred with an appropriate message box. Just-in-time debugging can be re-enabled by calling User::SetJustInTime(ETrue).
When just-in-time debugging is enabled, the panic calls a function called ThreadPanicBreakPoint(). This function presents the debugger with an information structure which contains information about the ID and name of the thread that panicked, the panic category and reason (which are described shortly), and the name of the thread that caused the panic. The function then breaks into the code and launches the debugger within the context of the function that called the panic, using __asm int 3. You can use the debugger to look through the call stack to see where the panic arose and examine the appropriate state.
There are some subtle differences in behavior between Symbian OS v8.0, which contains the new hard real-time kernel (known at the time of going to press as ”EKA2”, which stands for ”EPOC Kernel Architecture 2”) and previous releases of Symbian OS (EKA1).
Panics on EKA1
A call to the static function User::Panic() panics the currently running thread. A thread may panic any other thread in the system by acquiring an RThread handle to it (as discussed in Chapter 10) and calling RThread::Panic(). Both functions take two parameters: a panic category string, which is limited to 16 characters, and an error code, expressed as a TInt.
Panics on EKA2
A call to the static function User::Panic() panics the currently running thread. A thread may panic any thread in the same process by calling RThread::Panic(), but can no longer panic threads in any other
GOOD PANIC STYLE |
249 |
process.2 The panic functions take a panic category string, which can contain an unlimited number of characters, and an error code, expressed, as usual, as a TInt.
15.2 Good Panic Style
Even without breaking into the debugger, you should still be able to track down the cause of a panic using the panic category string and error number. It’s good style to make your panic category string descriptive and unique, so other developers can locate the string in your header files, and with it, any associated panic error codes (which should also have suitably descriptive names).
Thus, you might have a general panic header file for your library which includes the following:
// ClangerPanic.h
#ifndef __CLANGERPANIC_H__ #define __CLANGERPANIC_H__
#include <e32base.h>
_LIT(KClangerPanic, "CLANGER-ENGINE");
enum TClangerEnginePanic
{
ECorruptBlueStringPudding, // =0, EIronChickenNotInitialized,// =1, EInvalidClangerSetting // =2 };
static void Panic(TClangerEnginePanic aCategory); #endif // __CLANGERPANIC_H__
Which defines the Panic() function separately as follows:
static void Panic(TClangerEnginePanic aCategory)
{
User::Panic(KClangerPanic, aCategory);
}
(You’ll notice by the way that the panic enumeration is a T Class because an enumeration is a type. Chapter 1 discusses the differences between class types on Symbian OS and how to use them.)
When the library code is passed invalid arguments, it may invoke Panic() with the appropriate error code, resulting in a panic and
2 Except where a server thread uses RMessagePtr to panic a misbehaving client thread.
250 |
PANICS |
termination of the thread in which it is running. The category and error will be reported, and may then be traced back by searching the library’s header files for "CLANGER-ENGINE", located inside ClangerPanic.h. You’ll see I’ve commented each error’s enum value with its associated number, just to make the lookup easier. I’ve tried to give each a descriptive name, though obviously they could be further documented, using in-source comments, for clarity.
Of course, if a client programmer has access to the source code for clanger.dll, they can also search it for calls to Panic() which use a particular error value, to track down where a panic originated.
15.3Symbian OS Panic Categories
Symbian OS itself has a series of well-documented panic categories and associated error values. You can find details of platform-specific panics in your preferred SDK. From Symbian OS v7.0, there is a special Panics section in the C++ API Reference of each SDK, which contains a comprehensive list of the Symbian OS system panics. Typical values you may encounter include:
•KERN-EXEC 3 – raised by an unhandled exception (such as an access violation caused, for example, by dereferencing NULL, memory misalignment or execution of an invalid instruction) inside a system call to the kernel executive; if an unhandled exception occurs inside code which is instead executing in user mode, the panic is seen as
USER-EXEC 3
•E32USER-CBASE 46 – raised by the active scheduler as a result of a stray signal (described further in Chapters 8 and 9)
•E32USER-CBASE 90 – raised by the cleanup stack when the object specified to be popped off is not the next object on the stack. The following code illustrates the cause of the panic; this issue is described more fully in Chapter 3, which describes the cleanup stack.
class CExample; // defined elsewhere
void CauseAPanicL()
{
TInt val = 1;
CExample* ptr1 = new (ELeave) CExample();
CleanupStack::PushL(ptr1);
CExample* ptr2 = new (ELeave) CExample();
CleanupStack::PushL(ptr2);
...
CleanupStack::Pop(ptr1); // Panics with E32USER-CBASE 90 here...