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 /* constan names */ 38 #define THREAD_NAME "TestedThread" 39 40 /* constants */ 41 #define STORAGE_DATA_SIZE 1024 42 #define STORAGE_DATA_CHAR 'X' 43 #define EVENTS_COUNT 2 44 45 /* events list */ 46 static jvmtiEvent eventsList[EVENTS_COUNT] = { 47 JVMTI_EVENT_THREAD_START, 48 JVMTI_EVENT_THREAD_END 49 }; 50 51 /* storage structure */ 52 typedef struct _StorageStructure { 53 char data[STORAGE_DATA_SIZE]; 54 } StorageStructure; 55 56 /* storage data */ 57 static StorageStructure storageData; 58 static StorageStructure* initialStorage = &storageData; 59 60 /* events counts */ 61 static int eventsStart = 0; 62 static int eventsEnd = 0; 63 64 /* ============================================================================= */ 65 66 /** Agent algorithm. */ 67 static void JNICALL 68 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { 69 70 NSK_DISPLAY0("Wait for thread to create\n"); 71 if (!nsk_jvmti_waitForSync(timeout)) 72 return; 73 74 /* perform testing */ 75 { 76 memset(storageData.data, STORAGE_DATA_CHAR, STORAGE_DATA_SIZE); 77 78 eventsStart = 0; 79 eventsEnd = 0; 80 NSK_DISPLAY1("Enable events: %d events\n", EVENTS_COUNT); 81 if (!nsk_jvmti_enableEvents(JVMTI_ENABLE, EVENTS_COUNT, eventsList, NULL)) 82 return; 83 84 NSK_DISPLAY0("Let tested thread to run\n"); 85 if (!nsk_jvmti_resumeSync()) 86 return; 87 88 NSK_DISPLAY0("Wait for tested thread to finish\n"); 89 if (!nsk_jvmti_waitForSync(timeout)) 90 return; 91 92 NSK_DISPLAY1("Disable events: %d events\n", EVENTS_COUNT); 93 if (!nsk_jvmti_enableEvents(JVMTI_DISABLE, EVENTS_COUNT, eventsList, NULL)) 94 return; 95 96 NSK_DISPLAY1("Check if all expected events received for tested thread: %s\n", 97 THREAD_NAME); 98 if (eventsStart <= 0 || eventsStart != eventsEnd) { 99 NSK_COMPLAIN3("Unexpected number of events received for tedted thread:\n" 100 "# thread name: %s\n" 101 "# THREAD_START: %d events\n" 102 "# THREAD_END: %d events\n", 103 THREAD_NAME, 104 eventsStart, eventsEnd); 105 nsk_jvmti_setFailStatus(); 106 } 107 } 108 109 NSK_DISPLAY0("Let debugee to finish\n"); 110 if (!nsk_jvmti_resumeSync()) 111 return; 112 } 113 114 /* ============================================================================= */ 115 116 /** THREAD_START callback. */ 117 JNIEXPORT void JNICALL 118 callbackThreadStart(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread) { 119 /* check if event is for tested thread */ 120 if (thread != NULL) { 121 jvmtiThreadInfo info; 122 123 if (!NSK_JVMTI_VERIFY( 124 NSK_CPP_STUB3(GetThreadInfo, jvmti, thread, &info))) { 125 nsk_jvmti_setFailStatus(); 126 return; 127 } 128 129 if (info.name != NULL && strcmp(info.name, THREAD_NAME) == 0) { 130 NSK_DISPLAY2(" ... received THREAD_START event for tested thread: %p (%s)\n", 131 (void*)thread, info.name); 132 eventsStart++; 133 134 NSK_DISPLAY1("SetThreadLocalStorage() for current thread with pointer: %p\n", 135 (void*)initialStorage); 136 if (!NSK_JVMTI_VERIFY( 137 NSK_CPP_STUB3(SetThreadLocalStorage, jvmti, 138 NULL, (void*)initialStorage))) { 139 nsk_jvmti_setFailStatus(); 140 return; 141 } 142 } 143 } 144 } 145 146 147 /** THREAD_END callback. */ 148 JNIEXPORT void JNICALL 149 callbackThreadEnd(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread) { 150 /* check if event is for tested thread */ 151 if (thread != NULL) { 152 jvmtiThreadInfo info; 153 154 if (!NSK_JVMTI_VERIFY( 155 NSK_CPP_STUB3(GetThreadInfo, jvmti, thread, &info))) { 156 nsk_jvmti_setFailStatus(); 157 return; 158 } 159 160 if (info.name != NULL && strcmp(info.name, THREAD_NAME) == 0) { 161 NSK_DISPLAY2(" ... received THREAD_END event for tested thread: %p (%s)\n", 162 (void*)thread, info.name); 163 eventsEnd++; 164 165 /* get storage data */ 166 { 167 StorageStructure* obtainedStorage = NULL; 168 169 NSK_DISPLAY0("GetThreadLocalStorage() for current thread\n"); 170 if (!NSK_JVMTI_VERIFY( 171 NSK_CPP_STUB3(GetThreadLocalStorage, jvmti, 172 NULL, (void**)&obtainedStorage))) { 173 nsk_jvmti_setFailStatus(); 174 return; 175 } 176 NSK_DISPLAY1(" ... got pointer: %p\n", (void*)obtainedStorage); 177 178 NSK_DISPLAY0("Check storage data obtained for current thread\n"); 179 if (obtainedStorage != initialStorage) { 180 NSK_COMPLAIN3("Wrong storage pointer returned for current thread:\n" 181 "# thread: %p\n" 182 "# got pointer: %p\n" 183 "# expected: %p\n", 184 (void*)thread, 185 (void*)obtainedStorage, (void*)initialStorage); 186 nsk_jvmti_setFailStatus(); 187 } else { 188 int changed = 0; 189 int i; 190 191 for (i = 0; i < STORAGE_DATA_SIZE; i++) { 192 if (obtainedStorage->data[i] != STORAGE_DATA_CHAR) { 193 changed++; 194 } 195 } 196 197 if (changed > 0) { 198 NSK_COMPLAIN3("Data changed in returned storage for current thread:\n" 199 "# thread: %p\n" 200 "# changed bytes: %d\n" 201 "# total bytes: %d\n", 202 (void*)thread, 203 changed, STORAGE_DATA_SIZE); 204 nsk_jvmti_setFailStatus(); 205 } 206 } 207 } 208 } 209 } 210 } 211 212 /* ============================================================================= */ 213 214 /** Agent library initialization. */ 215 #ifdef STATIC_BUILD 216 JNIEXPORT jint JNICALL Agent_OnLoad_setthrdstor003(JavaVM *jvm, char *options, void *reserved) { 217 return Agent_Initialize(jvm, options, reserved); 218 } 219 JNIEXPORT jint JNICALL Agent_OnAttach_setthrdstor003(JavaVM *jvm, char *options, void *reserved) { 220 return Agent_Initialize(jvm, options, reserved); 221 } 222 JNIEXPORT jint JNI_OnLoad_setthrdstor003(JavaVM *jvm, char *options, void *reserved) { 223 return JNI_VERSION_1_8; 224 } 225 #endif 226 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 227 jvmtiEnv* jvmti = NULL; 228 229 /* init framework and parse options */ 230 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 231 return JNI_ERR; 232 233 timeout = nsk_jvmti_getWaitTime() * 60 * 1000; 234 235 /* create JVMTI environment */ 236 if (!NSK_VERIFY((jvmti = 237 nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL)) 238 return JNI_ERR; 239 240 /* set callbacks for thread events */ 241 { 242 jvmtiEventCallbacks callbacks; 243 memset(&callbacks, 0, sizeof(callbacks)); 244 callbacks.ThreadStart = callbackThreadStart; 245 callbacks.ThreadEnd = callbackThreadEnd; 246 if (!NSK_JVMTI_VERIFY( 247 NSK_CPP_STUB3(SetEventCallbacks, jvmti, &callbacks, sizeof(callbacks)))) 248 return JNI_ERR; 249 } 250 251 /* register agent proc and arg */ 252 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 253 return JNI_ERR; 254 255 return JNI_OK; 256 } 257 258 /* ============================================================================= */ 259 260 }