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 }