Mercurial > hg > heapstats
view agent/src/heapstats-engines/callbackRegister.hpp @ 246:b3d1289e4539
Bug 3429: [REGRESSION] Cannot build HeapStats Agent on RHEL
Reviewed-by: ykubota
https://github.com/HeapStats/heapstats/pull/114
author | Yasumasa Suenaga <yasuenag@gmail.com> |
---|---|
date | Mon, 24 Jul 2017 21:16:53 +0900 |
parents | 354b87b559ef |
children |
line wrap: on
line source
/*! * \file callbackRegister.hpp * \brief Handling JVMTI callback functions. * 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 CALLBACK_REGISTER_HPP #define CALLBACK_REGISTER_HPP #include <jvmti.h> #include <jni.h> #include <pthread.h> #include <list> /*! * \brief Base class of JVMTI event callback. */ template <typename T, jvmtiEvent event> class TJVMTIEventCallback { protected: /*! * \brief JVMTI callback function list. */ static std::list<T> callbackList; /*! * \brief Read-Write lock for callback container. */ static pthread_rwlock_t callbackLock; public: /*! * \brief Register JVMTI callback function. * * \param callback [in] Callback function. */ static void registerCallback(T callback) { pthread_rwlock_wrlock(&callbackLock); { callbackList.push_back(callback); } pthread_rwlock_unlock(&callbackLock); }; /*! * \brief Unregister JVMTI callback function. * \param callback [in] Callback function to unregister. */ static void unregisterCallback(T callback) { pthread_rwlock_wrlock(&callbackLock); { #ifdef USE_N2350 // C++11 support auto list_begin = callbackList.cbegin(); auto list_end = callbackList.cend(); #else auto list_begin = callbackList.begin(); auto list_end = callbackList.end(); #endif for (auto itr = list_begin; itr != list_end; itr++) { if (*itr == callback) { callbackList.erase(itr); break; } } } pthread_rwlock_unlock(&callbackLock); }; /*! * \brief Merge JVMTI capabilities for this JVMTI event. * * \param capabilities [out] Capabilities to merge. */ static void mergeCapabilities(jvmtiCapabilities *capabilities){ // Nothing to do in default. }; /*! * \brief Merge JVMTI callback for this JVMTI event. * * \param callbacks [out] Callbacks to merge. */ static void mergeCallback(jvmtiEventCallbacks *callbacks){ // Nothing to do in deafault. }; /*! * \brief Switch JVMTI event notification. * * \param jvmti [in] JVMTI environment. * \param mode [in] Switch of this JVMTI event. */ static bool switchEventNotification(jvmtiEnv *jvmti, jvmtiEventMode mode) { return isError(jvmti, jvmti->SetEventNotificationMode(mode, event, NULL)); } }; /*! * \brief JVMTI callback list definition. */ template <typename T, jvmtiEvent event> std::list<T> TJVMTIEventCallback<T, event>::callbackList; /*! * \brief Read-Write lock for callback container. */ template <typename T, jvmtiEvent event> pthread_rwlock_t TJVMTIEventCallback<T, event>::callbackLock = PTHREAD_RWLOCK_INITIALIZER; #define ITERATE_CALLBACK_CHAIN(type, ...) \ pthread_rwlock_rdlock(&callbackLock); \ { \ for (std::list<type>::iterator itr = callbackList.begin(); \ itr != callbackList.end(); itr++) { \ (*itr)(__VA_ARGS__); \ } \ } \ pthread_rwlock_unlock(&callbackLock); #define DEFINE_MERGE_CALLBACK(callbackName) \ static void mergeCallback(jvmtiEventCallbacks *callbacks) { \ pthread_rwlock_rdlock(&callbackLock); \ { \ if (callbackList.size() == 0) { \ callbacks->callbackName = NULL; \ } else if (callbackList.size() == 1) { \ callbacks->callbackName = *callbackList.begin(); \ } else { \ callbacks->callbackName = &callbackStub; \ } \ } \ pthread_rwlock_unlock(&callbackLock); \ }; /*! * \brief JVMTI ClassPrepare callback. */ class TClassPrepareCallback : public TJVMTIEventCallback<jvmtiEventClassPrepare, JVMTI_EVENT_CLASS_PREPARE> { public: static void JNICALL callbackStub(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass){ ITERATE_CALLBACK_CHAIN(jvmtiEventClassPrepare, jvmti, env, thread, klass)}; DEFINE_MERGE_CALLBACK(ClassPrepare) }; /*! * \brief JVMTI DumpRequest callback. */ class TDataDumpRequestCallback : public TJVMTIEventCallback<jvmtiEventDataDumpRequest, JVMTI_EVENT_DATA_DUMP_REQUEST> { public: static void JNICALL callbackStub(jvmtiEnv *jvmti){ ITERATE_CALLBACK_CHAIN(jvmtiEventDataDumpRequest, jvmti)}; DEFINE_MERGE_CALLBACK(DataDumpRequest) }; /*! * \brief JVMTI GarbageCollectionStart callback. */ class TGarbageCollectionStartCallback : public TJVMTIEventCallback<jvmtiEventGarbageCollectionStart, JVMTI_EVENT_GARBAGE_COLLECTION_START> { public: static void JNICALL callbackStub(jvmtiEnv *jvmti){ ITERATE_CALLBACK_CHAIN(jvmtiEventGarbageCollectionStart, jvmti)}; DEFINE_MERGE_CALLBACK(GarbageCollectionStart) static void mergeCapabilities(jvmtiCapabilities *capabilities) { capabilities->can_generate_garbage_collection_events = 1; }; }; /*! * \brief JVMTI GarbageCollectionFinish callback. */ class TGarbageCollectionFinishCallback : public TJVMTIEventCallback<jvmtiEventGarbageCollectionFinish, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH> { public: static void JNICALL callbackStub(jvmtiEnv *jvmti){ ITERATE_CALLBACK_CHAIN(jvmtiEventGarbageCollectionFinish, jvmti)}; DEFINE_MERGE_CALLBACK(GarbageCollectionFinish) static void mergeCapabilities(jvmtiCapabilities *capabilities) { capabilities->can_generate_garbage_collection_events = 1; }; }; /*! * \brief JVMTI ResourceExhausted callback. */ class TResourceExhaustedCallback : public TJVMTIEventCallback<jvmtiEventResourceExhausted, JVMTI_EVENT_RESOURCE_EXHAUSTED> { public: static void JNICALL callbackStub(jvmtiEnv *jvmti, JNIEnv *env, jint flags, const void *reserved, const char *description) { ITERATE_CALLBACK_CHAIN(jvmtiEventResourceExhausted, jvmti, env, flags, reserved, description); }; DEFINE_MERGE_CALLBACK(ResourceExhausted) static void mergeCapabilities(jvmtiCapabilities *capabilities) { capabilities->can_generate_resource_exhaustion_heap_events = 1; capabilities->can_generate_resource_exhaustion_threads_events = 1; }; }; /*! * \brief JVMTI MonitorContendedEnter callback. */ class TMonitorContendedEnterCallback : public TJVMTIEventCallback<jvmtiEventMonitorContendedEnter, JVMTI_EVENT_MONITOR_CONTENDED_ENTER> { public: static void JNICALL callbackStub(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jobject object) { ITERATE_CALLBACK_CHAIN(jvmtiEventMonitorContendedEnter, jvmti, env, thread, object); }; DEFINE_MERGE_CALLBACK(MonitorContendedEnter) static void mergeCapabilities(jvmtiCapabilities *capabilities) { capabilities->can_generate_monitor_events = 1; }; }; /*! * \brief JVMTI MonitorContendedEntered callback. */ class TMonitorContendedEnteredCallback : public TJVMTIEventCallback<jvmtiEventMonitorContendedEntered, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED> { public: static void JNICALL callbackStub(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jobject object) { ITERATE_CALLBACK_CHAIN(jvmtiEventMonitorContendedEntered, jvmti, env, thread, object); }; DEFINE_MERGE_CALLBACK(MonitorContendedEntered) static void mergeCapabilities(jvmtiCapabilities *capabilities) { capabilities->can_generate_monitor_events = 1; }; }; /*! * \brief JVMTI VMInit callback. */ class TVMInitCallback : public TJVMTIEventCallback<jvmtiEventVMInit, JVMTI_EVENT_VM_INIT> { public: static void JNICALL callbackStub(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) { ITERATE_CALLBACK_CHAIN(jvmtiEventVMInit, jvmti, env, thread); }; DEFINE_MERGE_CALLBACK(VMInit) }; /*! * \brief JVMTI VMDeath callback. */ class TVMDeathCallback : public TJVMTIEventCallback<jvmtiEventVMDeath, JVMTI_EVENT_VM_DEATH> { public: static void JNICALL callbackStub(jvmtiEnv *jvmti, JNIEnv *env) { ITERATE_CALLBACK_CHAIN(jvmtiEventVMDeath, jvmti, env); }; DEFINE_MERGE_CALLBACK(VMDeath) }; /*! * \brief JVMTI ThreadStart callback. */ class TThreadStartCallback : public TJVMTIEventCallback<jvmtiEventThreadStart, JVMTI_EVENT_THREAD_START> { public: static void JNICALL callbackStub(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) { ITERATE_CALLBACK_CHAIN(jvmtiEventThreadStart, jvmti, env, thread); }; DEFINE_MERGE_CALLBACK(ThreadStart) }; /*! * \brief JVMTI ThreadEnd callback. */ class TThreadEndCallback : public TJVMTIEventCallback<jvmtiEventThreadEnd, JVMTI_EVENT_THREAD_END> { public: static void JNICALL callbackStub(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) { ITERATE_CALLBACK_CHAIN(jvmtiEventThreadEnd, jvmti, env, thread); }; DEFINE_MERGE_CALLBACK(ThreadEnd) }; /*! * \brief JVMTI MonitorWait callback. */ class TMonitorWaitCallback : public TJVMTIEventCallback<jvmtiEventMonitorWait, JVMTI_EVENT_MONITOR_WAIT> { public: static void JNICALL callbackStub(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jobject object, jlong timeout) { ITERATE_CALLBACK_CHAIN(jvmtiEventMonitorWait, jvmti, env, thread, object, timeout); }; DEFINE_MERGE_CALLBACK(MonitorWait) static void mergeCapabilities(jvmtiCapabilities *capabilities) { capabilities->can_generate_monitor_events = 1; }; }; /*! * \brief JVMTI MonitorWaited callback. */ class TMonitorWaitedCallback : public TJVMTIEventCallback<jvmtiEventMonitorWaited, JVMTI_EVENT_MONITOR_WAITED> { public: static void JNICALL callbackStub(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jobject object, jboolean timeout) { ITERATE_CALLBACK_CHAIN(jvmtiEventMonitorWaited, jvmti, env, thread, object, timeout); }; DEFINE_MERGE_CALLBACK(MonitorWaited) static void mergeCapabilities(jvmtiCapabilities *capabilities) { capabilities->can_generate_monitor_events = 1; }; }; /*! * \brief Register JVMTI callbacks to JVM. * * \param jvmti [in] JVMTI environment. */ inline bool registerJVMTICallbacks(jvmtiEnv *jvmti) { jvmtiEventCallbacks callbacks = {0}; TClassPrepareCallback::mergeCallback(&callbacks); TDataDumpRequestCallback::mergeCallback(&callbacks); TGarbageCollectionStartCallback::mergeCallback(&callbacks); TGarbageCollectionFinishCallback::mergeCallback(&callbacks); TResourceExhaustedCallback::mergeCallback(&callbacks); TMonitorContendedEnterCallback::mergeCallback(&callbacks); TMonitorContendedEnteredCallback::mergeCallback(&callbacks); TVMInitCallback::mergeCallback(&callbacks); TVMDeathCallback::mergeCallback(&callbacks); TThreadStartCallback::mergeCallback(&callbacks); TThreadEndCallback::mergeCallback(&callbacks); TMonitorWaitCallback::mergeCallback(&callbacks); TMonitorWaitedCallback::mergeCallback(&callbacks); return isError( jvmti, jvmti->SetEventCallbacks(&callbacks, sizeof(jvmtiEventCallbacks))); } #endif // CALLBACK_REGISTER_HPP