javacommons/jvms/j9utils/threaddump/src/j9threaddumper.cpp
branchRCL_3
changeset 19 04becd199f91
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/jvms/j9utils/threaddump/src/j9threaddumper.cpp	Tue Apr 27 16:30:29 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 <string> // 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 <pls.h>
+ThreadDumperGlobals* getThreadDumperGlobals()
+{
+    // Access the PLS of this process
+    ThreadDumperGlobals* globals  =
+        Pls<ThreadDumperGlobals>(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<std::wstring> dirList = java::fileutils::FileUtilities::getDirContentsList(midpPrivateDataCage);
+
+    // Loop all existing files and try to find generated core dumps.
+    std::list<std::wstring>::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__