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 PASSED 0
  46 #define FAILED 2
  47 
  48 #define TEST_CLASS "GetOwnedMonitorInfoTest"
  49 
  50 static volatile jboolean event_has_posted = JNI_FALSE;
  51 static volatile jint status = PASSED;
  52 
  53 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
  54 
  55 static void ShowErrorMessage(jvmtiEnv *jvmti, jvmtiError errCode, const char *message) {
  56     char *errMsg;
  57     jvmtiError result;
  58 
  59     result = (*jvmti)->GetErrorName(jvmti, errCode, &errMsg);
  60     if (result == JVMTI_ERROR_NONE) {
  61         fprintf(stderr, "%s: %s (%d)\n", message, errMsg, errCode);
  62         (*jvmti)->Deallocate(jvmti, (unsigned char *)errMsg);
  63     } else {
  64         fprintf(stderr, "%s (%d)\n", message, errCode);
  65     }
  66 }
  67 
  68 static jboolean CheckLockObject(JNIEnv *env, jobject monitor) {
  69     jclass testClass;
  70 
  71     testClass = (*env)->FindClass(env, TEST_CLASS);
  72     if (testClass == NULL) {
  73         fprintf(stderr, "MonitorContendedEnter: " TEST_CLASS " not found\n");
  74         status = FAILED;
  75         event_has_posted = JNI_TRUE;
  76         return JNI_FALSE;
  77     }
  78 
  79     return (*env)->IsInstanceOf(env, monitor, testClass);
  80 }
  81 
  82 JNIEXPORT void JNICALL
  83 MonitorContendedEnter(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jobject monitor) {
  84     jvmtiError err;
  85     jvmtiThreadInfo threadInfo;
  86     jint monitorCount;
  87     jobject *ownedMonitors;
  88 
  89     if (CheckLockObject(env, monitor) == JNI_FALSE) {
  90         return;
  91     }
  92 
  93     err = (*jvmti)->GetThreadInfo(jvmti, thread, &threadInfo);
  94     if (err != JVMTI_ERROR_NONE) {
  95         ShowErrorMessage(jvmti, err,
  96                          "MonitorContendedEnter: error in JVMTI GetThreadInfo");
  97         status = FAILED;
  98         event_has_posted = JNI_TRUE;
  99         return;
 100     }
 101     err = (*jvmti)->GetOwnedMonitorInfo(jvmti, thread, &monitorCount, &ownedMonitors);
 102     if (err != JVMTI_ERROR_NONE) {
 103         ShowErrorMessage(jvmti, err,
 104                          "MonitorContendedEnter: error in JVMTI GetOwnedMonitorInfo");
 105         status = FAILED;
 106         event_has_posted = JNI_TRUE;
 107         return;
 108     }
 109 
 110     printf("MonitorContendedEnter: %s owns %d monitor(s)\n",
 111            threadInfo.name, monitorCount);
 112 
 113     (*jvmti)->Deallocate(jvmti, (unsigned char *)ownedMonitors);
 114     (*jvmti)->Deallocate(jvmti, (unsigned char *)threadInfo.name);
 115 
 116     if (monitorCount != 0) {
 117         fprintf(stderr, "MonitorContendedEnter: FAIL: monitorCount should be zero.\n");
 118         status = FAILED;
 119     }
 120 
 121     event_has_posted = JNI_TRUE;
 122 }
 123 
 124 JNIEXPORT void JNICALL
 125 MonitorContendedEntered(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jobject monitor) {
 126     jvmtiError err;
 127     jvmtiThreadInfo threadInfo;
 128     jint monitorCount;
 129     jobject *ownedMonitors;
 130 
 131     if (CheckLockObject(env, monitor) == JNI_FALSE) {
 132         return;
 133     }
 134 
 135     err = (*jvmti)->GetThreadInfo(jvmti, thread, &threadInfo);
 136     if (err != JVMTI_ERROR_NONE) {
 137         ShowErrorMessage(jvmti, err,
 138                          "MonitorContendedEntered: error in JVMTI GetThreadInfo");
 139         status = FAILED;
 140         return;
 141     }
 142     err = (*jvmti)->GetOwnedMonitorInfo(jvmti, thread, &monitorCount, &ownedMonitors);
 143     if (err != JVMTI_ERROR_NONE) {
 144         ShowErrorMessage(jvmti, err,
 145                          "MonitorContendedEntered: error in JVMTI GetOwnedMonitorInfo");
 146         status = FAILED;
 147         return;
 148     }
 149 
 150     printf("MonitorContendedEntered: %s owns %d monitor(s)\n",
 151            threadInfo.name, monitorCount);
 152 
 153     (*jvmti)->Deallocate(jvmti, (unsigned char *)ownedMonitors);
 154     (*jvmti)->Deallocate(jvmti, (unsigned char *)threadInfo.name);
 155 
 156     if (monitorCount != 1) {
 157         fprintf(stderr, "MonitorContendedEnter: FAIL: monitorCount should be one.\n");
 158         status = FAILED;
 159     }
 160 }
 161 
 162 JNIEXPORT jint JNICALL
 163 Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
 164     return Agent_Initialize(jvm, options, reserved);
 165 }
 166 
 167 JNIEXPORT jint JNICALL
 168 Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
 169     return Agent_Initialize(jvm, options, reserved);
 170 }
 171 
 172 JNIEXPORT jint JNICALL
 173 JNI_OnLoad(JavaVM *jvm, void *reserved) {
 174     return JNI_VERSION_1_8;
 175 }
 176 
 177 static
 178 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 179     jint res;
 180     jvmtiError err;
 181     jvmtiEnv *jvmti;
 182     jvmtiCapabilities caps;
 183     jvmtiEventCallbacks callbacks;
 184 
 185     printf("Agent_OnLoad started\n");
 186 
 187     res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
 188                                    JVMTI_VERSION_1);
 189     if (res != JNI_OK || jvmti == NULL) {
 190         fprintf(stderr, "Error: wrong result of a valid call to GetEnv!\n");
 191         return JNI_ERR;
 192     }
 193 
 194     err = (*jvmti)->GetPotentialCapabilities(jvmti, &caps);
 195     if (err != JVMTI_ERROR_NONE) {
 196         ShowErrorMessage(jvmti, err,
 197                          "Agent_OnLoad: error in JVMTI GetPotentialCapabilities");
 198         return JNI_ERR;
 199     }
 200 
 201     err = (*jvmti)->AddCapabilities(jvmti, &caps);
 202     if (err != JVMTI_ERROR_NONE) {
 203         ShowErrorMessage(jvmti, err,
 204                          "Agent_OnLoad: error in JVMTI AddCapabilities");
 205         return JNI_ERR;
 206     }
 207 
 208     err = (*jvmti)->GetCapabilities(jvmti, &caps);
 209     if (err != JVMTI_ERROR_NONE) {
 210         ShowErrorMessage(jvmti, err,
 211                          "Agent_OnLoad: error in JVMTI GetCapabilities");
 212         return JNI_ERR;
 213     }
 214 
 215     if (!caps.can_generate_monitor_events) {
 216         fprintf(stderr, "Warning: Monitor events are not implemented\n");
 217         return JNI_ERR;
 218     }
 219     if (!caps.can_get_owned_monitor_info) {
 220         fprintf(stderr, "Warning: GetOwnedMonitorInfo is not implemented\n");
 221         return JNI_ERR;
 222     }
 223 
 224     callbacks.MonitorContendedEnter   = &MonitorContendedEnter;
 225     callbacks.MonitorContendedEntered = &MonitorContendedEntered;
 226 
 227     err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(jvmtiEventCallbacks));
 228     if (err != JVMTI_ERROR_NONE) {
 229         ShowErrorMessage(jvmti, err,
 230                          "Agent_OnLoad: error in JVMTI SetEventCallbacks");
 231         return JNI_ERR;
 232     }
 233 
 234     err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
 235                                              JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL);
 236     if (err != JVMTI_ERROR_NONE) {
 237         ShowErrorMessage(jvmti, err,
 238                          "Agent_OnLoad: error in JVMTI SetEventNotificationMode #1");
 239         return JNI_ERR;
 240     }
 241     err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
 242                                              JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL);
 243     if (err != JVMTI_ERROR_NONE) {
 244         ShowErrorMessage(jvmti, err,
 245                          "Agent_OnLoad: error in JVMTI SetEventNotificationMode #2");
 246         return JNI_ERR;
 247     }
 248     printf("Agent_OnLoad finished\n");
 249     return JNI_OK;
 250 }
 251 
 252 JNIEXPORT jint JNICALL
 253 Java_GetOwnedMonitorInfoTest_check(JNIEnv *env, jclass cls) {
 254     return status;
 255 }
 256 
 257 JNIEXPORT jboolean JNICALL
 258 Java_GetOwnedMonitorInfoTest_hasEventPosted(JNIEnv *env, jclass cls) {
 259     return event_has_posted;
 260 }
 261 
 262 #ifdef __cplusplus
 263 }
 264 #endif