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