Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4860655
Votes 0
Synopsis GetCallTrace (jvmpi) returns 0 frames for threads in sleep ()
Category hotspot:jvmpi
Reported Against mantis-beta
Release Fixed
State 6-Fix Understood, bug
Priority: 4-Low
Related Bugs
Submit Date 08-MAY-2003
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) 
======================================================================
Work Around
N/A
Evaluation
 xxxxx@xxxxx  2003-05-09

A frame count of zero indicates that wait_for_ext_suspend_completion()
timed out so the GetCallTrace() bailed out early. The code path for
sleep must not be considered a suspend-equivalent condition, but
should be.

If memory serves me correctly, the code is there to support it, but
since the code was not exercised during the Merlin test cycle, it
was commented out until a proper test case could be found.

Perhaps, now we have one.
Comments
  
  Include a link with my name & email   

Submitted On 19-NOV-2003
schndt1900
This bug was reported against 1.4.2beta and I am still seeing 
it in 1.4.2_02. What is the schedule for fixing this bug ? Will 
it be fixed in 1.4.2_03 ? or 1.4.3 ?



PLEASE NOTE: JDK6 is formerly known as Project Mustang