1 /* 2 * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Oracle nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This source code is provided to illustrate the usage of a given feature 34 * or technique and has been deliberately simplified. Additional steps 35 * required for a production-quality application, such as security checks, 36 * input validation and proper error handling, might not be present in 37 * this sample code. 38 */ 39 40 41 /* Example of using JVMTI_EVENT_GARBAGE_COLLECTION_START and 42 * JVMTI_EVENT_GARBAGE_COLLECTION_FINISH events. 43 */ 44 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 49 #include "jni.h" 50 #include "jvmti.h" 51 52 /* For stdout_message(), fatal_error(), and check_jvmti_error() */ 53 #include "agent_util.h" 54 55 /* Global static data */ 56 static jvmtiEnv *jvmti; 57 static int gc_count; 58 static jrawMonitorID lock; 59 60 /* Worker thread that waits for garbage collections */ 61 static void JNICALL 62 worker(jvmtiEnv* jvmti, JNIEnv* jni, void *p) 63 { 64 jvmtiError err; 65 66 stdout_message("GC worker started...\n"); 67 68 for (;;) { 69 err = (*jvmti)->RawMonitorEnter(jvmti, lock); 70 check_jvmti_error(jvmti, err, "raw monitor enter"); 71 while (gc_count == 0) { 72 err = (*jvmti)->RawMonitorWait(jvmti, lock, 0); 73 if (err != JVMTI_ERROR_NONE) { 74 err = (*jvmti)->RawMonitorExit(jvmti, lock); 75 check_jvmti_error(jvmti, err, "raw monitor wait"); 76 return; 77 } 78 } 79 gc_count = 0; 80 81 err = (*jvmti)->RawMonitorExit(jvmti, lock); 82 check_jvmti_error(jvmti, err, "raw monitor exit"); 83 84 /* Perform arbitrary JVMTI/JNI work here to do post-GC cleanup */ 85 stdout_message("post-GarbageCollectionFinish actions...\n"); 86 } 87 } 88 89 /* Creates a new jthread */ 90 static jthread 91 alloc_thread(JNIEnv *env) 92 { 93 jclass thrClass; 94 jmethodID cid; 95 jthread res; 96 97 thrClass = (*env)->FindClass(env, "java/lang/Thread"); 98 if ( thrClass == NULL ) { 99 fatal_error("Cannot find Thread class\n"); 100 } 101 cid = (*env)->GetMethodID(env, thrClass, "<init>", "()V"); 102 if ( cid == NULL ) { 103 fatal_error("Cannot find Thread constructor method\n"); 104 } 105 res = (*env)->NewObject(env, thrClass, cid); 106 if ( res == NULL ) { 107 fatal_error("Cannot create new Thread object\n"); 108 } 109 return res; 110 } 111 112 /* Callback for JVMTI_EVENT_VM_INIT */ 113 static void JNICALL 114 vm_init(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) 115 { 116 jvmtiError err; 117 118 stdout_message("VMInit...\n"); 119 120 err = (*jvmti)->RunAgentThread(jvmti, alloc_thread(env), &worker, NULL, 121 JVMTI_THREAD_MAX_PRIORITY); 122 check_jvmti_error(jvmti, err, "running agent thread"); 123 } 124 125 /* Callback for JVMTI_EVENT_GARBAGE_COLLECTION_START */ 126 static void JNICALL 127 gc_start(jvmtiEnv* jvmti_env) 128 { 129 stdout_message("GarbageCollectionStart...\n"); 130 } 131 132 /* Callback for JVMTI_EVENT_GARBAGE_COLLECTION_FINISH */ 133 static void JNICALL 134 gc_finish(jvmtiEnv* jvmti_env) 135 { 136 jvmtiError err; 137 138 stdout_message("GarbageCollectionFinish...\n"); 139 140 err = (*jvmti)->RawMonitorEnter(jvmti, lock); 141 check_jvmti_error(jvmti, err, "raw monitor enter"); 142 gc_count++; 143 err = (*jvmti)->RawMonitorNotify(jvmti, lock); 144 check_jvmti_error(jvmti, err, "raw monitor notify"); 145 err = (*jvmti)->RawMonitorExit(jvmti, lock); 146 check_jvmti_error(jvmti, err, "raw monitor exit"); 147 } 148 149 /* Agent_OnLoad() is called first, we prepare for a VM_INIT event here. */ 150 JNIEXPORT jint JNICALL 151 Agent_OnLoad(JavaVM *vm, char *options, void *reserved) 152 { 153 jint rc; 154 jvmtiError err; 155 jvmtiCapabilities capabilities; 156 jvmtiEventCallbacks callbacks; 157 158 /* Get JVMTI environment */ 159 rc = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION); 160 if (rc != JNI_OK) { 161 fatal_error("ERROR: Unable to create jvmtiEnv, rc=%d\n", rc); 162 return -1; 163 } 164 165 /* Get/Add JVMTI capabilities */ 166 (void)memset(&capabilities, 0, sizeof(capabilities)); 167 capabilities.can_generate_garbage_collection_events = 1; 168 err = (*jvmti)->AddCapabilities(jvmti, &capabilities); 169 check_jvmti_error(jvmti, err, "add capabilities"); 170 171 /* Set callbacks and enable event notifications */ 172 memset(&callbacks, 0, sizeof(callbacks)); 173 callbacks.VMInit = &vm_init; 174 callbacks.GarbageCollectionStart = &gc_start; 175 callbacks.GarbageCollectionFinish = &gc_finish; 176 err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks)); 177 check_jvmti_error(jvmti, err, "set event callbacks"); 178 err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 179 JVMTI_EVENT_VM_INIT, NULL); 180 check_jvmti_error(jvmti, err, "set event notification"); 181 err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 182 JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL); 183 check_jvmti_error(jvmti, err, "set event notification"); 184 err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 185 JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL); 186 check_jvmti_error(jvmti, err, "set event notification"); 187 188 /* Create the necessary raw monitor */ 189 err = (*jvmti)->CreateRawMonitor(jvmti, "lock", &lock); 190 check_jvmti_error(jvmti, err, "create raw monitor"); 191 return 0; 192 } 193 194 /* Agent_OnUnload() is called last */ 195 JNIEXPORT void JNICALL 196 Agent_OnUnload(JavaVM *vm) 197 { 198 }