|
1 | 1 | /*
|
2 |
| - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. |
| 2 | + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. |
3 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
4 | 4 | *
|
5 | 5 | * This code is free software; you can redistribute it and/or modify it
|
@@ -39,27 +39,45 @@ typedef struct {
|
39 | 39 | const char **thrNames;
|
40 | 40 | } info;
|
41 | 41 |
|
| 42 | +typedef struct { |
| 43 | + info expected; |
| 44 | + info unexpected; |
| 45 | +} threadInfo; |
| 46 | + |
42 | 47 | static jvmtiEnv *jvmti;
|
43 | 48 | static jrawMonitorID lock1;
|
44 | 49 | static jrawMonitorID lock2;
|
45 | 50 | static jboolean printdump = JNI_FALSE;
|
46 | 51 | static jint result = PASSED;
|
47 |
| -static jvmtiThreadInfo inf; |
48 |
| -static int sys_cnt; |
49 |
| -static const char *names0[] = { "main" }; |
50 |
| -static const char *names1[] = { "main", "thread1" }; |
51 |
| -static const char *names2[] = { "main", "Thread-" }; |
52 |
| -static info thrInfo[] = { |
53 |
| - { 1, names0 }, { 1, names0 }, { 2, names1 }, { 1, names0 }, { 2, names2 } |
| 52 | + |
| 53 | +static const char main_name[] = "main"; |
| 54 | +static const char thread1_name[] = "thread1"; |
| 55 | +static const char sys_thread_name[] = "SysThread"; |
| 56 | + |
| 57 | +static const char *main_only[] = { main_name }; |
| 58 | +static const char *thr1_only[] = { thread1_name }; |
| 59 | +static const char *sys_only[] = { sys_thread_name }; |
| 60 | +static const char *main_thr1[] = { main_name, thread1_name }; |
| 61 | +static const char *main_sys[] = { main_name, sys_thread_name }; |
| 62 | +static const char *thr1_sys[] = { thread1_name, sys_thread_name }; |
| 63 | + |
| 64 | +static threadInfo thrInfo[] = { |
| 65 | + {{1, main_only}, {2, thr1_sys}}, |
| 66 | + {{1, main_only}, {2, thr1_sys}}, |
| 67 | + {{2, main_thr1}, {1, sys_only}}, |
| 68 | + {{1, main_only}, {2, thr1_sys}}, |
| 69 | + {{2, main_sys}, {1, thr1_only}} |
54 | 70 | };
|
55 | 71 |
|
56 | 72 | jthread jthr(JNIEnv *env) {
|
57 | 73 | jclass thrClass;
|
58 | 74 | jmethodID cid;
|
59 | 75 | jthread res;
|
60 | 76 | thrClass = env->FindClass("java/lang/Thread");
|
61 |
| - cid = env->GetMethodID(thrClass, "<init>", "()V"); |
62 |
| - res = env->NewObject(thrClass, cid); |
| 77 | + cid = env->GetMethodID(thrClass, "<init>", "(Ljava/lang/String;)V"); |
| 78 | + jstring thread_name = env->NewStringUTF(sys_thread_name); |
| 79 | + res = env->NewObject(thrClass, cid, thread_name); |
| 80 | + env->DeleteLocalRef(thread_name); |
63 | 81 | return res;
|
64 | 82 | }
|
65 | 83 |
|
@@ -149,12 +167,22 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
|
149 | 167 | return JNI_OK;
|
150 | 168 | }
|
151 | 169 |
|
| 170 | +void releaseThreadInfo(JNIEnv *env, jvmtiThreadInfo *info) { |
| 171 | + jvmti->Deallocate((unsigned char *)info->name); |
| 172 | + if (info->thread_group != NULL) { |
| 173 | + env->DeleteLocalRef(info->thread_group); |
| 174 | + } |
| 175 | + if (info->context_class_loader != NULL) { |
| 176 | + env->DeleteLocalRef(info->context_class_loader); |
| 177 | + } |
| 178 | +} |
| 179 | + |
152 | 180 | JNIEXPORT void checkInfo(JNIEnv *env, int ind) {
|
153 | 181 | jint threadsCount = -1;
|
154 | 182 | jthread *threads;
|
155 |
| - int i, j, found; |
156 | 183 | jvmtiError err;
|
157 |
| - int num_unexpected = 0; |
| 184 | + int expected = 0; |
| 185 | + jvmtiThreadInfo inf; |
158 | 186 |
|
159 | 187 | if (printdump == JNI_TRUE) {
|
160 | 188 | printf(" >>> Check: %d\n", ind);
|
@@ -196,42 +224,49 @@ JNIEXPORT void checkInfo(JNIEnv *env, int ind) {
|
196 | 224 | return;
|
197 | 225 | }
|
198 | 226 |
|
199 |
| - for (i = 0; i < threadsCount; i++) { |
200 |
| - if (!isThreadExpected(jvmti, threads[i])) { |
201 |
| - num_unexpected++; |
| 227 | + // check unexpected threads |
| 228 | + for (int i = 0; i < threadsCount; i++) { |
| 229 | + err = jvmti->GetThreadInfo(threads[i], &inf); |
| 230 | + if (err != JVMTI_ERROR_NONE) { |
| 231 | + printf("Failed to get thread info: %s (%d)\n", |
| 232 | + TranslateError(err), err); |
| 233 | + result = STATUS_FAILED; |
| 234 | + return; |
| 235 | + } |
| 236 | + if (printdump == JNI_TRUE) { |
| 237 | + printf(" >>> %s", inf.name); |
| 238 | + } |
| 239 | + bool found = false; |
| 240 | + for (int j = 0; j < thrInfo[ind].unexpected.cnt && !found; j++) { |
| 241 | + found = (inf.name != NULL && strcmp(inf.name, thrInfo[ind].unexpected.thrNames[j]) == 0); |
202 | 242 | }
|
| 243 | + if (found) { |
| 244 | + printf("Point %d: detected unexpected thread %s\n", ind, inf.name); |
| 245 | + result = STATUS_FAILED; |
| 246 | + } |
| 247 | + releaseThreadInfo(env, &inf); |
203 | 248 | }
|
204 |
| - |
205 |
| - if (threadsCount - num_unexpected != thrInfo[ind].cnt + sys_cnt) { |
206 |
| - printf("Point %d: number of threads expected: %d, got: %d\n", |
207 |
| - ind, thrInfo[ind].cnt + sys_cnt, threadsCount - num_unexpected); |
208 |
| - result = STATUS_FAILED; |
209 |
| - return; |
| 249 | + if (printdump == JNI_TRUE) { |
| 250 | + printf("\n"); |
210 | 251 | }
|
211 | 252 |
|
212 |
| - for (i = 0; i < thrInfo[ind].cnt; i++) { |
213 |
| - for (j = 0, found = 0; j < threadsCount && !found; j++) { |
| 253 | + // verify all expected threads are present |
| 254 | + for (int i = 0; i < thrInfo[ind].expected.cnt; i++) { |
| 255 | + bool found = false; |
| 256 | + for (int j = 0; j < threadsCount && !found; j++) { |
214 | 257 | err = jvmti->GetThreadInfo(threads[j], &inf);
|
215 | 258 | if (err != JVMTI_ERROR_NONE) {
|
216 | 259 | printf("Failed to get thread info: %s (%d)\n",
|
217 | 260 | TranslateError(err), err);
|
218 | 261 | result = STATUS_FAILED;
|
219 | 262 | return;
|
220 | 263 | }
|
221 |
| - if (printdump == JNI_TRUE) { |
222 |
| - printf(" >>> %s", inf.name); |
223 |
| - } |
224 |
| - found = (inf.name != NULL && |
225 |
| - strstr(inf.name, thrInfo[ind].thrNames[i]) == inf.name && |
226 |
| - (ind == 4 || strlen(inf.name) == |
227 |
| - strlen(thrInfo[ind].thrNames[i]))); |
228 |
| - } |
229 |
| - if (printdump == JNI_TRUE) { |
230 |
| - printf("\n"); |
| 264 | + found = (inf.name != NULL && strcmp(inf.name, thrInfo[ind].expected.thrNames[j]) == 0); |
| 265 | + releaseThreadInfo(env, &inf); |
231 | 266 | }
|
232 | 267 | if (!found) {
|
233 | 268 | printf("Point %d: thread %s not detected\n",
|
234 |
| - ind, thrInfo[ind].thrNames[i]); |
| 269 | + ind, thrInfo[ind].expected.thrNames[i]); |
235 | 270 | result = STATUS_FAILED;
|
236 | 271 | }
|
237 | 272 | }
|
@@ -265,33 +300,6 @@ JNIEXPORT void checkInfo(JNIEnv *env, int ind) {
|
265 | 300 | }
|
266 | 301 | }
|
267 | 302 |
|
268 |
| -JNIEXPORT void JNICALL Java_nsk_jvmti_GetAllThreads_allthr001_setSysCnt(JNIEnv *env, jclass cls) { |
269 |
| - jint threadsCount = -1; |
270 |
| - jthread *threads; |
271 |
| - jvmtiError err; |
272 |
| - int i; |
273 |
| - |
274 |
| - err = jvmti->GetAllThreads(&threadsCount, &threads); |
275 |
| - if (err != JVMTI_ERROR_NONE) { |
276 |
| - printf("Failed to get all threads (count): %s (%d)\n", |
277 |
| - TranslateError(err), err); |
278 |
| - result = STATUS_FAILED; |
279 |
| - return; |
280 |
| - } |
281 |
| - |
282 |
| - sys_cnt = threadsCount - 1; |
283 |
| - |
284 |
| - for (i = 0; i < threadsCount; i++) { |
285 |
| - if (!isThreadExpected(jvmti, threads[i])) { |
286 |
| - sys_cnt--; |
287 |
| - } |
288 |
| - } |
289 |
| - |
290 |
| - if (printdump == JNI_TRUE) { |
291 |
| - printf(" >>> number of system threads: %d\n", sys_cnt); |
292 |
| - } |
293 |
| -} |
294 |
| - |
295 | 303 | JNIEXPORT void JNICALL
|
296 | 304 | Java_nsk_jvmti_GetAllThreads_allthr001_checkInfo(JNIEnv *env, jclass cls, jint ind) {
|
297 | 305 | checkInfo(env, ind);
|
|
0 commit comments