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