diff -r e8e63152f320 -r 2a9601315dfc javacommons/jvms/j9utils/threaddump/src/j9threaddumper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javacommons/jvms/j9utils/threaddump/src/j9threaddumper.cpp Mon May 03 12:27:20 2010 +0300 @@ -0,0 +1,316 @@ +/* +* Copyright (c) 2009 - 2010 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: Thread dump server of J9 VM in S60, +* +*/ + + +#include // Needed for strcmp + +#include "logger.h" +#include "fileutilities.h" +#include "exceptionbase.h" +#include "javacommonutils.h" +#include "javasymbianoslayer.h" + +#include "j9threaddumper.h" + +using namespace java::util; + +// ======== STATIC VARIABLES ======== + +OS_NONSHARABLE_CLASS(ThreadDumperGlobals) +{ +public: + ThreadDumperGlobals() : mDumper(0) + { + } + +public: + J9ThreadDumper* mDumper; +}; + + +#if defined(__WINSCW__) + +#include +ThreadDumperGlobals* getThreadDumperGlobals() +{ + // Access the PLS of this process + ThreadDumperGlobals* globals = + Pls(TUid::Uid(0x20022E77)); + return globals; +} + +#else + +static ThreadDumperGlobals* sGlobals = 0; + +ThreadDumperGlobals* getThreadDumperGlobals() +{ + if (sGlobals == 0) + { + sGlobals = new ThreadDumperGlobals(); + } + return sGlobals; +} +#endif + + +// Function prototypes +void JNICALL agentThread(void* args); +jint JNICALL JVM_OnLoad(JavaVM* vm, char* options, void* reserved); + + + +J9ThreadDumper::J9ThreadDumper(JavaVM* vm, DgRasInterface* jvmri) : + mJavaVM(vm), mJNIEnv(0), mJvmriInterface(jvmri), + mTask(NO_TASK), mState(CREATED) +{ + JELOG2(EJavaRuntime); +} + +J9ThreadDumper::~J9ThreadDumper() +{ + JELOG2(EJavaRuntime); +} + + +void JNICALL agentThread(void* /*args*/) +{ +#ifdef __SYMBIAN32__ + RThread().SetPriority(EPriorityMore); +#endif // __SYMBIAN32__ + JELOG2(EJavaRuntime); + getThreadDumperGlobals()->mDumper->doRun(); + delete getThreadDumperGlobals()->mDumper; + getThreadDumperGlobals()->mDumper = 0; +#ifndef __WINSCW__ + delete sGlobals; + sGlobals = 0; +#endif + +} + +void J9ThreadDumper::doDump() +{ + JELOG2(EJavaRuntime); + mTask = DO_DUMP; + wakeUp(); +} + +void J9ThreadDumper::close() +{ + JELOG2(EJavaRuntime); + mTask = CLOSE; + wakeUp(); + mState = CLOSED; +} + + + +void J9ThreadDumper::moveGeneratedDumpFile() +{ +#ifdef __SYMBIAN32__ + JELOG2(EJavaRuntime); + const wchar_t* const midpPrivateDataCage = L"c:\\private\\102033E6"; + const wchar_t* const destRoot = L"c:\\logs\\java\\"; + + + // Ensure that the target dir exists. + std::wstring dest(destRoot); + std::replace(dest.begin(), dest.end(), '\\', '/'); + java::fileutils::FileUtilities::makeDirAll(dest); + + // Get all the files of the private data cage. + std::list dirList = java::fileutils::FileUtilities::getDirContentsList(midpPrivateDataCage); + + // Loop all existing files and try to find generated core dumps. + std::list::const_iterator it; + for (it = dirList.begin(); it != dirList.end(); it++) + { + if (it->find(L"javacore.") == 0) + { + std::wstring oldName(midpPrivateDataCage); + oldName += L"\\"; + oldName += *it; + std::wstring newName(destRoot); + newName += *it; + + char* oldUtf8Name = JavaCommonUtils::wstringToUtf8(oldName); + char* newUtf8Name = JavaCommonUtils::wstringToUtf8(newName); + + int error = rename(oldUtf8Name, newUtf8Name); + delete[] oldUtf8Name; + delete[] newUtf8Name; + } + } +#endif // __SYMBIAN32__ +} + +void J9ThreadDumper::wakeUp() +{ + JELOG2(EJavaRuntime); + if (mState == ACTIVE) + { + mMonitor->notify(); + } +} + +void J9ThreadDumper::doRun() +{ + JELOG2(EJavaRuntime); + if (mState != CREATED) + { + return; + } + + int status = mJavaVM->AttachCurrentThreadAsDaemon((void**)&mJNIEnv, 0); + if (status == 0) + { + mMonitor.reset(Monitor::createMonitor()); + mState = ACTIVE; + while (mState == ACTIVE) + { + mMonitor->wait(); + switch (mTask) + { + case DO_DUMP: + mJvmriInterface->GenerateJavacore(mJNIEnv); + moveGeneratedDumpFile(); + break; + case CLOSE: + mState = CLOSED; + break; + } + mTask = NO_TASK; + } + mJavaVM->DetachCurrentThread(); + } + else + { + ELOG1(EUtils, "Thread dumper failed to attach to VM: %d", status); + } +} + +JNIEXPORT jint JNICALL JVM_OnLoad(JavaVM* vm, char* options, void* /*reserved*/) +{ + JELOG2(EJavaRuntime); + int rc = -1; + JNIEnv* env; + + try + { + // Get the JNIEnv for the current thread + rc = vm->GetEnv((void **)&env, JNI_VERSION_1_2); + if (rc != JNI_OK) + { + // No JNIEnv; fail + return JNI_ERR; + } + + // Get the RAS Interface + DgRasInterface* jvmriInterface; + rc = vm->GetEnv((void **)&jvmriInterface, JVMRAS_VERSION_1_3); + if (rc != JNI_OK) + { + // No RAS Interface available; fail + return JNI_ERR; + } + + getThreadDumperGlobals()->mDumper = new J9ThreadDumper(vm, jvmriInterface); + + if (options != 0) + { + LOG1(EUtils, EInfo, "Dump options = %s", options); + } + // Request creation of the agent thread + rc = jvmriInterface->CreateThread(env, agentThread,0 , 0); + } + + catch (ExceptionBase& ex) + { + ELOG1(EJavaRuntime,"ERROR in Thread Dump. ExceptionBase: %s",ex.toString().c_str()); + } + catch (std::exception& e) + { + + ELOG1(EJavaRuntime,"ERROR in Thread Dump. std::exception: %s",e.what()); + } + catch (...) + { + ELOG(EJavaRuntime,"ERROR in Thread Dump. Unexpected exception was caught"); + } + return rc; +} + +// Keep this in sync with typedef in threaddumper.h file +void doThreadDump() +{ + JELOG2(EJavaRuntime); + J9ThreadDumper* instance = getThreadDumperGlobals()->mDumper; + if (instance) + { + instance->doDump(); + } +#ifndef __WINSCW__ + else + { + delete sGlobals; + sGlobals = 0; + } +#endif +} + +// Keep this in sync with typedef in threaddumper.h file +void closeThreadDump() +{ + JELOG2(EJavaRuntime); + J9ThreadDumper* instance = getThreadDumperGlobals()->mDumper; + if (instance) + { + instance->close(); + } +#ifndef __WINSCW__ + else + { + delete sGlobals; + sGlobals = 0; + } +#endif +} + + +#ifdef __SYMBIAN32__ +EXPORT_C FuncPtr JNICALL jni_lookup(const char* aName) +{ + JELOG2(EJavaRuntime); + if (!strcmp(aName, "JVM_OnLoad")) + { + return (FuncPtr)JVM_OnLoad; + } + + else if (!strcmp(aName, "doThreadDump")) + { + return (FuncPtr)doThreadDump; + } + + else if (!strcmp(aName, "closeThreadDump")) + { + return (FuncPtr)closeThreadDump; + } + + return 0; +} +#endif // __SYMBIAN32__