1 /*
   2  * Copyright (c) 2003, 2018, 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 
  25  Unit test to test the following:
  26 
  27  Onload phase:
  28 
  29  1.  CreateRawMonitor
  30  2.  RawMonitorEnter
  31  3.  RawMonitorExit
  32  4.  DestroyRawMonitor
  33  5.  Recursive RawMonitorEnter and DestroyRawMonitor
  34  6.  RawMonitorExit for not owned monitor in onload phase.
  35  7.  RawMonitorExit for not owned monitor in live phase.
  36 
  37  Mixed phase:
  38 
  39  1. Onload RawMonitorEnter and live phase RawMonitorExit
  40  2. Onload RawMonitorEnter and start phase RawMonitorExit
  41  3. Start phase RawMonitorEnter and RawMonitorExit.
  42  4. Onload RawmonitorEnter and start phase Destroy
  43 
  44  */
  45 
  46 #include <stdio.h>
  47 #include <string.h>
  48 #include "jvmti.h"
  49 #include "agent_common.h"
  50 
  51 extern "C" {
  52 
  53 
  54 #define JVMTI_ERROR_CHECK(str,res) if ( res != JVMTI_ERROR_NONE) { printf(str); printf(" %d\n",res); return res;}
  55 #define JVMTI_ERROR_CHECK_EXPECTED_ERROR(str,res,err) if ( res != err) { printf(str); printf(" unexpected error %d\n",res); return res;}
  56 
  57 #define JVMTI_ERROR_CHECK_VOID(str,res) if ( res != JVMTI_ERROR_NONE) { printf(str); printf(" %d\n",res); iGlobalStatus = 2; }
  58 
  59 #define JVMTI_ERROR_CHECK_EXPECTED_ERROR_VOID(str,res,err) if ( res != err) { printf(str); printf(" unexpected error %d\n",res); iGlobalStatus = 2; }
  60 
  61 #define THREADS_LIMIT 8
  62 
  63 jrawMonitorID access_lock;
  64 jrawMonitorID access_lock_not_entered;
  65 jvmtiEnv *jvmti;
  66 jint iGlobalStatus = 0;
  67 jthread main_thread;
  68 static jvmtiEventCallbacks callbacks;
  69 static jvmtiCapabilities jvmti_caps;
  70 jrawMonitorID jraw_monitor[20];
  71 
  72 static volatile int process_once = 1;
  73 
  74 
  75 
  76 int printdump = 0;
  77 
  78 
  79 void debug_printf(const char *fmt, ...) {
  80     va_list args;
  81 
  82     va_start(args, fmt);
  83     if (printdump) {
  84         vprintf(fmt, args);
  85     }
  86     va_end(args);
  87 }
  88 
  89 
  90 void JNICALL vmStart(jvmtiEnv *jvmti_env, JNIEnv *env) {
  91     jvmtiError res;
  92     res = jvmti->GetCurrentThread(&main_thread);
  93     JVMTI_ERROR_CHECK_VOID(" JVMTI GetCurrentThread returned error", res);
  94     main_thread = (jthread)env->NewGlobalRef(main_thread);
  95 }
  96 
  97 void JNICALL vmInit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) {
  98 
  99     jvmtiError res;
 100 
 101     debug_printf("VMInit event  done\n");
 102     res = jvmti->RawMonitorExit(access_lock);
 103     JVMTI_ERROR_CHECK_VOID(" Raw monitor exit returned error", res);
 104     res = jvmti->RawMonitorExit(access_lock);
 105     JVMTI_ERROR_CHECK_VOID(" Raw monitor exit returned error", res);
 106 }
 107 
 108 void JNICALL vmExit(jvmtiEnv *jvmti_env, JNIEnv *env) {
 109     debug_printf("------------ JVMTI_EVENT_VM_DEATH ------------\n");
 110 }
 111 
 112 void JNICALL classFileLoadHookEvent(jvmtiEnv *jvmti_env, JNIEnv *env,
 113                         jclass class_being_redifined,
 114                         jobject loader, const char* name,
 115                         jobject protection_domain,
 116                         jint class_data_len,
 117                         const unsigned char* class_data,
 118                         jint* new_class_data_len,
 119                         unsigned char** new_class_data) {
 120 
 121     jvmtiError res;
 122     jvmtiPhase phase;
 123     jthread    thread;
 124 
 125     res = jvmti->GetPhase(&phase);
 126     JVMTI_ERROR_CHECK_VOID(" JVMTI GetPhase returned error", res);
 127     if (phase != JVMTI_PHASE_START) {
 128         return; /* only the start phase is tested */
 129     }
 130     res = jvmti->GetCurrentThread(&thread);
 131     JVMTI_ERROR_CHECK_VOID(" JVMTI GetCurrentThread returned error", res);
 132     if (!env->IsSameObject(thread, main_thread)) {
 133         return; /* only the main thread is tested */
 134     }
 135 
 136     debug_printf("------------ classFileLoadHookEvent ------------\n");
 137 
 138     /* Test raw monitor in start phase */
 139 
 140     if (process_once) {
 141 
 142         process_once = 0;
 143 
 144             /* test not entered raw monitor */
 145         res = jvmti->RawMonitorExit(access_lock_not_entered);
 146         JVMTI_ERROR_CHECK_EXPECTED_ERROR_VOID("Raw monitor exit returned error", res,JVMTI_ERROR_NOT_MONITOR_OWNER);
 147 
 148             /* release lock in start phase */
 149         res = jvmti->RawMonitorExit(access_lock);
 150         JVMTI_ERROR_CHECK_VOID("Raw monitor exit returned error", res);
 151 
 152             /* release lock in start phase */
 153         res = jvmti->RawMonitorExit(access_lock);
 154         JVMTI_ERROR_CHECK_VOID("Raw monitor exit returned error", res);
 155 
 156         res = jvmti->RawMonitorEnter(access_lock);
 157         JVMTI_ERROR_CHECK_VOID("Raw monitor enter returned error", res);
 158 
 159         res = jvmti->RawMonitorEnter(access_lock);
 160         JVMTI_ERROR_CHECK_VOID("Raw monitor enter returned error", res);
 161     }
 162 
 163 }
 164 
 165 
 166 
 167 void init_callbacks() {
 168     memset((void *)&callbacks, 0, sizeof(jvmtiEventCallbacks));
 169     callbacks.VMStart = vmStart;
 170     callbacks.VMInit = vmInit;
 171     callbacks.VMDeath = vmExit;
 172     callbacks.ClassFileLoadHook = classFileLoadHookEvent;
 173 }
 174 
 175 
 176 #ifdef STATIC_BUILD
 177 JNIEXPORT jint JNICALL Agent_OnLoad_rawmonitor(JavaVM *jvm, char *options, void *reserved) {
 178     return Agent_Initialize(jvm, options, reserved);
 179 }
 180 JNIEXPORT jint JNICALL Agent_OnAttach_rawmonitor(JavaVM *jvm, char *options, void *reserved) {
 181     return Agent_Initialize(jvm, options, reserved);
 182 }
 183 JNIEXPORT jint JNI_OnLoad_rawmonitor(JavaVM *jvm, char *options, void *reserved) {
 184     return JNI_VERSION_1_8;
 185 }
 186 #endif
 187 jint Agent_Initialize(JavaVM * jvm, char *options, void *reserved) {
 188     jint res;
 189 
 190     if (options && strlen(options) > 0) {
 191         if (strstr(options, "printdump")) {
 192             printdump = 1;
 193         }
 194     }
 195 
 196     res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
 197     if (res < 0) {
 198         debug_printf("Wrong result of a valid call to GetEnv!\n");
 199         return JNI_ERR;
 200     }
 201 
 202     /* Onload phase Create data access lock */
 203     res = jvmti->CreateRawMonitor("_access_lock", &access_lock);
 204     JVMTI_ERROR_CHECK("CreateRawMonitor failed with error code ", res);
 205     res = jvmti->CreateRawMonitor("_access_lock_not_entered", &access_lock_not_entered);
 206     JVMTI_ERROR_CHECK("CreateRawMonitor failed with error code ", res);
 207     /* Create this raw monitor in onload and it is used in live phase */
 208     res = jvmti->CreateRawMonitor("RawMonitor-0", &jraw_monitor[0]);
 209     JVMTI_ERROR_CHECK("CreateRawMonitor failed with error code ", res);
 210 
 211 
 212     /* Add capabilities */
 213     res = jvmti->GetPotentialCapabilities(&jvmti_caps);
 214     JVMTI_ERROR_CHECK("GetPotentialCapabilities returned error", res);
 215 
 216     res = jvmti->AddCapabilities(&jvmti_caps);
 217     JVMTI_ERROR_CHECK("GetPotentialCapabilities returned error", res);
 218 
 219     /* Enable events */
 220     init_callbacks();
 221     res = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
 222     JVMTI_ERROR_CHECK("SetEventCallbacks returned error", res);
 223 
 224     res = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
 225     JVMTI_ERROR_CHECK("SetEventNotificationMode for VM_INIT returned error", res);
 226 
 227     res = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL);
 228     JVMTI_ERROR_CHECK("SetEventNotificationMode for vm death event returned error", res);
 229 
 230     res = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
 231     JVMTI_ERROR_CHECK("SetEventNotificationMode CLASS_FILE_LOAD_HOOK returned error", res);
 232 
 233      /* acquire lock in onload */
 234     res = jvmti->RawMonitorEnter(access_lock);
 235     JVMTI_ERROR_CHECK("Raw monitor enter returned error", res);
 236 
 237     /* release lock in onload */
 238     res = jvmti->RawMonitorExit(access_lock);
 239     JVMTI_ERROR_CHECK("Raw monitor exit returned error", res);
 240 
 241     /* test not entered raw monitor */
 242     res = jvmti->RawMonitorExit(access_lock_not_entered);
 243     JVMTI_ERROR_CHECK_EXPECTED_ERROR("Raw monitor exit returned error", res,JVMTI_ERROR_NOT_MONITOR_OWNER);
 244 
 245     /* acquire lock in onload */
 246     res = jvmti->RawMonitorEnter(access_lock);
 247     JVMTI_ERROR_CHECK("Raw monitor enter returned error", res);
 248 
 249     res = jvmti->RawMonitorEnter(access_lock);
 250     JVMTI_ERROR_CHECK("Raw monitor enter returned error", res);
 251 
 252     res = jvmti->RawMonitorEnter(access_lock);
 253     JVMTI_ERROR_CHECK("Raw monitor enter returned error", res);
 254 
 255     /* test Destroy raw monitor in onload phase */
 256     res = jvmti->DestroyRawMonitor(access_lock);
 257     JVMTI_ERROR_CHECK("Destroy Raw monitor returned error", res);
 258 
 259     /* Create data access lock  in onload and enter in onload phase */
 260     res = jvmti->CreateRawMonitor("_access_lock", &access_lock);
 261     JVMTI_ERROR_CHECK("CreateRawMonitor failed with error code ", res);
 262 
 263     res = jvmti->RawMonitorEnter(access_lock);
 264     JVMTI_ERROR_CHECK("Raw monitor enter returned error", res);
 265 
 266     res = jvmti->RawMonitorEnter(access_lock);
 267     JVMTI_ERROR_CHECK("Raw monitor enter returned error", res);
 268 
 269 
 270     /* This monitor is entered here and it is released in live phase by a call from java code
 271      */
 272     res = jvmti->RawMonitorEnter(jraw_monitor[0]);
 273     JVMTI_ERROR_CHECK("Raw monitor enter returned error", res);
 274     res = jvmti->RawMonitorEnter(jraw_monitor[0]);
 275     JVMTI_ERROR_CHECK("Raw monitor enter returned error", res);
 276     res = jvmti->RawMonitorExit(jraw_monitor[0]);
 277     JVMTI_ERROR_CHECK("Raw monitor exit returned error", res);
 278 
 279     return JNI_OK;
 280 }
 281 
 282 
 283 JNIEXPORT jint JNICALL
 284 Java_nsk_jvmti_unit_functions_rawmonitor_GetResult(JNIEnv * env, jclass cls) {
 285     return iGlobalStatus;
 286 }
 287 
 288 
 289 JNIEXPORT void JNICALL
 290 Java_nsk_jvmti_unit_functions_rawmonitor_CreateRawMonitor(JNIEnv * env, jclass klass, jint i) {
 291     jvmtiError ret;
 292     char sz[128];
 293 
 294     sprintf(sz, "Rawmonitor-%d",i);
 295     debug_printf("jvmti create raw monitor \n");
 296     ret = jvmti->CreateRawMonitor(sz, &jraw_monitor[i]);
 297 
 298     if (ret != JVMTI_ERROR_NONE) {
 299         printf("Error: CreateRawMonitor %d \n", ret);
 300         iGlobalStatus = 2;
 301     }
 302 }
 303 
 304 JNIEXPORT void JNICALL
 305 Java_nsk_jvmti_unit_functions_rawmonitor_RawMonitorEnter(JNIEnv * env, jclass cls, jint i) {
 306     jvmtiError ret;
 307 
 308     debug_printf("jvmti Raw monitor enter \n");
 309     ret = jvmti->RawMonitorEnter(jraw_monitor[i]);
 310 
 311     if (ret != JVMTI_ERROR_NONE) {
 312         printf("Error: RawMonitorEnter %d \n", ret);
 313         iGlobalStatus = 2;
 314     }
 315 }
 316 
 317 JNIEXPORT void JNICALL
 318 Java_nsk_jvmti_unit_functions_rawmonitor_RawMonitorExit(JNIEnv * env, jclass cls, jint i) {
 319     jvmtiError ret;
 320 
 321     debug_printf("jvmti raw monitor exit \n");
 322     ret = jvmti->RawMonitorExit(jraw_monitor[i]);
 323 
 324     if (ret != JVMTI_ERROR_NONE) {
 325         printf("Error: RawMonitorExit %d \n", ret);
 326         iGlobalStatus = 2;
 327     }
 328 }
 329 
 330 JNIEXPORT void JNICALL
 331 Java_nsk_jvmti_unit_functions_rawmonitor_RawMonitorWait(JNIEnv * env, jclass cls, jint i) {
 332     jvmtiError ret;
 333 
 334     debug_printf("jvmti RawMonitorWait \n");
 335     ret = jvmti->RawMonitorWait(jraw_monitor[i], -1);
 336 
 337     if (ret != JVMTI_ERROR_NONE) {
 338         printf("Error: RawMonitorWait %d \n", ret);
 339         iGlobalStatus = 2;
 340     }
 341 }
 342 
 343 }