Mercurial > hg > heapstats
changeset 157:f3e6f861c1b2
Bug 2911: [REFACTORING][JDK 9] Refactoring signal handling mechanism
author | Yasumasa Suenaga <yasuenag@gmail.com> |
---|---|
date | Mon, 18 Apr 2016 21:28:04 +0900 |
parents | 6a568c9776c3 |
children | f5626d1b4522 |
files | agent/src/heapstats-engines/configuration.cpp agent/src/heapstats-engines/configuration.hpp agent/src/heapstats-engines/libmain.cpp agent/src/heapstats-engines/logMain.cpp agent/src/heapstats-engines/signalManager.cpp agent/src/heapstats-engines/signalManager.hpp agent/src/heapstats-engines/vmFunctions.cpp agent/src/heapstats-engines/vmFunctions.hpp |
diffstat | 8 files changed, 304 insertions(+), 653 deletions(-) [+] |
line wrap: on
line diff
--- a/agent/src/heapstats-engines/configuration.cpp Mon Apr 11 21:51:17 2016 +0900 +++ b/agent/src/heapstats-engines/configuration.cpp Mon Apr 18 21:28:04 2016 +0900 @@ -21,6 +21,7 @@ #include "globals.hpp" #include "fsUtil.hpp" +#include "signalManager.hpp" #include "configuration.hpp" #if USE_PCRE @@ -272,7 +273,7 @@ void TConfiguration::ReadSignalValue(const char *value, char **dest) { if (value == NULL) { *dest = NULL; - } else if (isSupportSignal(value)) { + } else if (TSignalManager::findSignal(value) != -1) { if (*dest != NULL) { free(*dest); } @@ -739,51 +740,6 @@ } } -/*! - * \brief Check signal is supported by JVM. - * \param sigName [in] Name of signal. - * \return Signal is supported, if value is true. - * Otherwise, value is false. - * \sa Please see below JDK source about JVM supported signal.<br> - * hotspot/src/os/linux/vm/jvm_linux.cpp - */ -bool TConfiguration::isSupportSignal(char const *sigName) { - /* JVM supported signals. */ - const char *supportSignals[] = { - /* POSIX signal. */ - "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT", "SIGFPE", - "SIGKILL", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM", "SIGUSR1", - "SIGUSR2", "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", "SIGTTIN", - "SIGTTOU", "SIGBUS", "SIGPOLL", "SIGTRAP", "SIGURG", "SIGVTALRM", - "SIGXCPU", "SIGXFSZ", "SIGPROF", - -#ifdef SIGSYS - "SIGSYS", -#endif - - /* Non-POSIX signal. */ - "SIGIOT", "SIGIO", "SIGCLD", "SIGPWR", "SIGWINCH", -#ifdef SIGSTKFLT - "SIGSTKFLT", -#endif - - /* End flag. */ - NULL - /* JVM was not supported below signal. */ - /* "SIGINFO", "SIGLOST", "SIGEMT", "SIGUNUSED" and etc.. */ - }; - - /* Search signal name. */ - for (int sigIdx = 0; supportSignals[sigIdx] != NULL; sigIdx++) { - if (strcmp(sigName, supportSignals[sigIdx]) == 0) { - /* Found. */ - return true; - } - } - - return false; -} - void TConfiguration::setLogLevel(TConfiguration *inst, TLogLevel val, TLogLevel *dest) { *dest = val;
--- a/agent/src/heapstats-engines/configuration.hpp Mon Apr 11 21:51:17 2016 +0900 +++ b/agent/src/heapstats-engines/configuration.hpp Mon Apr 18 21:28:04 2016 +0900 @@ -323,16 +323,6 @@ protected: /*! - * \brief Check signal is supported by JVM. - * \param sigName [in] Name of signal. - * \return Signal is supported, if value is true. - * Otherwise, value is false. - * \sa Please see below JDK source about JVM supported signal.<br> - * hotspot/src/os/linux/vm/jvm_linux.cpp - */ - bool isSupportSignal(char const *sigName); - - /*! * \brief Read string value from configuration. * \param value [in] Value of this configuration. * \param dest [in] [out] Destination of this configuration.
--- a/agent/src/heapstats-engines/libmain.cpp Mon Apr 11 21:51:17 2016 +0900 +++ b/agent/src/heapstats-engines/libmain.cpp Mon Apr 18 21:28:04 2016 +0900 @@ -2,7 +2,7 @@ * \file libmain.cpp * \brief This file is used to common works.<br> * e.g. initialization, finalization, etc... - * Copyright (C) 2011-2015 Nippon Telegraph and Telephone Corporation + * Copyright (C) 2011-2016 Nippon Telegraph and Telephone Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -105,7 +105,7 @@ * \param siginfo [in] Information of received signal. * \param data [in] Data of received signal. */ -void ReloadSigProc(int signo, void *siginfo, void *data) { +void ReloadSigProc(int signo, siginfo_t *siginfo, void *data) { /* Enable flag. */ flagReloadConfig = 1; NOTIFY_CATCH_SIGNAL; @@ -265,36 +265,24 @@ conf->validate(); } - /* If failure signal initialization. */ - if (unlikely(!TSignalManager::globalInitialize(env))) { - logger->printWarnMsg("Failure signal handler initialization."); - /* Disable many signal. */ - conf->TriggerOnLogSignal()->set(false); - conf->ReloadSignal()->set(NULL); - } - /* Initialize signal flag. */ flagReloadConfig = 0; /* Start HeapStats agent threads. */ - try { - reloadSigMngr = new TSignalManager(env, &ReloadSigProc); - - /* Switch reload signal state. */ - if (conf->ReloadSignal()->get() != NULL) { - /* Setting new reload signal. */ - if (unlikely( - !reloadSigMngr->catchSignal(env, conf->ReloadSignal()->get()))) { - /* Reload configuration signal is disable. */ - logger->printWarnMsg("Failure register reload configuration signal."); + if (conf->ReloadSignal()->get() != NULL) { + try { + reloadSigMngr = new TSignalManager(conf->ReloadSignal()->get()); + if (!reloadSigMngr->addHandler(&ReloadSigProc)) { + logger->printWarnMsg("Reload signal handler setup is failed."); conf->ReloadSignal()->set(NULL); } + } catch (const char *errMsg) { + logger->printWarnMsg(errMsg); + conf->ReloadSignal()->set(NULL); + } catch (...) { + logger->printWarnMsg("Reload signal handler setup is failed."); + conf->ReloadSignal()->set(NULL); } - - } catch (const char *errMsg) { - logger->printWarnMsg(errMsg); - } catch (...) { - logger->printWarnMsg("AgentThread start failed!"); } /* Calculate alert limit. */ @@ -389,11 +377,6 @@ /* If reload log signal is enabled. */ if (likely(reloadSigMngr != NULL)) { - /* Terminate reload signal manager. */ - if (likely(conf->ReloadSignal()->get() != NULL)) { - reloadSigMngr->ignoreSignal(env, conf->ReloadSignal()->get()); - } - reloadSigMngr->terminate(env); delete reloadSigMngr; reloadSigMngr = NULL; } @@ -413,9 +396,6 @@ conf->ThreadRecordFileName()->get()); } } - - /* Signal finalization. */ - TSignalManager::globalFinalize(env); } /*!
--- a/agent/src/heapstats-engines/logMain.cpp Mon Apr 11 21:51:17 2016 +0900 +++ b/agent/src/heapstats-engines/logMain.cpp Mon Apr 18 21:28:04 2016 +0900 @@ -1,7 +1,7 @@ /*! * \file logmain.cpp * \brief This file is used common logging process. - * Copyright (C) 2011-2015 Nippon Telegraph and Telephone Corporation + * Copyright (C) 2011-2016 Nippon Telegraph and Telephone Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -108,7 +108,7 @@ * \param siginfo [in] Information of received signal. * \param data [in] Data of received signal. */ -void normalLogProc(int signo, void *siginfo, void *data) { +void normalLogProc(int signo, siginfo_t *siginfo, void *data) { /* Enable flag. */ flagLogSignal = 1; NOTIFY_CATCH_SIGNAL; @@ -120,7 +120,7 @@ * \param siginfo [in] Information of received signal. * \param data [in] Data of received signal. */ -void anotherLogProc(int signo, void *siginfo, void *data) { +void anotherLogProc(int signo, siginfo_t *siginfo, void *data) { /* Enable flag. */ flagAllLogSignal = 1; NOTIFY_CATCH_SIGNAL; @@ -365,45 +365,37 @@ flagLogSignal = 0; flagAllLogSignal = 0; - /* Signal enable flag. */ - bool enableNormalSig = (conf->LogSignalNormal()->get() != NULL); - bool enableAllSig = (conf->LogSignalAll()->get() != NULL); - - try { - /* Create instance for log signal. */ - logSignalMngr = new TSignalManager(env, &normalLogProc); - logAllSignalMngr = new TSignalManager(env, &anotherLogProc); - - if (conf->TriggerOnLogSignal()->get()) { - /* If "normal log signal" is designated. */ - if (enableNormalSig) { - /* Enable signal handling. */ - if (unlikely(!logSignalMngr->catchSignal( - env, conf->LogSignalNormal()->get()))) { - logger->printWarnMsg("Failure register normal log signal."); - /* Normal log signal is disable. */ - conf->LogSignalNormal()->set(NULL); - } + /* Signal handler setup */ + if (conf->LogSignalNormal()->get() != NULL) { + try { + logSignalMngr = new TSignalManager(conf->LogSignalNormal()->get()); + if (!logSignalMngr->addHandler(&normalLogProc)) { + logger->printWarnMsg("Log normal signal handler setup is failed."); + conf->LogSignalNormal()->set(NULL); } + } catch (const char *errMsg) { + logger->printWarnMsg(errMsg); + conf->LogSignalNormal()->set(NULL); + } catch (...) { + logger->printWarnMsg("Log normal signal handler setup is failed."); + conf->LogSignalNormal()->set(NULL); + } + } - /* If "all log signal" is designated. */ - if (enableAllSig) { - /* Enable signal handling. */ - if (unlikely(!logAllSignalMngr->catchSignal( - env, conf->LogSignalAll()->get()))) { - logger->printWarnMsg("Failure register all log signal."); - /* All log signal is disable. */ - conf->LogSignalAll()->set(NULL); - } + if (conf->LogSignalAll()->get() != NULL) { + try { + logAllSignalMngr = new TSignalManager(conf->LogSignalAll()->get()); + if (!logAllSignalMngr->addHandler(&anotherLogProc)) { + logger->printWarnMsg("Log all signal handler setup is failed."); + conf->LogSignalAll()->set(NULL); } + } catch (const char *errMsg) { + logger->printWarnMsg(errMsg); + conf->LogSignalAll()->set(NULL); + } catch (...) { + logger->printWarnMsg("Log all signal handler setup is failed."); + conf->LogSignalAll()->set(NULL); } - } catch (const char *errMsg) { - logger->printWarnMsg(errMsg); - conf->TriggerOnLogSignal()->set(false); - - } catch (...) { - logger->printWarnMsg("Signal handler start failed!"); - conf->TriggerOnLogSignal()->set(false); } } @@ -413,30 +405,13 @@ * \param env [in] JNI environment object. */ void onVMDeathForLog(jvmtiEnv *jvmti, JNIEnv *env) { - /* Flag of signal enable. */ - bool enableNormalSig = conf->Attach()->get() && - conf->TriggerOnLogSignal()->get() && - (conf->LogSignalNormal()->get() != NULL); - bool enableAllSig = conf->Attach()->get() && - conf->TriggerOnLogSignal()->get() && - (conf->LogSignalAll()->get() != NULL); - - /* If normal log signal is enabled. */ - if (likely(logSignalMngr != NULL)) { - /* Terminate normal log signal manager. */ - if (enableNormalSig) { - logSignalMngr->ignoreSignal(env, conf->LogSignalNormal()->get()); - } - logSignalMngr->terminate(env); + if (logSignalMngr != NULL) { + delete logSignalMngr; + logSignalMngr = NULL; } - - /* If all log signal is enabled. */ - if (likely(logAllSignalMngr != NULL)) { - /* Terminate all log signal manager. */ - if (enableAllSig) { - logAllSignalMngr->ignoreSignal(env, conf->LogSignalAll()->get()); - } - logAllSignalMngr->terminate(env); + if (logAllSignalMngr != NULL) { + delete logAllSignalMngr; + logAllSignalMngr = NULL; } }
--- a/agent/src/heapstats-engines/signalManager.cpp Mon Apr 11 21:51:17 2016 +0900 +++ b/agent/src/heapstats-engines/signalManager.cpp Mon Apr 18 21:28:04 2016 +0900 @@ -1,7 +1,7 @@ /*! * \file signalManager.cpp * \brief This file is used by signal handling. - * Copyright (C) 2011-2015 Nippon Telegraph and Telephone Corporation + * Copyright (C) 2011-2016 Nippon Telegraph and Telephone Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -19,418 +19,137 @@ * */ +#include <signal.h> + #include "globals.hpp" +#include "vmFunctions.hpp" #include "signalManager.hpp" -/* Class static variables. */ + +static TSignalHandlerChain *sighandlers[NSIG] = {0}; -/*! - * \brief Object of "NativeSignalHandler" class information. - */ -jclass TSignalManager::classNativeHandler = NULL; -/*! - * \brief Object of "Signal" class information. - */ -jclass TSignalManager::classSignal = NULL; -/*! - * \brief Object of "String" class information. - */ -jclass TSignalManager::classString = NULL; +static TSignalMap signalMap[] = + { + {SIGHUP, "SIGHUP"}, {SIGALRM, "SIGALRM"}, {SIGUSR1, "SIGUSR1"}, + {SIGUSR2, "SIGUSR2"}, {SIGTSTP, "SIGTSTP"}, {SIGTTIN, "SIGTTIN"}, + {SIGTTOU, "SIGTTOU"}, {SIGPOLL, "SIGPOLL"}, {SIGVTALRM, "SIGVTALRM"}, + {SIGIOT, "SIGIOT"}, {SIGWINCH, "SIGWINCH"} + }; + + +void SignalHandlerStub(int signo, siginfo_t *siginfo, void *data) { + TSignalHandlerChain *chain = sighandlers[signo]; + TVMFunctions *vmFunc = TVMFunctions::getInstance(); -/*! - * \brief Constructor of "NativeSignalHandler" class. - */ -jmethodID TSignalManager::nativeHandler_init = NULL; -/*! - * \brief Constructor of "Signal" class. - */ -jmethodID TSignalManager::signal_init = NULL; -/*! - * \brief Constructor of "String" class. - */ -jmethodID TSignalManager::string_init = NULL; -/*! - * \brief Method "handle" of "Signal" class. - */ -jmethodID TSignalManager::signal_handle = NULL; + while (chain != NULL) { + if ((void *)chain->handler == vmFunc->GetSRHandlerPointer()) { + /* SR handler should be called in HotSpot Thread context. */ + if (vmFunc->GetThread() != NULL) { + chain->handler(signo, siginfo, data); + } + } else if (((void *)chain->handler == vmFunc->GetUserHandlerPointer()) && + (signo == SIGHUP)) { + // This might SHUTDOWN1_SIGNAL handler which is defined in + // java.lang.Terminator . (Unix class) + // We should ignore this signal. -/*! - * \brief Default signal handler. - */ -jobject TSignalManager::signal_DFL = NULL; + // Do nothing. + } else if ((void *)chain->handler != SIG_IGN) { + chain->handler(signo, siginfo, data); + } -/*! - * \brief Flag of load initialize data. - */ -bool TSignalManager::loadFlag = false; + chain = chain->next; + } +} + /* Class methods. */ /*! - * \brief TSignalManager constructor. - * \param env [in] JNI environment object. - * \param proc [in] Pointer of signal callback. + * \brief Find signal number from name. + * \param sig Signal name. + * \return Signal number. Return -1 if not found. */ -TSignalManager::TSignalManager(JNIEnv *env, TSignalHandler proc) { - /* If don't loaded data yet. */ - if (unlikely(!loadFlag)) { - throw "Didn't initialize signal handler yet."; +int TSignalManager::findSignal(const char *sig) { + for (size_t idx = 0; idx < (sizeof(signalMap) / sizeof(TSignalMap)); idx++) { + if (strcmp(signalMap[idx].name, sig) == 0){ + return signalMap[idx].sig; + } } - /* Create signal handler on JVM. */ - jobject localSigHandler = env->NewObject( - classNativeHandler, nativeHandler_init, (jlong)((ptrdiff_t)proc)); - - /* If failure create signal handler. */ - if (unlikely(localSigHandler == NULL)) { - handlePendingException(env); - throw "Failure create signal handler."; - } + return -1; +} - /* Get global referrence. */ - insSignalHandler = env->NewGlobalRef(localSigHandler); +/*! + * \brief TSignalManager constructor. + * \param sig Signal string. + */ +TSignalManager::TSignalManager(const char *sig) { + this->signal = findSignal(sig); - /* If failure get global referrence. */ - if (unlikely(insSignalHandler == NULL)) { - handlePendingException(env); - env->DeleteLocalRef(localSigHandler); - throw "Failure create signal handler."; + if (this->signal == -1) { + static char errstr[1024]; + snprintf(errstr, 1024, "Invalid signal: %s", sig); + throw errstr; } - - env->DeleteLocalRef(localSigHandler); } /*! * \brief TSignalManager destructor. */ -TSignalManager::~TSignalManager(void) { /* None. */ } - -/*! - * \brief Add signal which is handled. - * \param env [in] JNI environment object. - * \param sigName [in] Name of signal. - * \return Process is succeed, if value is true.<br> - * Process is failure, if value is false. - */ -bool TSignalManager::catchSignal(JNIEnv *env, char *sigName) { - /* Set user's signal handler. */ - return setSignalHandler(env, sigName, insSignalHandler); -} +TSignalManager::~TSignalManager() { + TSignalHandlerChain *chain = sighandlers[this->signal]; + JVM_RegisterSignal(this->signal, (void *)chain->handler); -/*! - * \brief Specify signal to ignore. - * \param env [in] JNI environment object. - * \param sigName [in] Name of signal. - * \return Process is succeed, if value is true.<br> - * Process is failure, if value is false. - */ -bool TSignalManager::ignoreSignal(JNIEnv *env, char *sigName) { - /* Set default signal handler. */ - return setSignalHandler(env, sigName, signal_DFL); -} - -/*! - * \brief Terminate handling signal. - * \param env [in] JNI environment object. - */ -void TSignalManager::terminate(JNIEnv *env) { - /* Sanity check. */ - if (likely(insSignalHandler != NULL)) { - /* Delete global reference. */ - env->DeleteGlobalRef(insSignalHandler); - insSignalHandler = NULL; + while (chain != NULL) { + TSignalHandlerChain *next = chain->next; + free(chain); + chain = next; } } /*! - * \brief Global initialization. - * \param env [in] JNI environment object. - * \return Process is succeed, if value is true.<br> - * Process is failure, if value is false. - * \warning Please call only once from main thread. + * \brief Add signal handler. + * \param handler [in] Function pointer for signal handler. + * \return true if new signal handler is added. */ -bool TSignalManager::globalInitialize(JNIEnv *env) { - /* If already loaded data. */ - if (loadFlag) { - logger->printWarnMsg("Already initialized signal manager."); - return true; - } - loadFlag = true; - - /* Search class. */ +bool TSignalManager::addHandler(TSignalHandler handler) { + TSignalHandlerChain *chain = sighandlers[this->signal]; - /* Search class list. */ - struct { - jclass *pClass; - char className[255]; - jmethodID *pClassInit; - char initArgs[255]; - } loadClassList[] = { - {&classNativeHandler, "Lsun/misc/NativeSignalHandler;", - &nativeHandler_init, "(J)V"}, - {&classSignal, "Lsun/misc/Signal;", &signal_init, - "(Ljava/lang/String;)V"}, - {&classString, "Ljava/lang/String;", &string_init, "([B)V"}, - {NULL, {0}, NULL, {0}} /* End flag. */ - }; + if (chain == NULL) { + TSignalHandler oldHandler = (TSignalHandler)JVM_RegisterSignal( + this->signal, (void *)&SignalHandlerStub); - /* Search class and get global reference. */ - for (int i = 0; loadClassList[i].pClass != NULL; i++) { - /* Find java class. */ - jclass localRefClass = env->FindClass(loadClassList[i].className); - /* If not found common class. */ - if (unlikely(localRefClass == NULL)) { - handlePendingException(env); - - logger->printWarnMsg("Couldn't get common class."); + if ((ptrdiff_t)oldHandler == -1L) { // Cannot set return false; - } - - /* Get global reference. */ - (*loadClassList[i].pClass) = (jclass)env->NewGlobalRef(localRefClass); - /* If failure getting global reference. */ - if (unlikely((*loadClassList[i].pClass) == NULL)) { - handlePendingException(env); - - logger->printWarnMsg("Couldn't get global reference."); - return false; + } else if ((ptrdiff_t)oldHandler == 1L) { // Ignore signal + oldHandler = (TSignalHandler)SIG_IGN; + } else if ((ptrdiff_t)oldHandler == 2L) { // User Handler in HotSpot + oldHandler = + (TSignalHandler)TVMFunctions::getInstance()->GetUserHandlerPointer(); } - /* Get class constructor. */ - (*loadClassList[i].pClassInit) = - env->GetMethodID(localRefClass, "<init>", loadClassList[i].initArgs); - /* If failure getting constructor. */ - if (unlikely((*loadClassList[i].pClassInit) == NULL)) { - handlePendingException(env); + chain = (TSignalHandlerChain *)calloc(1, sizeof(TSignalHandlerChain)); - logger->printWarnMsg("Couldn't get constructor of common class."); - return false; + if (chain == NULL) { + throw errno; } - /* Clearup. */ - env->DeleteLocalRef(localRefClass); - } - - /* Search method. */ - - /* Get "Signal" class "handle" method. */ - signal_handle = env->GetStaticMethodID( - classSignal, "handle", - "(Lsun/misc/Signal;Lsun/misc/SignalHandler;)Lsun/misc/SignalHandler;"); - /* If failure getting "handle" function. */ - if (unlikely(signal_handle == NULL)) { - handlePendingException(env); - - logger->printWarnMsg("Couldn't get function of signal handling."); - return false; + chain->handler = oldHandler; + sighandlers[this->signal] = chain; } - /* Search default signal handler. */ - return getDefaultSignalHandler(env); -} - -/*! - * \brief Global finalize. - * \param env [in] JNI environment object. - * \return Process is succeed, if value is true.<br> - * Process is failure, if value is false. - * \warning Please call only once from main thread. - */ -bool TSignalManager::globalFinalize(JNIEnv *env) { - /* Sanity check. */ - if (!loadFlag) { - logger->printWarnMsg("Didn't initialize signal manager yet."); - return false; - } - loadFlag = false; - - /* Delete common data's global reference. */ - if (likely(classNativeHandler != NULL)) { - env->DeleteGlobalRef(classNativeHandler); - classNativeHandler = NULL; - } - if (likely(classSignal != NULL)) { - env->DeleteGlobalRef(classSignal); - classSignal = NULL; - } - if (likely(classString != NULL)) { - env->DeleteGlobalRef(classString); - classString = NULL; - } - if (likely(signal_DFL != NULL)) { - env->DeleteGlobalRef(signal_DFL); - signal_DFL = NULL; + while (chain->next != NULL) { + chain = chain->next; } + chain->next = (TSignalHandlerChain *)calloc(1, sizeof(TSignalHandlerChain)); + + if (chain->next == NULL) { + throw errno; + } + + chain->next->handler = handler; return true; } -/*! - * \brief Setting signal handle function. - * \param env [in] JNI environment object. - * \param sigName [in] Name of signal. - * \param handler [in] Setting signal handler. - * \return Process is succeed, if value is true.<br> - * Process is failure, if value is false. - */ -bool TSignalManager::setSignalHandler(JNIEnv *env, char *sigName, - jobject handler) { - /* Sanity check. */ - if (unlikely(insSignalHandler == NULL)) { - logger->printWarnMsg("Illegal signal handler."); - return false; - } - - jobject insSignal = NULL; - jobject olderHandler = NULL; - jstring javaSigName = NULL; - - /* Create string in java (We should cut SIG from sigName) */ - if (unlikely(!createJString(env, sigName + 3, &javaSigName))) { - logger->printWarnMsg("Couldn't create java string."); - return false; - } - - /* Create signal object */ - insSignal = env->NewObject(classSignal, signal_init, javaSigName); - if (unlikely(insSignal == NULL)) { - handlePendingException(env); - - logger->printWarnMsg("Couldn't create signal object."); - env->DeleteLocalRef(javaSigName); - return false; - } - - /* Setting signal handler. */ - olderHandler = env->CallStaticObjectMethod(classSignal, signal_handle, - insSignal, handler); - /* If failure setting signal handler. */ - if (unlikely(env->ExceptionOccurred() != NULL)) { - handlePendingException(env); - - logger->printWarnMsg("Couldn't set signal handler."); - env->DeleteLocalRef(javaSigName); - env->DeleteLocalRef(insSignal); - return false; - } - - /* Cleanup. */ - env->DeleteLocalRef(olderHandler); - env->DeleteLocalRef(javaSigName); - env->DeleteLocalRef(insSignal); - - return true; -} - -/*! - * \brief Convert string from C++ native to java. - * \param env [in] JNI environment object. - * \param nativeStr [in] String in C++. - * \param javaStr [in,out] String object in java. - * \return Process is succeed, if value is true.<br> - * Process is failure, if value is false. - */ -bool TSignalManager::createJString(JNIEnv *env, char *nativeStr, - jstring *javaStr) { - /* Sanity check. */ - if (unlikely(nativeStr == NULL || strlen(nativeStr) == 0)) { - logger->printWarnMsg("Illegal native string."); - return false; - } - - jbyteArray byteArray = NULL; - size_t strLen = strlen(nativeStr); - - /* Creaet source byte array. */ - byteArray = env->NewByteArray(strLen); - if (unlikely(byteArray == NULL)) { - handlePendingException(env); - - logger->printWarnMsg("Couldn't create byte array."); - return false; - } - - /* Copy native string to byte array. */ - env->SetByteArrayRegion(byteArray, 0, strLen, (jbyte *)nativeStr); - if (unlikely(env->ExceptionOccurred() != NULL)) { - handlePendingException(env); - - logger->printWarnMsg("Couldn't copy to byte array."); - env->DeleteLocalRef(byteArray); - return false; - } - - /* Create java string object. */ - *javaStr = (jstring)env->NewObject(classString, string_init, byteArray); - /* if failure create java string. */ - if (unlikely(*javaStr == NULL)) { - handlePendingException(env); - - logger->printWarnMsg("Couldn't create string object."); - env->DeleteLocalRef(byteArray); - return false; - } - - /* Cleanup. */ - env->DeleteLocalRef(byteArray); - - return true; -} - -/*! - * \brief Getting default signal handler in JVM. - * \param env [in] JNI environment object. - * \return Process is succeed, if value is true.<br> - * Process is failure, if value is false. - */ -bool TSignalManager::getDefaultSignalHandler(JNIEnv *env) { - /* Find "SignalHandler" class. */ - jclass classSignalHandler = env->FindClass("Lsun/misc/SignalHandler;"); - /* If failure signalhandler class. */ - if (unlikely(classSignalHandler == NULL)) { - handlePendingException(env); - - logger->printWarnMsg("Failure getting class of default signal handler."); - return false; - } - - /* Find static field. */ - jfieldID sigDFL = env->GetStaticFieldID(classSignalHandler, "SIG_DFL", - "Lsun/misc/SignalHandler;"); - /* If not found default signal handler. */ - if (unlikely(sigDFL == NULL)) { - handlePendingException(env); - - logger->printWarnMsg("Couldn't get fieldID of default signal handler."); - env->DeleteLocalRef(classSignalHandler); - return false; - } - - /* Get static field reference. */ - jobject localSigDFL = env->GetStaticObjectField(classSignalHandler, sigDFL); - /* If failure getting field. */ - if (unlikely(localSigDFL == NULL)) { - handlePendingException(env); - - logger->printWarnMsg("Couldn't get value of default signal handler."); - env->DeleteLocalRef(classSignalHandler); - return false; - } - - /* Get global reference. */ - signal_DFL = env->NewGlobalRef(localSigDFL); - if (unlikely(signal_DFL == NULL)) { - handlePendingException(env); - - logger->printWarnMsg("Couldn't get global reference."); - env->DeleteLocalRef(localSigDFL); - env->DeleteLocalRef(classSignalHandler); - return false; - } - - /* Cleanup. */ - env->DeleteLocalRef(localSigDFL); - env->DeleteLocalRef(classSignalHandler); - - return true; -}
--- a/agent/src/heapstats-engines/signalManager.hpp Mon Apr 11 21:51:17 2016 +0900 +++ b/agent/src/heapstats-engines/signalManager.hpp Mon Apr 18 21:28:04 2016 +0900 @@ -1,7 +1,7 @@ /*! * \file signalManager.hpp * \brief This file is used by signal handling. - * Copyright (C) 2011-2015 Nippon Telegraph and Telephone Corporation + * Copyright (C) 2011-2016 Nippon Telegraph and Telephone Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -22,6 +22,9 @@ #ifndef _SIGNAL_MNGR_H #define _SIGNAL_MNGR_H +#include <jni.h> +#include <signal.h> + #include "util.hpp" /*! @@ -31,146 +34,62 @@ * But this value is always null. * \param data [in] Data of received signal.<br> * But this value is always null. - * \sa Please see JDK source about "siginfo" and "data" is always null.<br> - * jdk/src/share/native/sun/misc/NativeSignalHandler.c * \warning Function must be signal-safe. */ -typedef void (*TSignalHandler)(int signo, void *siginfo, void *data); +typedef void (*TSignalHandler)(int signo, siginfo_t *siginfo, void *data); + +typedef struct structSignalHandlerChain { + TSignalHandler handler; + structSignalHandlerChain *next; +} TSignalHandlerChain; + +typedef struct { + int sig; + const char *name; +} TSignalMap; + /*! * \brief This class is handling signal. */ class TSignalManager { - public: - /*! - * \brief TSignalManager constructor. - * \param env [in] JNI environment object. - * \param proc [in] Pointer of signal callback. - */ - TSignalManager(JNIEnv *env, TSignalHandler proc); - - /*! - * \brief TSignalManager destructor. - */ - virtual ~TSignalManager(void); - - /*! - * \brief Add signal which is handled. - * \param env [in] JNI environment object. - * \param sigName [in] Name of signal. - * \return Process is succeed, if value is true.<br> - * Process is failure, if value is false. - */ - bool catchSignal(JNIEnv *env, char *sigName); - /*! - * \brief Specify signal to ignore. - * \param env [in] JNI environment object. - * \param sigName [in] Name of signal. - * \return Process is succeed, if value is true.<br> - * Process is failure, if value is false. - */ - bool ignoreSignal(JNIEnv *env, char *sigName); - - /*! - * \brief Terminate handling signal. - * \param env [in] JNI environment object. - */ - void terminate(JNIEnv *env); + private: + /*! + * \brief Signal number for this instance. + */ + int signal; - /*! - * \brief Global initialization. - * \param env [in] JNI environment object. - * \return Process is succeed, if value is true.<br> - * Process is failure, if value is false. - * \warning Please call only once from main thread. - */ - static bool globalInitialize(JNIEnv *env); - - /*! - * \brief Global finalize. - * \param env [in] JNI environment object. - * \return Process is succeed, if value is true.<br> - * Process is failure, if value is false. - * \warning Please call only once from main thread. - */ - static bool globalFinalize(JNIEnv *env); + /*! + * \brief SR_Handler in HotSpot VM + */ + static TSignalHandler SR_Handler; - protected: - /*! - * \brief Setting signal handle function. - * \param env [in] JNI environment object. - * \param sigName [in] Name of signal. - * \param handler [in] Setting signal handler. - * \return Process is succeed, if value is true.<br> - * Process is failure, if value is false. - */ - virtual bool setSignalHandler(JNIEnv *env, char *sigName, jobject handler); - - /*! - * \brief Convert string from C++ native to java. - * \param env [in] JNI environment object. - * \param nativeStr [in] String in C++. - * \param javaStr [in,out] String object in java. - * \return Process is succeed, if value is true.<br> - * Process is failure, if value is false. - */ - bool createJString(JNIEnv *env, char *nativeStr, jstring *javaStr); - - /*! - * \brief Getting default signal handler in JVM. - * \param env [in] JNI environment object. - * \return Process is succeed, if value is true.<br> - * Process is failure, if value is false. - */ - static bool getDefaultSignalHandler(JNIEnv *env); - - RELEASE_ONLY(private :) + public: + /*! + * \brief Find signal number from name. + * \param sig Signal name. + * \return Signal number. Return -1 if not found. + */ + static int findSignal(const char *sig); - /*! - * \brief Object of "NativeSignalHandler" class information. - */ - static jclass classNativeHandler; - /*! - * \brief Object of "Signal" class information. - */ - static jclass classSignal; - /*! - * \brief Object of "String" class information. - */ - static jclass classString; + /*! + * \brief TSignalManager constructor. + * \param sig Signal string. + */ + TSignalManager(const char *sig); - /*! - * \brief Constructor of "NativeSignalHandler" class. - */ - static jmethodID nativeHandler_init; - /*! - * \brief Constructor of "Signal" class. - */ - static jmethodID signal_init; - /*! - * \brief Constructor of "String" class. - */ - static jmethodID string_init; - /*! - * \brief Method "handle" of "Signal" class. - */ - static jmethodID signal_handle; + /*! + * \brief TSignalManager destructor. + */ + virtual ~TSignalManager(void); - /*! - * \brief Default signal handler. - */ - static jobject signal_DFL; - - /*! - * \brief Flag of load initialize data. - */ - static bool loadFlag; - - /*! - * \brief Orignal signal handler. - */ - jobject insSignalHandler; + /*! + * \brief Add signal handler. + * \param handler [in] Function pointer for signal handler. + * \return true if new signal handler is added. + */ + bool addHandler(TSignalHandler handler); }; #endif // _SIGNAL_MNGR_H
--- a/agent/src/heapstats-engines/vmFunctions.cpp Mon Apr 11 21:51:17 2016 +0900 +++ b/agent/src/heapstats-engines/vmFunctions.cpp Mon Apr 18 21:28:04 2016 +0900 @@ -1,7 +1,7 @@ /*! * \file vmFunctions.cpp * \brief This file includes functions in HotSpot VM.<br> - * Copyright (C) 2014-2015 Yasumasa Suenaga + * Copyright (C) 2014-2016 Yasumasa Suenaga * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -147,6 +147,36 @@ return false; } + /* Search "get_thread" function symbol. */ + get_thread = (TGet_thread) this->symFinder->findSymbol(GET_THREAD_SYMBOL); + if (get_thread == NULL) { // for JDK 9 + /* Search "ThreadLocalStorage::thread" function symbol. */ + get_thread = (TGet_thread) this->symFinder->findSymbol( + THREADLOCALSTORAGE_THREAD_SYMBOL); + if (unlikely(get_thread == NULL)) { + logger->printWarnMsg("ThreadLocalStorage::thread() not found."); + return false; + } + } + + /* Search "UserHandler" function symbol. */ + userHandler = (TUserHandler) this->symFinder->findSymbol(USERHANDLER_SYMBOL); + if (unlikely(userHandler == NULL)) { + logger->printWarnMsg("UserHandler() not found."); + return false; + } + + /* Search "SR_handler" function symbol. */ + sr_handler = (TSR_Handler) this->symFinder->findSymbol(SR_HANDLER_SYMBOL); + if (sr_handler == NULL) { // for OpenJDK + sr_handler = (TSR_Handler) this->symFinder->findSymbol( + SR_HANDLER_SYMBOL_FALLBACK); + if (sr_handler == NULL) { + logger->printWarnMsg("SR_handler() not found."); + return false; + } + } + if (vmVal->getUseG1()) { inst->getG1VTableFromSymbol(); }
--- a/agent/src/heapstats-engines/vmFunctions.hpp Mon Apr 11 21:51:17 2016 +0900 +++ b/agent/src/heapstats-engines/vmFunctions.hpp Mon Apr 18 21:28:04 2016 +0900 @@ -1,7 +1,7 @@ /*! * \file vmFunctions.hpp * \brief This file includes functions in HotSpot VM. - * Copyright (C) 2014-2015 Yasumasa Suenaga + * Copyright (C) 2014-2016 Yasumasa Suenaga * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -92,6 +92,28 @@ */ #define UNSAFE_PARK_SYMBOL "Unsafe_Park" +/*! + * \brief Symbol of get_thread() + */ +#define GET_THREAD_SYMBOL "get_thread" + +/*! + * \brief Symbol of ThreadLocalStorage::thread() + */ +#define THREADLOCALSTORAGE_THREAD_SYMBOL "_ZN18ThreadLocalStorage6threadEv" + +/*! + * \brief Symbol of UserHandler() + */ +#define USERHANDLER_SYMBOL "_ZL11UserHandleriPvS_" + +/*! + * \brief Symbol of SR_handler() + */ +#define SR_HANDLER_SYMBOL "_ZL10SR_handleriP7siginfoP8ucontext" +#define SR_HANDLER_SYMBOL_FALLBACK "_ZL10SR_handleriP9siginfo_tP8ucontext" + + /* Function type definition */ /*! @@ -156,6 +178,43 @@ typedef void (*TUnsafe_Park)(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time); +/*! + * \brief JNI function of sun.misc.Unsafe#park() . + * \param env [in] JNI environment. + * \param unsafe [in] Unsafe object. + * \param isAbsolute [in] absolute. + * \param time [in] Park time. + */ +typedef void (*TUnsafe_Park)(JNIEnv *env, jobject unsafe, jboolean isAbsolute, + jlong time); + +/*! + * \brief Get C++ Thread instance. + * \return C++ Thread instance of this thread context. + */ +typedef void *(*TGet_thread)(); + +/*! + * \brief User signal handler for HotSpot. + * \param sig Signal number. + * \param siginfo Signal information. + * \param context Thread context. + */ +typedef void (*TUserHandler)(int sig, void *siginfo, void *context); + +/*! + * \brief Thread suspend/resume signal handler in HotSpot. + * \param sig Signal number. + * \param siginfo Signal information. + * \param context Thread context. + */ +typedef void (*TSR_Handler)(int sig, siginfo_t *siginfo, ucontext_t *context); + + +/* Exported function in libjvm.so */ +extern "C" void *JVM_RegisterSignal(jint sig, void *handler); + + /* extern variables */ extern "C" void *VTableForTypeArrayOopClosure[2]; extern "C" THeap_IsInPermanent is_in_permanent; @@ -195,6 +254,21 @@ */ TUnsafe_Park unsafePark; + /*! + * \brief Function pointer for "get_thread()". + */ + TGet_thread get_thread; + + /*! + * \brief Function pointer for "UserHandler". + */ + TUserHandler userHandler; + + /*! + * \brief Function pointer for "SR_handler". + */ + TSR_Handler sr_handler; + /* Class of HeapStats for scanning variables in HotSpot VM */ TSymbolFinder *symFinder; @@ -260,6 +334,14 @@ } inline void *GetUnsafe_ParkPointer(void) { return (void *)unsafePark; } + + inline void *GetThread(void) { + return get_thread(); + } + + inline void *GetUserHandlerPointer(void) { return (void *)userHandler; } + + inline void *GetSRHandlerPointer(void) { return (void *)sr_handler; } }; #endif // VMFUNCTIONS_H