Join Now
Quality Rating:
  • Currently 0.0 / 5
(0.0 / 5 - 0 votes cast)
Expertise Level:
  • Currently 0.0 / 5
(0.0 / 5 - 0 votes cast)

This page was last modified 16:16, 23 June 2008.

How to catch a panic

From Forum Nokia Wiki

Yes, a panic. Although panics, by their nature, are uncatchable there is a way to prevent them from severely influencing your program.

First off, why would you do it? What is the use-case? Typically a panic draws attention to a programmatic error that should have already been corrected in the program. It always terminates the program execution and it's on purpose: programs panic from an unrecoverable stage. So why would we want to catch a panic if we were able to do so?

Well, there is at least one special use-case: in a test framework used for automated testing. In a typical unit testing framework, for example, where test suites containing test cases are being performed it's always a nice feature if the execution of tests doesn't get interrupted even in case of a fatal error. If the severe programming error doesn't harm other test cases, then it's ideal if the termination of a test case doesn't influence the life-time of other test cases.

Can panics be caught? At first sight, it may seem that User::SetExceptionHandler() would do. But it doesn't: exceptions are not the same as panics. So installing a new exception handler will not enable us to catch panics, even though it makes it possible to catch a small portion of ALL panics (e.g. an access violation aka KERN-EXE 3).

The ultimate solution is to let your test case run in a new thread. A new thread that you have control over: you create, destroy and most importantly monitor it. You can request notification when this thread dies normally or otherwise via RThread::Logon(). Combined this with RThread::ExitReason(), you can get a clue when and how a thread has exited. Even in case of a panic your main thread will not be affected at all so your - test - framework can continue to run.

The following example shows a console based exe which monitors other thread's death, displaying type and reason:

#ifndef THREADNOTIFIER_H
#define THREADNOTIFIER_H
 
#include <e32base.h>
 
class CThreadNotifier : public CActive
{
public:
    CThreadNotifier();
    ~CThreadNotifier();
    void ConstructL();
 
    void IssueRequest();
 
protected:
    void RunL();
    void DoCancel();
    TInt RunError(TInt aError);
 
    RUndertaker iUndertaker;
    TInt iThreadHandle;
};
 
#endif
#include "ThreadNotifier.h"
 
#include <e32cons.h>
 
_LIT(KPanicMsg, "THREAD-NOTIFIER");
 
LOCAL_D CConsoleBase* console;
 
CThreadNotifier::CThreadNotifier()
    : CActive(CActive::EPriorityStandard)
{
    CActiveScheduler::Add(this);
}
 
void CThreadNotifier::ConstructL()
{
    User::LeaveIfError(iUndertaker.Create());
}
 
CThreadNotifier::~CThreadNotifier()
{
    Cancel();
    iUndertaker.Close();
}
 
void CThreadNotifier::IssueRequest()
{
    __ASSERT_ALWAYS(!IsActive(), User::Panic(KPanicMsg, 0));
 
    iUndertaker.Logon(iStatus, iThreadHandle);
    SetActive();
}
 
void CThreadNotifier::RunL()
{
    if (iStatus == KErrDied)
    {
        RThread thread;
        thread.SetHandle(iThreadHandle);
        console->Printf(_L("Thread %S (%d) died (Type: %d, reason %d)\n"), 
&thread.Name(), (int)thread.Id(), thread.ExitType(), thread.ExitReason());
        thread.Close();
    }
 
    IssueRequest();
}
 
void CThreadNotifier::DoCancel()
{
    iUndertaker.LogonCancel();
}
 
TInt CThreadNotifier::RunError(TInt /*aError*/)
{
    return KErrNone;
}
 
 
LOCAL_C void callExampleL()
{
    console = Console::NewL(_L("Thread Notifier"), TSize(KDefaultConsWidth, 
 KDefaultConsHeight));
    CleanupStack::PushL(console);
 
    CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
    CleanupStack::PushL(scheduler);
    CActiveScheduler::Install(scheduler);
 
    CThreadNotifier* notifier = new(ELeave) CThreadNotifier;
    CleanupStack::PushL(notifier);
    notifier->ConstructL();
    notifier->IssueRequest();
 
    CActiveScheduler::Start();
 
    CleanupStack::PopAndDestroy(3, console);    // console, scheduler, notifier
}
 
GLDEF_C TInt E32Main()
{
    __UHEAP_MARK;
    CTrapCleanup* cleanup = CTrapCleanup::New();
    TRAPD(error, callExampleL());
    __ASSERT_ALWAYS(!error, User::Panic(KPanicMsg, error));
    delete cleanup;
    __UHEAP_MARKEND;
    return 0;
}
Related Discussions
Thread Thread Starter Forum Replies Last Post
does not work CancelAsyncRequest Method. Tanya General Symbian C++ 9 2007-12-03 06:14
How can I catch the exception of .c in Symbian xmnlk General Symbian C++ 2 2008-06-03 04:38
panic USER-EXEC 3 jmatulja General Symbian C++ 7 2003-11-21 09:23
OverwritecolorL is crashing in S60 gigglie General Symbian C++ 5 2008-04-01 02:54
Nokia Screen lock-up sgreid101 Mobile Java General 2 2006-11-22 15:00
 
Powered by MediaWiki
     
     RDF Facets:
     
     
     qfnZtypeQUqfnTypeZCommunityContentQ
     qfnZtypeQUqfnTypeZWebpageQ
     qfnZtypeQUqfnTypeZWikiContentQ
     qmarsZlanguageQUxhttpE3aE2fE2fswE2enokiaE2ecomE2flanguageE2d1E2fenX
     
    
            
            RDF Facets:
            
            
                        qfnZuserE5ftagQSxconsoleX
                        qfnZuserE5ftagQSxthreadX
                        qfnZuserE5ftagQSxwriteX