1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 #include <stdio.h>
  25 #include <string.h>
  26 #include "jvmti.h"
  27 #include "jni.h"
  28 
  29 #ifdef __cplusplus
  30 extern "C" {
  31 #endif
  32 
  33 #ifndef JNI_ENV_ARG
  34 
  35 #ifdef __cplusplus
  36 #define JNI_ENV_ARG(x, y) y
  37 #define JNI_ENV_PTR(x) x
  38 #else
  39 #define JNI_ENV_ARG(x,y) x, y
  40 #define JNI_ENV_PTR(x) (*x)
  41 #endif
  42 
  43 #endif
  44 
  45 #define TranslateError(err) "JVMTI error"
  46 
  47 #define PASSED 0
  48 #define FAILED 2
  49 
  50 static jint status = PASSED;
  51 
  52 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
  53 
  54 JNIEXPORT void JNICALL
  55 MonitorContendedEnter(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jobject monitor) {
  56     jvmtiThreadInfo threadInfo;
  57     jint monitorCount;
  58     jobject *ownedMonitors;
  59 
  60     (*jvmti)->GetThreadInfo(jvmti, thread, &threadInfo);
  61     (*jvmti)->GetOwnedMonitorInfo(jvmti, thread, &monitorCount, &ownedMonitors);
  62 
  63     printf("MonitorContendedEnter: %s owns %d monitor(s)\n",
  64            threadInfo.name, monitorCount);
  65 
  66     (*jvmti)->Deallocate(jvmti, (unsigned char *)ownedMonitors);
  67     (*jvmti)->Deallocate(jvmti, (unsigned char *)threadInfo.name);
  68 
  69     if (monitorCount != 0) {
  70         status = FAILED;
  71     }
  72 }
  73 
  74 JNIEXPORT void JNICALL
  75 MonitorContendedEntered(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jobject monitor) {
  76     jvmtiThreadInfo threadInfo;
  77     jint monitorCount;
  78     jobject *ownedMonitors;
  79 
  80     (*jvmti)->GetThreadInfo(jvmti, thread, &threadInfo);
  81     (*jvmti)->GetOwnedMonitorInfo(jvmti, thread, &monitorCount, &ownedMonitors);
  82 
  83     printf("MonitorContendedEntered: %s owns %d monitor(s)\n",
  84            threadInfo.name, monitorCount);
  85 
  86     (*jvmti)->Deallocate(jvmti, (unsigned char *)ownedMonitors);
  87     (*jvmti)->Deallocate(jvmti, (unsigned char *)threadInfo.name);
  88 
  89     if (monitorCount != 1) {
  90         status = FAILED;
  91     }
  92 }
  93 
  94 JNIEXPORT jint JNICALL
  95 Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
  96     return Agent_Initialize(jvm, options, reserved);
  97 }
  98 
  99 JNIEXPORT jint JNICALL
 100 Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
 101     return Agent_Initialize(jvm, options, reserved);
 102 }
 103 
 104 JNIEXPORT jint JNICALL
 105 JNI_OnLoad(JavaVM *jvm, void *reserved) {
 106     return JNI_VERSION_1_8;
 107 }
 108 
 109 static
 110 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 111     jint res;
 112     jvmtiError err;
 113     jvmtiEnv *jvmti;
 114     jvmtiCapabilities caps;
 115     jvmtiEventCallbacks callbacks;
 116 
 117     printf("Agent_OnLoad started\n");
 118 
 119     res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
 120                                    JVMTI_VERSION_1);
 121     if (res != JNI_OK || jvmti == NULL) {
 122         printf("    Error: wrong result of a valid call to GetEnv!\n");
 123         return JNI_ERR;
 124     }
 125 
 126     err = (*jvmti)->GetPotentialCapabilities(jvmti, &caps);
 127     if (err != JVMTI_ERROR_NONE) {
 128         printf("Agent_OnLoad: error in JVMTI GetPotentialCapabilities: %d\n",  err);
 129         return JNI_ERR;
 130     }
 131 
 132     err = (*jvmti)->AddCapabilities(jvmti, &caps);
 133     if (err != JVMTI_ERROR_NONE) {
 134         printf("Agent_OnLoad: error in JVMTI AddCapabilities: %d\n", err);
 135     }
 136 
 137     err = (*jvmti)->GetCapabilities(jvmti, &caps);
 138     if (err != JVMTI_ERROR_NONE) {
 139         printf("Agent_OnLoad: error in JVMTI GetCapabilities: %d\n",  err);
 140         return JNI_ERR;
 141     }
 142 
 143     if (!caps.can_generate_monitor_events) {
 144         printf("Warning: Monitor events are not implemented\n");
 145     }
 146     if (!caps.can_get_owned_monitor_info) {
 147         printf("Warning: GetOwnedMonitorInfo is not implemented\n");
 148     }
 149 
 150     callbacks.MonitorContendedEnter   = &MonitorContendedEnter;
 151     callbacks.MonitorContendedEntered = &MonitorContendedEntered;
 152 
 153     err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(jvmtiEventCallbacks));
 154     if (err != JVMTI_ERROR_NONE) {
 155         printf("Agent_OnLoad: error in JVMTI SetEventCallbacks: %d\n", err);
 156     }
 157 
 158     err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
 159                                              JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL);
 160     if (err != JVMTI_ERROR_NONE) {
 161         printf("Agent_OnLoad: error in JVMTI SetEventNotificationMode #1: %d\n", err);
 162     }
 163     err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
 164                                              JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL);
 165     if (err != JVMTI_ERROR_NONE) {
 166         printf("Agent_OnLoad: error in JVMTI SetEventNotificationMode #2: %d\n", err);
 167     }
 168     printf("Agent_OnLoad finished\n");
 169     return JNI_OK;
 170 }
 171 
 172 JNIEXPORT jint JNICALL
 173 Java_GetOwnedMonitorInfoTest_check(JNIEnv *env, jclass cls) {
 174     return status;
 175 }
 176 
 177 #ifdef __cplusplus
 178 }
 179 #endif