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