Mercurial > hg > heapstats
view agent/src/heapstats-engines/jniCallbackRegister.hpp @ 245:354b87b559ef
Bug 3424: HeapStats Agent might crash when thread recorder is disabled via realoading configuration
Reviewed-by: ykubota
https://github.com/HeapStats/heapstats/pull/112
author | Yasumasa Suenaga <yasuenag@gmail.com> |
---|---|
date | Sat, 22 Jul 2017 19:04:47 +0900 |
parents | 0610f1482f41 |
children | b3d1289e4539 |
line wrap: on
line source
/*! * \file jniCallbackRegister.hpp * \brief Handling JNI function callback. * Copyright (C) 2015-2017 Yasumasa Suenaga * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef JNI_CALLBACK_REGISTER_HPP #define JNI_CALLBACK_REGISTER_HPP #include <jvmti.h> #include <jni.h> #include <pthread.h> #include <list> /* Type definition for JNI functions. */ typedef void (*TJVM_Sleep)(JNIEnv *env, jclass threadClass, jlong millis); typedef void (*TUnsafe_Park)(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time); /* Import functions from libjvm.so */ extern "C" void JVM_Sleep(JNIEnv *env, jclass threadClass, jlong millis); /*! * \brief Base class of callback for JNI functions. */ template <typename T> class TJNICallbackRegister { protected: /*! * \brief Callback function list before calling JNI function. */ static std::list<T> prologueCallbackList; /*! * \brief Callback function list after calling JNI function. */ static std::list<T> epilogueCallbackList; /*! * \brief Read-Write lock for callback container. */ static pthread_rwlock_t callbackLock; public: /*! * \brief Register callbacks for JNI function. * * \param prologue [in] Callback before calling JNI function. * \param epilogue [in] Callback after calling JNI function. */ static void registerCallback(T prologue, T epilogue) { pthread_rwlock_wrlock(&callbackLock); { if (prologue != NULL) { prologueCallbackList.push_back(prologue); } if (epilogue != NULL) { epilogueCallbackList.push_back(epilogue); } } pthread_rwlock_unlock(&callbackLock); }; /*! * \brief Unegister callbacks for JNI function. * * \param prologue [in] Callback before calling JNI function. * \param epilogue [in] Callback after calling JNI function. */ static void unregisterCallback(T prologue, T epilogue) { pthread_rwlock_wrlock(&callbackLock); { if (prologue != NULL) { for (auto itr = prologueCallbackList.cbegin(); itr != prologueCallbackList.cend(); itr++) { if (prologue == *itr) { prologueCallbackList.erase(itr); break; } } } if (epilogue != NULL) { for (auto itr = epilogueCallbackList.cbegin(); itr != epilogueCallbackList.cend(); itr++) { if (epilogue == *itr) { epilogueCallbackList.erase(itr); break; } } } } pthread_rwlock_unlock(&callbackLock); }; }; /*! * \brief JNI callbacks for prologue. */ template <typename T> std::list<T> TJNICallbackRegister<T>::prologueCallbackList; /*! * \brief JNI callbacks for epilogue. */ template <typename T> std::list<T> TJNICallbackRegister<T>::epilogueCallbackList; /*! * \brief Read-Write lock for callback container. */ template <typename T> pthread_rwlock_t TJNICallbackRegister<T>::callbackLock = PTHREAD_RWLOCK_INITIALIZER; #define ITERATE_JNI_CALLBACK_CHAIN(type, originalFunc, ...) \ std::list<type>::iterator itr; \ \ pthread_rwlock_rdlock(&callbackLock); \ { \ for (itr = prologueCallbackList.begin(); \ itr != prologueCallbackList.end(); itr++) { \ (*itr)(__VA_ARGS__); \ } \ } \ pthread_rwlock_unlock(&callbackLock); \ \ originalFunc(__VA_ARGS__); \ \ pthread_rwlock_rdlock(&callbackLock); \ { \ for (itr = epilogueCallbackList.begin(); \ itr != epilogueCallbackList.end(); itr++) { \ (*itr)(__VA_ARGS__); \ } \ } \ pthread_rwlock_unlock(&callbackLock); /*! * \brief JVM_Sleep callback (java.lang.System#sleep()) */ class TJVMSleepCallback : public TJNICallbackRegister<TJVM_Sleep> { public: static void JNICALL callbackStub(JNIEnv *env, jclass threadClass, jlong millis){ ITERATE_JNI_CALLBACK_CHAIN(TJVM_Sleep, JVM_Sleep, env, threadClass, millis)}; static bool switchCallback(JNIEnv *env, bool isEnable) { jclass threadClass = env->FindClass("java/lang/Thread"); JNINativeMethod sleepMethod; sleepMethod.name = (char *)"sleep"; sleepMethod.signature = (char *)"(J)V"; sleepMethod.fnPtr = isEnable ? (void *)&callbackStub : (void *)&JVM_Sleep; return (env->RegisterNatives(threadClass, &sleepMethod, 1) == 0); } }; /*! * \brief Unsafe_Park callback (sun.misc.Unsafe#park()) */ class TUnsafeParkCallback : public TJNICallbackRegister<TUnsafe_Park> { public: static void JNICALL callbackStub(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time){ ITERATE_JNI_CALLBACK_CHAIN(TUnsafe_Park, TVMFunctions::getInstance()->Unsafe_Park, env, unsafe, isAbsolute, time)}; static bool switchCallback(JNIEnv *env, bool isEnable) { jclass unsafeClass = env->FindClass("sun/misc/Unsafe"); JNINativeMethod parkMethod; parkMethod.name = (char *)"park"; parkMethod.signature = (char *)"(ZJ)V"; parkMethod.fnPtr = isEnable ? (void *)&callbackStub : TVMFunctions::getInstance()->GetUnsafe_ParkPointer(); return (env->RegisterNatives(unsafeClass, &parkMethod, 1) == 0); } }; #endif // JNI_CALLBACK_REGISTER_HPP