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