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 JNIEnv* jni = NULL;
36 static jvmtiEnv *jvmti = NULL;
37 static jlong timeout = 0;
38 
39 /* number of tested threads */
40 #define THREADS_KINDS           6
41 #define DEFAULT_THREADS_NUMBER  1
42 
43 /* names of tested threads */
44 static const char* threadsName[THREADS_KINDS] = {
45     "ThreadRunning",
46     "ThreadEntering",
47     "ThreadWaiting",
48     "ThreadSleeping",
49     "ThreadRunningInterrupted",
50     "ThreadRunningNative"
51 };
52 
53 /* expected states of tested threads */
54 #define JVMTI_THREAD_STATE_NOT_STARTED 0
55 static jint threadsState[THREADS_KINDS] = {
56     JVMTI_THREAD_STATE_RUNNABLE,
57     JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER,
58     JVMTI_THREAD_STATE_IN_OBJECT_WAIT,
59     JVMTI_THREAD_STATE_SLEEPING,
60     JVMTI_THREAD_STATE_RUNNABLE,
61     JVMTI_THREAD_STATE_RUNNABLE
62 };
63 
64 /* references to tested threads */
65 static jthread* threadsList[THREADS_KINDS];
66 static int threadsCounts[THREADS_KINDS];
67 static int threadsCount = 0;
68 
69 /* indexes of known threads */
70 static const int interruptedThreadIndex = THREADS_KINDS - 2;
71 static const int nativeThreadIndex = THREADS_KINDS - 1;
72 
73 /* ============================================================================= */
74 
75 /* testcase(s) */
76 static int prepare();
77 static int checkThreads(int suspended, const char* kind, jlong timeout);
78 static int suspendThreadsList(int suspend);
79 static int suspendThreadsIndividually(int suspend);
80 static int clean();
81 
82 /* ============================================================================= */
83 
84 /** Agent algorithm. */
85 static void JNICALL
agentProc(jvmtiEnv * jvmti,JNIEnv * agentJNI,void * arg)86 agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) {
87     jni = agentJNI;
88 
89     /* wait for initial sync */
90     if (!nsk_jvmti_waitForSync(timeout))
91         return;
92 
93     /* perform testcase(s) */
94     {
95         /* prepare data: find threads */
96         if (!prepare()) {
97             nsk_jvmti_setFailStatus();
98             return;
99         }
100 
101         /* testcase #1: check not suspended threads */
102         NSK_DISPLAY0("Testcase #1: check state of not suspended threads\n");
103         if (!checkThreads(NSK_FALSE, "not suspended", timeout))
104             return;
105 
106         /* suspend threads */
107         NSK_DISPLAY0("Suspend threads list\n");
108         if (!suspendThreadsList(NSK_TRUE))
109             return;
110 
111         /* testcase #2: check suspended threads */
112         NSK_DISPLAY0("Testcase #2: check state of suspended threads\n");
113         if (!checkThreads(NSK_TRUE, "suspended", 0))
114             return;
115 
116         /* resume threads */
117         NSK_DISPLAY0("Resume threads list\n");
118         if (!suspendThreadsList(NSK_FALSE))
119             return;
120 
121         /* testcase #3: check resumed threads */
122         NSK_DISPLAY0("Testcase #3: check state of resumed threads\n");
123         if (!checkThreads(NSK_FALSE, "resumed", 0))
124             return;
125 
126         /* clean date: delete threads references */
127         if (!clean()) {
128             nsk_jvmti_setFailStatus();
129             return;
130         }
131     }
132 
133     /* resume debugee after last sync */
134     if (!nsk_jvmti_resumeSync())
135         return;
136 }
137 
138 /* ============================================================================= */
139 
140 /**
141  * Prepare data:
142  *    - clean threads list
143  *    - get all live threads
144  *    - get threads name
145  *    - find tested threads
146  *    - make global refs
147  */
prepare()148 static int prepare() {
149     jthread *allThreadsList = NULL;
150     jint allThreadsCount = 0;
151     int notfound = 0;
152     int i, j;
153 
154     NSK_DISPLAY1("Prepare: find tested threads: %d kinds\n", THREADS_KINDS);
155 
156     /* allocate and clean threads list */
157     for (i = 0; i < THREADS_KINDS; i++) {
158         threadsCounts[i] = 0;
159         threadsList[i] = NULL;
160 
161         if (!NSK_JVMTI_VERIFY(jvmti->Allocate(threadsCount * sizeof(jthread),
162                                               (unsigned char**)&threadsList[i])))
163             return NSK_FALSE;
164 
165         for (j = 0; j < threadsCount; j++) {
166             threadsList[i][j] = NULL;
167         }
168     }
169 
170     /* get all live threads */
171     if (!NSK_JVMTI_VERIFY(jvmti->GetAllThreads(&allThreadsCount, &allThreadsList)))
172         return NSK_FALSE;
173 
174     if (!NSK_VERIFY(allThreadsCount > 0 && allThreadsList != NULL))
175         return NSK_FALSE;
176 
177     /* find tested threads */
178     for (i = 0; i < allThreadsCount; i++) {
179         jvmtiThreadInfo threadInfo;
180 
181         if (!NSK_VERIFY(allThreadsList[i] != NULL))
182             return NSK_FALSE;
183 
184         /* get thread name (info) */
185         if (!NSK_JVMTI_VERIFY(jvmti->GetThreadInfo(allThreadsList[i], &threadInfo)))
186             return NSK_FALSE;
187 
188         /* find by name */
189         if (threadInfo.name != NULL) {
190             for (j = 0; j < THREADS_KINDS; j++) {
191                 if (strcmp(threadInfo.name, threadsName[j]) == 0) {
192                     int k = threadsCounts[j];
193                     if (k < threadsCount)
194                         threadsList[j][k] = allThreadsList[i];
195                     threadsCounts[j]++;
196                 }
197             }
198         }
199     }
200 
201     /* deallocate all threads list */
202     if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)allThreadsList)))
203         return NSK_FALSE;
204 
205     /* check if all tested threads found */
206     notfound = 0;
207     for (i = 0; i < THREADS_KINDS; i++) {
208         if (threadsCounts[i] != threadsCount) {
209             NSK_COMPLAIN3("Found unexpected number of tested threads (%s):\n"
210                             "#   found:    %d\n"
211                             "#   expected: %d\n",
212                             threadsName[i], threadsCounts[i], threadsCount);
213             nsk_jvmti_setFailStatus();
214             notfound++;
215         }
216     }
217 
218     if (notfound > 0)
219         return NSK_FALSE;
220 
221     /* make global refs */
222     for (i = 0; i < THREADS_KINDS; i++) {
223         for (j = 0; j < threadsCount; j++) {
224             if (!NSK_JNI_VERIFY(jni, (threadsList[i][j] =
225                     jni->NewGlobalRef(threadsList[i][j])) != NULL))
226                 return NSK_FALSE;
227         }
228     }
229 
230     return NSK_TRUE;
231 }
232 
233 /**
234  * Suspend or resume tested threads list.
235  */
suspendThreadsList(int suspend)236 static int suspendThreadsList(int suspend) {
237     jlong resultsSize = threadsCount * sizeof(jvmtiError);
238     jvmtiError* results = NULL;
239     const char* kind = (suspend ? "suspending" : "resuming");
240     int i, j;
241 
242     /* allocate results array */
243     if (!NSK_JVMTI_VERIFY(jvmti->Allocate(resultsSize, (unsigned char**)&results))) {
244         nsk_jvmti_setFailStatus();
245         return NSK_FALSE;
246     }
247 
248     for (i = 0; i < THREADS_KINDS; i++) {
249         /* suspend or resume threads list */
250         if (suspend) {
251             if (!NSK_JVMTI_VERIFY(jvmti->SuspendThreadList(threadsCount, threadsList[i], results)))
252                 nsk_jvmti_setFailStatus();
253         } else {
254             if (!NSK_JVMTI_VERIFY(jvmti->ResumeThreadList(threadsCount, threadsList[i], results)))
255                 nsk_jvmti_setFailStatus();
256         }
257 
258         /* check results */
259         for (j = 0; j < threadsCount; j++) {
260             if (results[j] != JVMTI_ERROR_NONE) {
261                 NSK_COMPLAIN5("Unexpected result of %s thread #%d (%s):\n"
262                                 "#   got result: %s (%d)\n",
263                                 kind, j, threadsName[i],
264                                 TranslateError(results[j]), (int)results[j]);
265                 nsk_jvmti_setFailStatus();
266             }
267         }
268     }
269 
270     /* deallocate results array */
271     if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)results))) {
272         nsk_jvmti_setFailStatus();
273     }
274 
275     return NSK_TRUE;
276 }
277 
278 /**
279  * Suspend or resume tested threads individually.
280  */
suspendThreadsIndividually(int suspend)281 static int suspendThreadsIndividually(int suspend) {
282     int i, j;
283 
284     for (i = 0; i < THREADS_KINDS; i++) {
285         for (j = 0; j < threadsCount; j++) {
286             if (suspend) {
287                 NSK_DISPLAY2("    suspend thread #%d (%s)\n", j, threadsName[i]);
288                 if (!NSK_JVMTI_VERIFY(jvmti->SuspendThread(threadsList[i][j])))
289                     nsk_jvmti_setFailStatus();
290             } else {
291                 NSK_DISPLAY2("    resume thread #%d (%s)\n", j, threadsName[i]);
292                 if (!NSK_JVMTI_VERIFY(jvmti->ResumeThread(threadsList[i][j])))
293                     nsk_jvmti_setFailStatus();
294             }
295         }
296     }
297     return NSK_TRUE;
298 }
299 
300 /**
301  * Testcase: check tested threads
302  *    - get thread state and state flag
303  *    - wait for WAITIME if state is not expected
304  *    - check if thread state is as expected
305  *
306  * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break.
307  */
checkThreads(int suspended,const char * kind,jlong timeout)308 static int checkThreads(int suspended, const char* kind, jlong timeout) {
309     int i, j;
310 
311     /* check each thread */
312     for (i = 0; i < THREADS_KINDS; i++) {
313         for (j = 0; j < threadsCount; j++) {
314             jint state = JVMTI_THREAD_STATE_NOT_STARTED;
315             jlong t = 0;
316 
317             NSK_DISPLAY2("    thread #%d (%s):\n", j, threadsName[i]);
318 
319             /* get thread state */
320             if (!NSK_JVMTI_VERIFY(jvmti->GetThreadState(threadsList[i][j], &state))) {
321                 nsk_jvmti_setFailStatus();
322                 return NSK_FALSE;
323             }
324 
325             NSK_DISPLAY2("        state  = %s (%d)\n",
326                                         TranslateState(state), (int)state);
327 
328             /* check SUSPENDED state */
329             if (suspended) {
330                 if (!(state & JVMTI_THREAD_STATE_SUSPENDED)) {
331                     NSK_COMPLAIN5("No SUSPENDED state for %s thread #%d (%s):\n"
332                                     "#    got flags: %s (%d)\n",
333                                     kind, j, threadsName[i],
334                                     TranslateState(state), (int)state);
335                     nsk_jvmti_setFailStatus();
336                 }
337             } else {
338                 if (state & JVMTI_THREAD_STATE_SUSPENDED) {
339                     NSK_COMPLAIN5("Unexpected SUSPENDED state for %s thread #%d (%s):\n"
340                                     "#   got flags: %s (%d)\n",
341                                     kind, j, threadsName[i],
342                                     TranslateState(state), (int)state);
343                     nsk_jvmti_setFailStatus();
344                 }
345             }
346         }
347     }
348 
349     /* test may continue */
350     return NSK_TRUE;
351 }
352 
353 /**
354  * Clean data:
355  *   - dispose global references to tested threads
356  */
clean()357 static int clean() {
358     int i, j;
359 
360     /* dispose global references to threads */
361     for (i = 0; i < THREADS_KINDS; i++) {
362         for (j = 0; j < threadsCount; j++) {
363             NSK_TRACE(jni->DeleteGlobalRef(threadsList[i][j]));
364         }
365     }
366 
367     /* deallocate memory */
368     for (i = 0; i < THREADS_KINDS; i++) {
369         if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)threadsList[i])))
370             return NSK_FALSE;
371         threadsList[i] = NULL;
372     }
373 
374     return NSK_TRUE;
375 }
376 
377 /* ============================================================================= */
378 
379 static volatile int testedThreadRunning = NSK_FALSE;
380 static volatile int testedThreadShouldFinish = NSK_FALSE;
381 
382 /** Native running method in tested thread. */
383 JNIEXPORT void JNICALL
Java_nsk_jvmti_scenarios_sampling_SP03_sp03t001ThreadRunningNative_nativeMethod(JNIEnv * jni,jobject obj)384 Java_nsk_jvmti_scenarios_sampling_SP03_sp03t001ThreadRunningNative_nativeMethod(JNIEnv* jni,
385                                                                                      jobject obj) {
386     volatile int i = 0, n = 1000;
387 
388     /* run in a loop */
389     testedThreadRunning = NSK_TRUE;
390     while (!testedThreadShouldFinish) {
391         if (n <= 0)
392             n = 1000;
393         if (i >= n)
394             i = 0;
395         i++;
396     }
397     testedThreadRunning = NSK_FALSE;
398 }
399 
400 /** Wait for native method is running. */
401 JNIEXPORT jboolean JNICALL
Java_nsk_jvmti_scenarios_sampling_SP03_sp03t001ThreadRunningNative_checkReady(JNIEnv * jni,jobject obj)402 Java_nsk_jvmti_scenarios_sampling_SP03_sp03t001ThreadRunningNative_checkReady(JNIEnv* jni,
403                                                                                    jobject obj) {
404     while (!testedThreadRunning) {
405         nsk_jvmti_sleep(1000);
406     }
407     return testedThreadRunning ? JNI_TRUE : JNI_FALSE;
408 }
409 
410 /* Let native method to finish. */
411 JNIEXPORT void JNICALL
Java_nsk_jvmti_scenarios_sampling_SP03_sp03t001ThreadRunningNative_letFinish(JNIEnv * jni,jobject obj)412 Java_nsk_jvmti_scenarios_sampling_SP03_sp03t001ThreadRunningNative_letFinish(JNIEnv* jni,
413                                                                                   jobject obj) {
414     testedThreadShouldFinish = NSK_TRUE;
415 }
416 
417 /* ============================================================================= */
418 
419 /** Agent library initialization. */
420 #ifdef STATIC_BUILD
Agent_OnLoad_sp03t001(JavaVM * jvm,char * options,void * reserved)421 JNIEXPORT jint JNICALL Agent_OnLoad_sp03t001(JavaVM *jvm, char *options, void *reserved) {
422     return Agent_Initialize(jvm, options, reserved);
423 }
Agent_OnAttach_sp03t001(JavaVM * jvm,char * options,void * reserved)424 JNIEXPORT jint JNICALL Agent_OnAttach_sp03t001(JavaVM *jvm, char *options, void *reserved) {
425     return Agent_Initialize(jvm, options, reserved);
426 }
JNI_OnLoad_sp03t001(JavaVM * jvm,char * options,void * reserved)427 JNIEXPORT jint JNI_OnLoad_sp03t001(JavaVM *jvm, char *options, void *reserved) {
428     return JNI_VERSION_1_8;
429 }
430 #endif
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)431 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
432 
433     /* init framework and parse options */
434     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
435         return JNI_ERR;
436 
437     timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
438 
439     /* get number of threads for each kind */
440     threadsCount = nsk_jvmti_findOptionIntValue("threads", DEFAULT_THREADS_NUMBER);
441     if (!NSK_VERIFY(threadsCount > 0))
442         return JNI_ERR;
443 
444     /* create JVMTI environment */
445     if (!NSK_VERIFY((jvmti =
446             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
447         return JNI_ERR;
448 
449     /* add specific capabilities for suspending thread */
450     {
451         jvmtiCapabilities suspendCaps;
452         memset(&suspendCaps, 0, sizeof(suspendCaps));
453         suspendCaps.can_suspend = 1;
454         if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&suspendCaps)))
455             return JNI_ERR;
456     }
457 
458     /* register agent proc and arg */
459     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
460         return JNI_ERR;
461 
462     return JNI_OK;
463 }
464 
465 /* ============================================================================= */
466 
467 }
468