javaruntimes/starterutils/src.s60/osthreadsupervisor.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 15 Sep 2010 12:05:25 +0300
branchRCL_3
changeset 77 7cee158cb8cd
parent 19 04becd199f91
permissions -rw-r--r--
Revision: v2.2.13 Kit: 201036

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  This class is for thread death monitoring.
*
*/

#include <e32base.h>

#include "osthreadsupervisor.h"

#include "runtimeexception.h"

#include "logger.h"
#include "javacommonutils.h"

using namespace java::runtime;
using namespace java::util;


OsThreadSupervisor::OsThreadSupervisor(bool tryThreadDumping) :
        mDoExit(false), mTryThreadDump(tryThreadDumping)
{
    JELOG2(EJavaRuntime);
    startUndertakerThread();
}

OsThreadSupervisor::~OsThreadSupervisor()
{
    JELOG2(EJavaRuntime);
    // Wake the undertaker thread in order to close it.
    mDoExit = true;
    mRequestStatus = KRequestPending;
    TRequestStatus* requestStatus = &mRequestStatus;
    mSupervisorThread.RequestComplete(requestStatus, KErrNone);
    mSupervisorThread.Close();
}


void OsThreadSupervisor::startUndertakerThread()
{
    JELOG2(EJavaRuntime);
    RThread thread;

    // Create the undertaker thread.
    _LIT(KUndertakerName, "JavaMidp undertaker");
    TInt err = thread.Create(KUndertakerName,
                             OsThreadSupervisor::underTakerThreadMain,
                             0x2000, 0, this);

    if (err == KErrNone)
    {
        // Set the prioroty to high.
        thread.SetPriority(EPriorityMuchMore);
        thread.Resume();
        thread.Close();
    }
    else
    {
        thread.Close();
        std::string errorStr("Not able to create undertaker thread. Reason: ");
        errorStr.append(JavaCommonUtils::intToString(err));
        throw RuntimeException(errorStr, __FILE__, __FUNCTION__, __LINE__);
    }

}

int OsThreadSupervisor::underTakerThreadMain(void* starter)
{
    JELOG2(EJavaRuntime);
    OsThreadSupervisor* supervisor =
        reinterpret_cast<OsThreadSupervisor*>(starter);

    // Open the thread handle so that RequstComplete methods can be
    // called from another thread.
    supervisor->mSupervisorThread.Open(RThread().Id());

    RUndertaker underTaker;
    if (underTaker.Create() == KErrNone)
    {
        // Get the process id of this process.
        TProcessId processId = RProcess().Id();
        int status = KErrNone;
        LOG1(EJavaRuntime, EInfo, "Starting to monitor MIDP process %lld",
             processId.Id());
        // We will receive notification from ALL the thread deaths from all
        // processes. That is why the looping is needed.
        while (status == KErrNone)
        {
            int threadHandle;

            // Logon to monitor thread deaths.
            status = underTaker.Logon(supervisor->mRequestStatus, threadHandle);
            if (status != KErrNone)
            {
                ELOG1(EJavaRuntime, "Undertaker thread failed to do logon. "
                      " Reason: %d", status);
                break;
            }

            // Start to wait thread deaths or shutdown indication.
            User::WaitForRequest(supervisor->mRequestStatus);
            if (supervisor->mDoExit)
            {
                // We are going down, so no need to monitor thread deaths.
                // Closing the undertaker thread.
                LOG(EJavaRuntime, EInfo, "Undertaker closed succesfully");
                return 0;
            }
            RThread thread;
            thread.SetHandle(threadHandle);
            LOG2(EJavaRuntime, EInfo, "A thread %lld has died with exit type %d",
                 thread.Id().Id(), thread.ExitType());

            // We are only interested in panicing threads.
            if (thread.ExitType() == EExitPanic)
            {
                RProcess terminatedProcess;
                status = thread.Process(terminatedProcess);
                if (status == KErrNone)
                {
                    LOG2(EJavaRuntime, EInfo,
                         "Thread panic from process id: %lld. "
                         "Our id is: %lld",
                         terminatedProcess.Id().Id(), processId.Id());
                    // Check if this thread belong to our process.
                    if (terminatedProcess.Id() == processId)
                    {
                        // One of MIDP threads has paniced, so lets terminate
                        // the whole process.
                        status = KErrDied;
                    }
                    terminatedProcess.Close();
                }
                else
                {
                    ELOG1(EJavaRuntime, "Solving paniced thread's process "
                          "failed. Reason: %d", status);
                }
            }
            thread.Close();
        }
    }
    ELOG(EJavaRuntime, "Panic in one of the MIDP threads. Stopping process!");
    RProcess().Terminate(KErrAbort);
    return 0;
}