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