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 #include <stdio.h>
  25 #include <string.h>
  26 
  27 #include "nsk_tools.h"
  28 #include "JVMTITools.h"
  29 #include "jvmti_tools.h"
  30 #include "agent_common.h"
  31 #include "jni_tools.h"
  32 
  33 extern "C" {
  34 
  35 #define PASSED 0
  36 #define STATUS_FAILED 2
  37 #define WAIT_TIME 2000
  38 
  39 static jvmtiEnv *jvmti = NULL;
  40 static jvmtiCapabilities caps;
  41 static jvmtiEventCallbacks callbacks;
  42 /* volatile variables */
  43 static jrawMonitorID agent_start_lock, thr_start_lock, thr_resume_lock, thr_event_lock;
  44 static volatile jthread agent_thread = NULL;
  45 static volatile jboolean terminate_debug_agent = JNI_FALSE;
  46 static volatile jboolean debug_agent_timed_out = JNI_FALSE;
  47 static volatile jboolean debug_agent_started = JNI_FALSE;
  48 static volatile jthread next_thread = NULL;
  49 static jvmtiThreadInfo inf;
  50 static volatile int eventsCount = 0;
  51 static volatile jint result = PASSED;
  52 
  53 /*
  54     The agent runs special debugger agent (debug_agent) in a separate thread
  55     that operates on behalf of other threads.
  56     Upon receiving ThreadStart event, the debugger agent:
  57     - suspends the new thread
  58     - calls jni_DeleteGlobalRef with a jnienv * for that new thread
  59     - resumes the new thread
  60     Then the thread suspend status is checked in ThreadStart callback.
  61 
  62     The following monitors are used to synchronize debugger thread with other
  63     threads:
  64     1. agent_start_lock
  65        used to notify VMInit callback as well as ThreadStart callback
  66        that agent thread has been started.
  67     2. thr_event_lock
  68        used to guarantee that only one ThreadStart event is proceeded at
  69        the time.
  70     3. thr_start_lock
  71        used to notify agent thread that new thread has been started.
  72     4. thr_resume_lock
  73        used to notify ThreadStart callback that agent thread finished
  74        suspending and resuming the thread.
  75 
  76     So, the threads behaves as following:
  77 
  78 VMInit                  | debug_agent                 |   ThreadStart
  79 -------------------------------------------------------------------------
  80                         |                             |
  81  agent_start_lock.enter |                             | agent_start_lock.enter
  82                         |                             |
  83  ... create debug_agent | ... start                   |  while (!debug_agent)
  84  agent_start_lock.wait  |                             |    agent_start_lock.wait
  85                         | agent_start_lock.enter      |
  86                         | agent_start_lock.notifyAll  |
  87                         | agent_start_lock.exit       |
  88  agent_start_lock.exit  |                             |  agent_start_lock.exit
  89                         |                             |
  90                         |                             |  thr_event_lock.enter
  91                         |                             |
  92                         | thr_start_lock.enter        |  thr_start_lock.enter
  93                         | if (!next_thread)           |  thr_resume_lock.enter
  94                         |     thr_start_lock.wait     |
  95                         |                             |  ... next_thread = ...
  96                         |                             |  thr_start_lock.notify
  97                         |                             |  thr_start_lock.exit
  98                         |                             |
  99                         | ... suspend new thread      |  thr_resume_lock.wait
 100                         | ... resume new thread       |
 101                         |                             |
 102                         | thr_resume_lock.enter       |
 103                         | thr_resume_lock.notify      |
 104                         | thr_resume_lock.exit        |
 105                         |                             |  ... check next_thread state
 106                         |                             |  thr_resume_lock.exit
 107                         | thr_start_lock.exit         |
 108                                                       | thr_event_lock.exit
 109 
 110 
 111 */
 112 
 113 static void JNICALL
 114 debug_agent(jvmtiEnv* jvmti, JNIEnv* jni, void *p) {
 115     JNIEnv *env = jni;
 116     jint thrStat;
 117     jobject temp;
 118 
 119     /* Notify VMInit callback as well as ThreadStart callback (if any)
 120      * that agent thread has been started
 121      */
 122     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorEnter, jvmti, agent_start_lock))) {
 123         result = STATUS_FAILED;
 124         NSK_COMPLAIN0("[agent] failed to acquire agent_start_lock\n");
 125     }
 126 
 127     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorNotifyAll, jvmti, agent_start_lock))) {
 128         result = STATUS_FAILED;
 129         NSK_COMPLAIN0("[agent] failed to notify about agent_start_lock\n");
 130     }
 131 
 132     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorExit, jvmti, agent_start_lock))) {
 133         result = STATUS_FAILED;
 134         NSK_COMPLAIN0("[agent] failed to release agent_start_lock\n");
 135     }
 136 
 137     NSK_DISPLAY0(">>> [agent] agent created\n");
 138 
 139     debug_agent_started = JNI_TRUE;
 140 
 141     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorEnter, jvmti, thr_start_lock))) {
 142         result = STATUS_FAILED;
 143         NSK_COMPLAIN0("[agent] failed to enter thr_start_lock\n");
 144     }
 145 
 146     while (terminate_debug_agent != JNI_TRUE) {
 147 
 148         if (next_thread == NULL ) {
 149             /* wait till new thread will be created and started */
 150             if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(RawMonitorWait, jvmti, thr_start_lock, (jlong)0))) {
 151                 result = STATUS_FAILED;
 152                 NSK_COMPLAIN0("[agent] Failed while waiting thr_start_lock\n");
 153             }
 154         }
 155 
 156         if (next_thread != NULL) {
 157             /* hmm, why NewGlobalRef is called one more time???
 158              * next_thread = NSK_CPP_STUB2(NewGlobalRef, env, next_thread);
 159              */
 160             if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(SuspendThread, jvmti, next_thread))) {
 161                 result = STATUS_FAILED;
 162                 NSK_COMPLAIN1("[agent] Failed to suspend thread#%d\n", eventsCount);
 163             }
 164 
 165             NSK_DISPLAY2(">>> [agent] thread#%d %s suspended ...\n", eventsCount, inf.name);
 166 
 167             /* these dummy calls provoke VM to hang */
 168             temp = NSK_CPP_STUB2(NewGlobalRef, env, next_thread);
 169             NSK_CPP_STUB2(DeleteGlobalRef, env, temp);
 170 
 171             if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(ResumeThread, jvmti, next_thread))) {
 172                 result = STATUS_FAILED;
 173                 NSK_COMPLAIN1("[agent] Failed to resume thread#%d\n", eventsCount);
 174             }
 175 
 176             NSK_DISPLAY2(">>> [agent] thread#%d %s resumed ...\n", eventsCount, inf.name);
 177 
 178             if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetThreadState, jvmti, next_thread, &thrStat))) {
 179                 result = STATUS_FAILED;
 180                 NSK_COMPLAIN1("[agent] Failed to get thread state for thread#%d\n", eventsCount);
 181             }
 182 
 183             NSK_DISPLAY3(">>> [agent] %s threadState=%s (%x)\n",
 184                     inf.name, TranslateState(thrStat), thrStat);
 185 
 186             if (thrStat & JVMTI_THREAD_STATE_SUSPENDED) {
 187                 NSK_COMPLAIN1("[agent] \"%s\" was not resumed\n", inf.name);
 188                 NSK_CPP_STUB2(FatalError, env, "[agent] could not recover");
 189             }
 190 
 191             NSK_CPP_STUB2(DeleteGlobalRef, env, next_thread);
 192             next_thread = NULL;
 193 
 194             /* Notify ThreadStart callback that thread has been resumed */
 195             if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorEnter, jvmti, thr_resume_lock))) {
 196                 NSK_COMPLAIN0("[agent] Failed to acquire thr_resume_lock\n");
 197                 result = STATUS_FAILED;
 198             }
 199 
 200             debug_agent_timed_out = JNI_FALSE;
 201 
 202             if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorNotify, jvmti, thr_resume_lock))) {
 203                 NSK_COMPLAIN0("[agent] Failed to notifing about thr_resume_lock\n");
 204                 result = STATUS_FAILED;
 205             }
 206 
 207             if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorExit, jvmti, thr_resume_lock))) {
 208                 NSK_COMPLAIN0("[agent] Failed to release thr_resume_lock\n");
 209                 result = STATUS_FAILED;
 210             }
 211         }
 212     }
 213 
 214     /*
 215      * We don't call RawMonitorExit(thr_start_lock) in the loop so we don't
 216      * lose any notify calls.
 217      */
 218     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorExit, jvmti, thr_start_lock))) {
 219         NSK_COMPLAIN0("[agent] Failed to release thr_start_lock\n");
 220         result = STATUS_FAILED;
 221     }
 222 
 223     NSK_DISPLAY0(">>> [agent] done.\n");
 224 }
 225 
 226 void JNICALL ThreadStart(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) {
 227     jint thrStat;
 228     jvmtiPhase phase;
 229 
 230     NSK_DISPLAY0(">>> [ThreadStart hook] start\n");
 231 
 232     /* skip if thread is 'agent thread' */
 233     if (NSK_CPP_STUB3(IsSameObject, env, agent_thread, thread) == JNI_TRUE) {
 234         NSK_DISPLAY0(">>> [ThreadStart hook] skip agent thread\n");
 235         NSK_DISPLAY0(">>> [ThreadStart hook] end\n");
 236         return;
 237     }
 238 
 239     /* wait till agent thread is started
 240      * (otherwise can fail while waiting on thr_resume_thread due to timeout)
 241      */
 242     if (debug_agent_started != JNI_TRUE) {
 243         if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorEnter, jvmti_env, agent_start_lock))) {
 244             NSK_COMPLAIN0("[ThreadStart hook] Failed to acquire agent_start_lock\n");
 245             result = STATUS_FAILED;
 246         }
 247 
 248         while (debug_agent_started != JNI_TRUE) {
 249             NSK_DISPLAY1(">>> [ThreadStart hook] waiting %dms for agent thread to start\n", WAIT_TIME);
 250 
 251             if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(RawMonitorWait,
 252                     jvmti_env, agent_start_lock, (jlong)WAIT_TIME))) {
 253                 NSK_COMPLAIN0("[ThreadStart hook] Failed to wait for agent_start_lock\n");
 254                 result = STATUS_FAILED;
 255             }
 256         }
 257 
 258         if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorExit, jvmti_env, agent_start_lock))) {
 259             NSK_COMPLAIN0("[ThreadStart hook] Failed to release agent_start_lock\n");
 260             result = STATUS_FAILED;
 261         }
 262     }
 263 
 264 
 265     /* get JVMTI phase */
 266     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetPhase, jvmti_env, &phase))) {
 267         NSK_COMPLAIN0("[ThreadStart hook] Failed to get JVMTI phase\n");
 268         result = STATUS_FAILED;
 269     }
 270 
 271     /* Acquire event lock,
 272      * so only one StartThread callback could be proceeded at the time
 273      */
 274     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorEnter, jvmti_env, thr_event_lock))) {
 275         NSK_COMPLAIN0("[ThreadStart hook] Failed to acquire thr_event_lock\n");
 276         result = STATUS_FAILED;
 277     }
 278 
 279     {
 280         /* Get thread name */
 281         inf.name = (char*) "UNKNOWN";
 282         if (phase == JVMTI_PHASE_LIVE) {
 283             /* GetThreadInfo may only be called during the live phase */
 284             if (!NSK_JVMTI_VERIFY(
 285                     NSK_CPP_STUB3(GetThreadInfo, jvmti_env, thread, &inf))) {
 286                 NSK_COMPLAIN1("[ThreadStart hook] Failed to get thread infor for thread#%d\n", eventsCount);
 287                 result = STATUS_FAILED;
 288             }
 289         }
 290 
 291         NSK_DISPLAY2(">>> [ThreadStart hook] thread#%d: %s\n", eventsCount, inf.name);
 292 
 293         /* Acquire thr_start_lock */
 294         if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorEnter, jvmti_env, thr_start_lock))) {
 295             NSK_COMPLAIN1("[ThreadStart hook] thread#%d failed to acquire thr_start_lock\n", eventsCount);
 296             result = STATUS_FAILED;
 297         }
 298 
 299             /* Acquire thr_resume_lock before we release thr_start_lock to prevent
 300              * debug agent from notifying us before we are ready.
 301          */
 302         if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorEnter, jvmti_env, thr_resume_lock))) {
 303             NSK_COMPLAIN1("[ThreadStart hook] thread#%d failed to acquire thr_resume_lock\n", eventsCount);
 304             result = STATUS_FAILED;
 305         }
 306 
 307         /* Store thread */
 308         next_thread = NSK_CPP_STUB2(NewGlobalRef, env, thread);
 309         debug_agent_timed_out = JNI_TRUE;
 310 
 311         /* Notify agent thread about new started thread and let agent thread to work with it */
 312         if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorNotify, jvmti_env, thr_start_lock))) {
 313             NSK_COMPLAIN1("[ThreadStart hook] thread#%d failed to notify about thr_start_lock\n", eventsCount);
 314             result = STATUS_FAILED;
 315         }
 316 
 317         if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorExit, jvmti_env, thr_start_lock))) {
 318             NSK_COMPLAIN1("[ThreadStart hook] thread#%d failed to release thr_start_lock\n", eventsCount);
 319             result = STATUS_FAILED;
 320         }
 321 
 322         /* Wait till this started thread will be resumed by agent thread */
 323         if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(RawMonitorWait,
 324                 jvmti_env, thr_resume_lock, (jlong)WAIT_TIME ))) {
 325             NSK_COMPLAIN1("[ThreadStart hook] thread#%d failed while waiting for thr_resume_lock\n", eventsCount);
 326             result = STATUS_FAILED;
 327         }
 328 
 329         if (debug_agent_timed_out == JNI_TRUE) {
 330             NSK_COMPLAIN1("[ThreadStart hook] \"%s\": debug agent timed out\n", inf.name);
 331             NSK_CPP_STUB2(FatalError, env, "[ThreadStart hook] could not recover");
 332         }
 333 
 334         /* Release thr_resume_lock lock */
 335         if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorExit, jvmti_env, thr_resume_lock))) {
 336             NSK_COMPLAIN1("[ThreadStart hook] thread#%d failed to release thr_resume_lock\n", eventsCount);
 337             result = STATUS_FAILED;
 338         }
 339 
 340         /* check that thread is not in SUSPENDED state */
 341         if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(GetThreadState, jvmti_env, thread, &thrStat))) {
 342             NSK_COMPLAIN1("[ThreadStart hook] Failed to get thread state for thread#%d\n", eventsCount);
 343             result = STATUS_FAILED;
 344         }
 345 
 346         NSK_DISPLAY2(">>> [ThreadStart hook] threadState=%s (%x)\n",
 347                 TranslateState(thrStat), thrStat);
 348 
 349         if (thrStat & JVMTI_THREAD_STATE_SUSPENDED) {
 350             NSK_COMPLAIN1("[ThreadStart hook] \"%s\" was self-suspended\n", inf.name);
 351             NSK_CPP_STUB2(FatalError, env, "[ThreadStart hook] could not recover");
 352         }
 353 
 354         eventsCount++;
 355     }
 356 
 357     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorExit, jvmti_env, thr_event_lock))) {
 358         NSK_COMPLAIN0("[ThreadStart hook] Failed to release thr_event_lock\n");
 359         result = STATUS_FAILED;
 360     }
 361 
 362     NSK_DISPLAY0(">>> [ThreadStart hook] end\n");
 363 }
 364 
 365 void JNICALL VMInit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thr) {
 366     jclass cls = NULL;
 367     jmethodID mid = NULL;
 368 
 369     NSK_DISPLAY0(">>> VMInit event: start\n");
 370 
 371     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
 372             jvmti_env, JVMTI_ENABLE, JVMTI_EVENT_THREAD_START, NULL))) {
 373         NSK_COMPLAIN0("TEST FAILED: failed to enable JVMTI_EVENT_THREAD_START\n");
 374         return;
 375     }
 376 
 377     /* Start agent thread */
 378     if (!NSK_VERIFY((cls =
 379             NSK_CPP_STUB2(FindClass, env, "java/lang/Thread")) != NULL)) {
 380         result = STATUS_FAILED;
 381             NSK_COMPLAIN0("TEST FAILED: Cannot start agent thread: FindClass() failed\n");
 382         return;
 383     }
 384 
 385 
 386     if (!NSK_VERIFY((mid =
 387             NSK_CPP_STUB4(GetMethodID, env, cls, "<init>", "()V")) != NULL)) {
 388         result = STATUS_FAILED;
 389             NSK_COMPLAIN0("TEST FAILED: Cannot start agent thread: GetMethodID() failed\n");
 390         return;
 391     }
 392 
 393 
 394     if (!NSK_VERIFY((agent_thread =
 395             NSK_CPP_STUB3(NewObject, env, cls, mid)) != NULL)) {
 396         result = STATUS_FAILED;
 397             NSK_COMPLAIN0("Cannot start agent thread: NewObject() failed\n");
 398         return;
 399     }
 400 
 401     agent_thread = (jthread) NSK_CPP_STUB2(NewGlobalRef, env, agent_thread);
 402     if (agent_thread == NULL) {
 403         result = STATUS_FAILED;
 404         NSK_COMPLAIN0("Cannot create global reference for agent_thread\n");
 405         return;
 406     }
 407 
 408     /*
 409      * Grab agent_start_lock before launching debug_agent to prevent
 410      * debug_agent from notifying us before we are ready.
 411      */
 412 
 413     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorEnter, jvmti_env, agent_start_lock))) {
 414         result = STATUS_FAILED;
 415         NSK_COMPLAIN0("TEST FAILED: failed to enter agent_start_lock\n");
 416     }
 417 
 418     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB5(RunAgentThread,
 419             jvmti_env, agent_thread, debug_agent, NULL, JVMTI_THREAD_NORM_PRIORITY))) {
 420         result = STATUS_FAILED;
 421         NSK_COMPLAIN0("TEST FAILED: failed to create agent thread\n");
 422     }
 423 
 424     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(RawMonitorWait, jvmti_env, agent_start_lock, (jlong)0))) {
 425         result = STATUS_FAILED;
 426         NSK_COMPLAIN0("TEST FAILED: failed to wait agent_start_lock\n");
 427     }
 428 
 429     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(RawMonitorExit, jvmti_env, agent_start_lock))) {
 430         result = STATUS_FAILED;
 431         NSK_COMPLAIN0("TEST FAILED: failed to exit agent_start_lock\n");
 432     }
 433 
 434     NSK_DISPLAY0(">>> VMInit event: end\n");
 435 }
 436 
 437 void JNICALL VMDeath(jvmtiEnv *jvmti_env, JNIEnv *env) {
 438     NSK_DISPLAY0(">>> VMDeath event\n");
 439 
 440     terminate_debug_agent = JNI_TRUE;
 441 }
 442 
 443 #ifdef STATIC_BUILD
 444 JNIEXPORT jint JNICALL Agent_OnLoad_threadstart002(JavaVM *jvm, char *options, void *reserved) {
 445     return Agent_Initialize(jvm, options, reserved);
 446 }
 447 JNIEXPORT jint JNICALL Agent_OnAttach_threadstart002(JavaVM *jvm, char *options, void *reserved) {
 448     return Agent_Initialize(jvm, options, reserved);
 449 }
 450 JNIEXPORT jint JNI_OnLoad_threadstart002(JavaVM *jvm, char *options, void *reserved) {
 451     return JNI_VERSION_1_8;
 452 }
 453 #endif
 454 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 455 
 456     /* init framework and parse options */
 457     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
 458         return JNI_ERR;
 459 
 460     /* create JVMTI environment */
 461     if (!NSK_VERIFY((jvmti =
 462             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) {
 463         NSK_COMPLAIN0("TEST FAILED: failed to create JVMTIEnv\n");
 464         return JNI_ERR;
 465     }
 466 
 467     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetPotentialCapabilities, jvmti, &caps))) {
 468         NSK_COMPLAIN0("TEST FAILED: failed to get potential capabilities\n");
 469         return JNI_ERR;
 470     }
 471 
 472     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(AddCapabilities, jvmti, &caps))) {
 473         NSK_COMPLAIN0("TEST FAILED: failed to add capabilities during agent load\n");
 474         return JNI_ERR;
 475     }
 476 
 477     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetCapabilities, jvmti, &caps))) {
 478         NSK_COMPLAIN0("TEST FAILED: failed to get capabilities\n");
 479         return JNI_ERR;
 480     }
 481 
 482     if (!caps.can_suspend) {
 483         NSK_DISPLAY0("WARNING: suspend/resume is not implemented\n");
 484     }
 485 
 486     /* create raw monitors */
 487     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(CreateRawMonitor, jvmti, "_agent_start_lock", &agent_start_lock))) {
 488         NSK_COMPLAIN0("TEST FAILED: failed to create agent_start_lock\n");
 489         return JNI_ERR;
 490     }
 491 
 492     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(CreateRawMonitor, jvmti, "_thr_event_lock", &thr_event_lock))) {
 493         NSK_COMPLAIN0("TEST FAILED: failed to create thr_event_lock\n");
 494         return JNI_ERR;
 495     }
 496 
 497     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(CreateRawMonitor, jvmti, "_thr_start_lock", &thr_start_lock))) {
 498         NSK_COMPLAIN0("TEST FAILED: failed to create thr_start_lock\n");
 499         return JNI_ERR;
 500     }
 501 
 502     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(CreateRawMonitor, jvmti, "_thr_resume_lock", &thr_resume_lock))) {
 503         NSK_COMPLAIN0("TEST FAILED: failed to create thr_resume_lock\n");
 504         return JNI_ERR;
 505     }
 506 
 507     callbacks.VMInit = &VMInit;
 508     callbacks.VMDeath = &VMDeath;
 509     callbacks.ThreadStart = &ThreadStart;
 510 
 511     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetEventCallbacks, jvmti, &callbacks, sizeof(callbacks)))) {
 512         NSK_COMPLAIN0("TEST FAILED: failed to set event callbacks\n");
 513         return JNI_ERR;
 514     }
 515 
 516     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
 517             jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL))) {
 518         NSK_COMPLAIN0("TEST FAILED: failed to enable JVMTI_EVENT_VM_INIT\n");
 519         return JNI_ERR;
 520     }
 521 
 522     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB4(SetEventNotificationMode,
 523             jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL))) {
 524         NSK_COMPLAIN0("TEST FAILED: failed to enable JVMTI_EVENT_VM_DEATH\n");
 525         return JNI_ERR;
 526     }
 527 
 528     return JNI_OK;
 529 }
 530 
 531 JNIEXPORT jint JNICALL
 532 Java_nsk_jvmti_ThreadStart_threadstart002_check(JNIEnv *env, jclass cls) {
 533     if (eventsCount == 0) {
 534         NSK_COMPLAIN0("None of thread start events!\n");
 535         result = STATUS_FAILED;
 536     }
 537 
 538     NSK_DISPLAY1(">>> total of thread start events: %d\n", eventsCount);
 539 
 540     return result;
 541 }
 542 
 543 }