|
Description
|
FULL PRODUCT VERSION :
java version "1.4.2-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2-beta-b19)
Java HotSpot(TM) Client VM (build 1.4.2-beta-b19, mixed mode)
FULL OS VERSION :
Debian GNU/Linux unstable
Linux grunt 2.4.20-k7 #1 Tue Jan 14 00:29:06 EST 2003 i686 unknown unknown GNU/Linux
glibc-2.2.5-11.5
A DESCRIPTION OF THE PROBLEM :
Start a java program running under a profiler,
Some of the threads in the java program has to call
Thread.sleep ().
let the profiler call GetCallTrace on each running thread.
Check how many call frames each thread got.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1.Compile the source given, both the java program and the
profiler (adjust include path to match current system).
javac JT.java
gcc -shared -o libsleep.so p.c -I /usr/local/jdk/include/ -I
/usr/local/jdk/include/linux/
2. set up LD_LIBRARY_PATH to include current directory.
for bash-like shells:
export LD_LIBRARY_PATH=.
3. run the java test case:
java -Xrunsleep JT
4: check the output, the interesting ones are the
thread_start for sleeper and waiting, find the id of thoose
threads and then the got-lines for those threads.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
That both of the stack traces should have a positive number of methods on the stack (the call frames should most probably be of equal size).
That is the output should look like:
...
thread_start (sleeper,main,system, 0x4423fcf8, 0x814a5dc)
thread_start (waiting,main,system, 0x44240e98, 0x814a894)
...
got: 3 methods for 0x814a5dc...
got: 3 methods for 0x814a894...
...
ACTUAL -
...
thread_start (sleeper,main,system, 0x4423fcf8, 0x814a5dc)
thread_start (waiting,main,system, 0x44240e98, 0x814a894)
...
got: 0 methods for 0x814a5dc...
got: 3 methods for 0x814a894...
...
The thread in sleep does not give any stack frames.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
/* begin JT.java */
public class JT {
public static void main (String[] args) {
Thread t1 = new Thread (new Runnable () {
public void run () {
try {
Thread.dumpStack ();
Thread.sleep (10 * 1000);
} catch (Exception e) {
e.printStackTrace ();
}
}
}, "sleeper");
Thread t2 = new Thread (new Runnable () {
public void run () {
try {
Thread.dumpStack ();
synchronized (this) {
wait (10 * 1000);
}
} catch (Exception e) {
e.printStackTrace ();
}
}
}, "waiting");
t1.start ();
t2.start ();
}
}
/* end JT.java */
/* ------------------------------------------------------------------*/
/* begin p.c */
#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
#include <jvmpi.h>
static JVMPI_Interface* jvmpi;
static int quit = 0;
static int num_threads = 0;
static JNIEnv* threads[50];
static void runner (void* data) {
int i;
JVMPI_CallTrace ct;
JVMPI_CallFrame* cf;
jint depth = 10;
cf = malloc (sizeof (*cf) * depth);
fprintf (stdout, "runner..\n");
while (!quit) {
fprintf (stdout, "runner loop..\n");
sleep (7);
for (i = 0; i < num_threads; i++) {
JNIEnv* t = threads[i];
jvmpi->SuspendThread (t);
ct.frames = cf;
ct.env_id = t;
jvmpi->GetCallTrace (&ct, depth);
fprintf (stdout, "got: %d methods for %p...\n",
ct.num_frames, t);
jvmpi->ResumeThread (t);
}
}
free (cf);
}
static void jvm_init_done (JNIEnv* env) {
fprintf (stdout, "jvm_init_done\n");
jvmpi->CreateSystemThread("p", JVMPI_NORMAL_PRIORITY, runner);
}
static void jvm_shut_down() {
fprintf (stdout, "jvm_init_done\n");
quit = 1;
}
static void thread_start (char* thread_name,
char* group_name,
char* parent_name,
jobjectID thread_id,
JNIEnv* env_id,
jint requested) {
fprintf (stdout, "thread_start (%s,%s,%s, %p, %p)\n", thread_name,
group_name, parent_name, thread_id, env_id);
threads[num_threads++] = env_id;
}
static void thread_end (JNIEnv* env) {
fprintf (stdout, "thread_end (%p)\n", env);
}
void notifyEvent (JVMPI_Event *e) {
switch(e->event_type) {
case JVMPI_EVENT_JVM_INIT_DONE:
jvm_init_done (e->env_id);
break;
case JVMPI_EVENT_JVM_SHUT_DOWN:
jvm_shut_down ();
break;
case JVMPI_EVENT_THREAD_START:
case JVMPI_EVENT_THREAD_START | JVMPI_REQUESTED_EVENT:
thread_start (e->u.thread_start.thread_name,
e->u.thread_start.group_name,
e->u.thread_start.parent_name,
e->u.thread_start.thread_id,
e->u.thread_start.thread_env_id,
e->event_type & JVMPI_REQUESTED_EVENT);
break;
case JVMPI_EVENT_THREAD_END:
thread_end (e->env_id);
break;
}
}
JNIEXPORT jint JNICALL JVM_OnLoad(JavaVM *jvm, char *options, void *reserved) {
fprintf (stdout, "p initializing: (%s):...\n", (options ? options : ""));
if (((*jvm)->GetEnv(jvm, (void **)&jvmpi, JVMPI_VERSION_1)) < 0)
return JNI_ERR;
jvmpi->NotifyEvent = notifyEvent;
jvmpi->EnableEvent (JVMPI_EVENT_JVM_INIT_DONE, NULL);
jvmpi->EnableEvent (JVMPI_EVENT_JVM_SHUT_DOWN, NULL);
jvmpi->EnableEvent (JVMPI_EVENT_THREAD_START, NULL);
jvmpi->EnableEvent (JVMPI_EVENT_THREAD_END, NULL);
}
/* end p.c */
/* ------------------------------------------------------------------------*/
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
when the sleeping thread leaves its current method with a
thread_exit it is possible to call GetCallFrame on it.
This mean that method profiling has to be enabled causing a
big slowdown to the program being profiled...
workaround:
(Review ID: 185274)
======================================================================
|