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 }