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 <string.h> 25 #include "jvmti.h" 26 #include "agent_common.h" 27 #include "jni_tools.h" 28 #include "jvmti_tools.h" 29 30 extern "C" { 31 32 /* ============================================================================= */ 33 34 /* scaffold objects */ 35 static jlong timeout = 0; 36 37 /* constant names */ 38 #define THREAD_NAME "TestedThread" 39 40 /* constants */ 41 #define DEFAULT_THREADS_COUNT 10 42 #define EVENTS_COUNT 1 43 44 /* events list */ 45 static jvmtiEvent eventsList[EVENTS_COUNT] = { 46 JVMTI_EVENT_THREAD_END 47 }; 48 49 static int threadsCount = 0; 50 static jthread* threads = NULL; 51 52 static volatile int eventsReceived = 0; 53 static jrawMonitorID eventsReceivedMtx = 0; 54 55 /* ============================================================================= */ 56 57 static int fillThreadsByName(jvmtiEnv* jvmti, JNIEnv* jni, 58 const char name[], int foundCount, jthread foundThreads[]); 59 60 /** Agent algorithm. */ 61 static void JNICALL 62 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { 63 64 NSK_DISPLAY0("Wait for threads to start\n"); 65 if (!nsk_jvmti_waitForSync(timeout)) 66 return; 67 68 /* perform testing */ 69 { 70 jvmtiError* results = NULL; 71 int i; 72 73 NSK_DISPLAY1("Allocate threads array: %d threads\n", threadsCount); 74 if (!NSK_JVMTI_VERIFY(jvmti->Allocate((threadsCount * sizeof(jthread)), 75 (unsigned char**)&threads))) { 76 nsk_jvmti_setFailStatus(); 77 return; 78 } 79 NSK_DISPLAY1(" ... allocated array: %p\n", (void*)threads); 80 81 NSK_DISPLAY1("Allocate results array: %d threads\n", threadsCount); 82 if (!NSK_JVMTI_VERIFY(jvmti->Allocate((threadsCount * sizeof(jvmtiError)), 83 (unsigned char**)&results))) { 84 nsk_jvmti_setFailStatus(); 85 return; 86 } 87 NSK_DISPLAY1(" ... allocated array: %p\n", (void*)threads); 88 89 NSK_DISPLAY1("Find threads: %d threads\n", threadsCount); 90 if (!NSK_VERIFY(fillThreadsByName(jvmti, jni, THREAD_NAME, threadsCount, threads))) 91 return; 92 93 NSK_DISPLAY0("Suspend threads list\n"); 94 if (!NSK_JVMTI_VERIFY(jvmti->SuspendThreadList(threadsCount, threads, results))) { 95 nsk_jvmti_setFailStatus(); 96 return; 97 } 98 99 NSK_DISPLAY0("Check threads results:\n"); 100 for (i = 0; i < threadsCount; i++) { 101 NSK_DISPLAY3(" ... thread #%d: %s (%d)\n", 102 i, TranslateError(results[i]), (int)results[i]); 103 if (!NSK_JVMTI_VERIFY(results[i])) 104 nsk_jvmti_setFailStatus(); 105 } 106 107 eventsReceived = 0; 108 NSK_DISPLAY1("Enable event: %s\n", "THREAD_END"); 109 if (!nsk_jvmti_enableEvents(JVMTI_ENABLE, EVENTS_COUNT, eventsList, NULL)) 110 return; 111 112 NSK_DISPLAY0("Let threads to run and finish\n"); 113 if (!nsk_jvmti_resumeSync()) 114 return; 115 116 NSK_DISPLAY0("Resume threads list\n"); 117 if (!NSK_JVMTI_VERIFY(jvmti->ResumeThreadList(threadsCount, threads, results))) { 118 nsk_jvmti_setFailStatus(); 119 return; 120 } 121 122 NSK_DISPLAY0("Check threads results:\n"); 123 for (i = 0; i < threadsCount; i++) { 124 NSK_DISPLAY3(" ... thread #%d: %s (%d)\n", 125 i, TranslateError(results[i]), (int)results[i]); 126 if (!NSK_JVMTI_VERIFY(results[i])) 127 nsk_jvmti_setFailStatus(); 128 } 129 130 NSK_DISPLAY1("Check that THREAD_END events received for timeout: %ld ms\n", (long)timeout); 131 { 132 jlong delta = 1000; 133 jlong time; 134 for (time = 0; time < timeout; time += delta) { 135 if (eventsReceived >= threadsCount) 136 break; 137 nsk_jvmti_sleep(delta); 138 } 139 140 if (eventsReceived < threadsCount) { 141 NSK_COMPLAIN1("Some threads have not ran and finished after resuming: %d threads\n", 142 (threadsCount - eventsReceived)); 143 nsk_jvmti_setFailStatus(); 144 } 145 } 146 147 NSK_DISPLAY1("Disable event: %s\n", "THREAD_END"); 148 if (!nsk_jvmti_enableEvents(JVMTI_DISABLE, EVENTS_COUNT, eventsList, NULL)) 149 return; 150 151 NSK_DISPLAY0("Wait for thread to finish\n"); 152 if (!nsk_jvmti_waitForSync(timeout)) 153 return; 154 155 NSK_DISPLAY0("Delete threads references\n"); 156 for (i = 0; i < threadsCount; i++) { 157 if (threads[i] != NULL) 158 NSK_TRACE(jni->DeleteGlobalRef(threads[i])); 159 } 160 161 NSK_DISPLAY1("Deallocate threads array: %p\n", (void*)threads); 162 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)threads))) { 163 nsk_jvmti_setFailStatus(); 164 } 165 166 NSK_DISPLAY1("Deallocate results array: %p\n", (void*)results); 167 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)results))) { 168 nsk_jvmti_setFailStatus(); 169 } 170 } 171 172 NSK_DISPLAY0("Let debugee to finish\n"); 173 if (!nsk_jvmti_resumeSync()) 174 return; 175 } 176 177 /* ============================================================================= */ 178 179 /** Find threads whose name starts with specified name prefix. */ 180 static int fillThreadsByName(jvmtiEnv* jvmti, JNIEnv* jni, 181 const char name[], int foundCount, jthread foundThreads[]) { 182 jint count = 0; 183 jthread* threads = NULL; 184 185 size_t len = strlen(name); 186 int found = 0; 187 int i; 188 189 for (i = 0; i < foundCount; i++) { 190 foundThreads[i] = NULL; 191 } 192 193 if (!NSK_JVMTI_VERIFY(jvmti->GetAllThreads(&count, &threads))) { 194 nsk_jvmti_setFailStatus(); 195 return NSK_FALSE; 196 } 197 198 found = 0; 199 for (i = 0; i < count; i++) { 200 jvmtiThreadInfo info; 201 202 if (!NSK_JVMTI_VERIFY(jvmti->GetThreadInfo(threads[i], &info))) { 203 nsk_jvmti_setFailStatus(); 204 break; 205 } 206 207 if (info.name != NULL && strncmp(name, info.name, len) == 0) { 208 NSK_DISPLAY3(" ... found thread #%d: %p (%s)\n", 209 found, threads[i], info.name); 210 if (found < foundCount) 211 foundThreads[found] = threads[i]; 212 found++; 213 } 214 215 } 216 217 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)threads))) { 218 nsk_jvmti_setFailStatus(); 219 return NSK_FALSE; 220 } 221 222 if (found != foundCount) { 223 NSK_COMPLAIN3("Unexpected number of tested threads found:\n" 224 "# name: %s\n" 225 "# found: %d\n" 226 "# expected: %d\n", 227 name, found, foundCount); 228 nsk_jvmti_setFailStatus(); 229 return NSK_FALSE; 230 } 231 232 NSK_DISPLAY1("Make global references for threads: %d threads\n", foundCount); 233 for (i = 0; i < foundCount; i++) { 234 if (!NSK_JNI_VERIFY(jni, (foundThreads[i] = (jthread) 235 jni->NewGlobalRef(foundThreads[i])) != NULL)) { 236 nsk_jvmti_setFailStatus(); 237 return NSK_FALSE; 238 } 239 NSK_DISPLAY2(" ... thread #%d: %p\n", i, foundThreads[i]); 240 } 241 242 return NSK_TRUE; 243 } 244 245 /* ============================================================================= */ 246 247 /** THREAD_END callback. */ 248 JNIEXPORT void JNICALL 249 callbackThreadEnd(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread) { 250 int i = 0; 251 252 jvmtiError e = jvmti->RawMonitorEnter(eventsReceivedMtx); 253 if ( !NSK_JVMTI_VERIFY(e) ) { 254 NSK_DISPLAY1(" ... ERROR entering raw monitor for thread %p\n", (void *) thread); 255 return; 256 } 257 258 /* check if event is for tested thread */ 259 for (i = 0; i < threadsCount; i++) { 260 if (thread != NULL && 261 jni->IsSameObject(threads[i], thread)) { 262 NSK_DISPLAY2(" ... received THREAD_END event for thread #%d: %p\n", 263 i, (void*)thread); 264 eventsReceived++; 265 jvmti->RawMonitorExit(eventsReceivedMtx); 266 return; 267 } 268 } 269 jvmti->RawMonitorExit(eventsReceivedMtx); 270 NSK_DISPLAY1(" ... received THREAD_END event for unknown thread: %p\n", (void*)thread); 271 } 272 273 /* ============================================================================= */ 274 275 /** Agent library initialization. */ 276 #ifdef STATIC_BUILD 277 JNIEXPORT jint JNICALL Agent_OnLoad_resumethrdlst002(JavaVM *jvm, char *options, void *reserved) { 278 return Agent_Initialize(jvm, options, reserved); 279 } 280 JNIEXPORT jint JNICALL Agent_OnAttach_resumethrdlst002(JavaVM *jvm, char *options, void *reserved) { 281 return Agent_Initialize(jvm, options, reserved); 282 } 283 JNIEXPORT jint JNI_OnLoad_resumethrdlst002(JavaVM *jvm, char *options, void *reserved) { 284 return JNI_VERSION_1_8; 285 } 286 #endif 287 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 288 jvmtiEnv* jvmti = NULL; 289 290 /* init framework and parse options */ 291 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 292 return JNI_ERR; 293 294 timeout = nsk_jvmti_getWaitTime() * 60 * 1000; 295 296 /* get options */ 297 threadsCount = nsk_jvmti_findOptionIntValue("threads", DEFAULT_THREADS_COUNT); 298 if (!NSK_VERIFY(threadsCount > 0)) 299 return JNI_ERR; 300 301 /* create JVMTI environment */ 302 if (!NSK_VERIFY((jvmti = 303 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) 304 return JNI_ERR; 305 306 /* add specific capabilities for suspending thread */ 307 { 308 jvmtiCapabilities suspendCaps; 309 memset(&suspendCaps, 0, sizeof(suspendCaps)); 310 suspendCaps.can_suspend = 1; 311 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&suspendCaps))) 312 return JNI_ERR; 313 } 314 315 /* set callbacks for THREAD_END event */ 316 { 317 jvmtiEventCallbacks callbacks; 318 memset(&callbacks, 0, sizeof(callbacks)); 319 callbacks.ThreadEnd = callbackThreadEnd; 320 if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)))) 321 return JNI_ERR; 322 } 323 324 /* create a mutex for the eventsReceived variable */ 325 { 326 if ( ! NSK_JVMTI_VERIFY(jvmti->CreateRawMonitor("eventsReceived", &eventsReceivedMtx))) { 327 return JNI_ERR; 328 } 329 } 330 331 /* register agent proc and arg */ 332 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 333 return JNI_ERR; 334 335 return JNI_OK; 336 } 337 338 /* ============================================================================= */ 339 340 }