Name: krT82822 Date: 02/09/2000
java version "1.3.0rc1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0rc1-T)
Java HotSpot(TM) Client VM (build 1.3.0rc1-S, mixed mode)
We have a thread analysis tool that does deadlock detection by regularly
asking for MONITOR_DUMP events and looking for cycles. With HotSpot RC1,
the MONITOR_DUMP on a deadlocked Java program does not show the cycle, and
in the test case below shows no threads even waiting to enter monitors.
Below are the output from running "java -Xrunjvmpi_tool Deadlock", and the
source for Deadlock.java and a pared-down JVMPI DLL called jvmpi_tool.
TEST OUTPUT: note no threads are waiting to enter any of the monitors, and
none of the monitors are owned:
Start 0x766214: "Finalizer"
Start 0x766ed4: "Reference Handler"
Start 0x762a34: "main"
Start 0x768074: "Monitor dumper"
Start 0x76aa84: "Signal Dispatcher"
Start 0x76eac4: "Thread-0"
Start 0x76dad4: "One"
Thread One: lockA
Start 0x76d4c4: "Two"
Thread Two: lockB
Monitor Dump:
Monitor 0x6b28578: Owner: 0 Entry count: 0
0 waiting to enter
0 awaiting notification
Monitor 0x6b285a8: Owner: 0 Entry count: 0
0 waiting to enter
0 awaiting notification
Monitor 0x2aa4a98: Owner: 0 Entry count: 0
0 waiting to enter
0 awaiting notification
Monitor 0x2a883c0: Owner: 0 Entry count: 0
0 waiting to enter
0 awaiting notification
Monitor 0x2a70328: Owner: 0 Entry count: 0
0 waiting to enter
1 awaiting notification
0x766214
Monitor 0x2a70238: Owner: 0 Entry count: 0
0 waiting to enter
1 awaiting notification
0x766ed4
SOURCE FOR Deadlock.java: Always deadlocks:
import java.lang.*;
public class Deadlock
{
private static String lockA = "lockA";
private static String lockB = "lockB";
static Object barrier = new Object();
static int count = 0;
public static void main(String[] args) {
new Thread (new DeadThread(lockA, lockB), "One").start();
new Thread (new DeadThread(lockB, lockA), "Two").start();
}
protected static class DeadThread implements Runnable {
String first_;
String second_;
public DeadThread(String first, String second) {
first_ = first;
second_ = second;
}
public void run () {
String name = Thread.currentThread().getName();
synchronized (first_) {
System.out.println("Thread " + name + ": " + fir
st_);
synchronized (Deadlock.barrier) {
if (Deadlock.count++ > 0) {
Deadlock.barrier.notify();
} else {
try {
Deadlock.barrier.wait();
} catch (Exception e) {}
}
}
synchronized (second_) {
System.out.println("Impossible: Thread "
+ name + ": " + first_);
}
}
}
}
}
SOURCE FOR jvmpi_tool: NOTE: Only tested on WinNT, but might happen to work on
Solaris. I know it's not pretty.
//
// Get a monitor dump from JVMPI
//
#include <stdio.h>
#include <jvmpi.h>
#ifdef _WINDOWS
# include <windows.h>
# define SLEEP(s) Sleep(s * 1000);
#else
# define SLEEP(s) sleep(s);
#endif
#define JVMPI(m) (jvmpi->m)
static JVMPI_Interface *jvmpi;
static int delay = 5;
static volatile int done = 0;
static int little_endian = 0;
static long u4(void *);
static void monitor(void *);
static void notify(JVMPI_Event *);
static void dump(char * begin, char * end);
extern "C" JNIEXPORT jint JNICALL
JVM_OnLoad(JavaVM *jvm, char *options, void *reserved)
{
int res = jvm->GetEnv((void **)&jvmpi, JVMPI_VERSION_1);
if (res < 0) {
return JNI_ERR;
}
jvmpi->NotifyEvent = notify;
JVMPI(EnableEvent)(JVMPI_EVENT_JVM_INIT_DONE, NULL);
JVMPI(EnableEvent)(JVMPI_EVENT_JVM_SHUT_DOWN, NULL);
JVMPI(EnableEvent)(JVMPI_EVENT_THREAD_START, NULL);
if (options && *options) {
int val = atoi(options);
if (val) {
delay = val;
}
}
int test = 1;
if (*(unsigned char *)&test) {
little_endian = 1;
}
return JNI_OK;
}
long
u4(void * buf)
{
long result;
unsigned char * p = (unsigned char *)buf;
if (little_endian) {
result = p[3] | (p[2] << 8) | (p[1] << 16) | (p[0] << 24);
} else {
result = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}
return result;
}
void
monitor(void * notused)
{
do {
SLEEP(delay);
if (!done) {
JVMPI(RequestEvent)(JVMPI_EVENT_MONITOR_DUMP, NULL);
}
} while (!done);
done = 0;
}
void
notify(JVMPI_Event * event)
{
jint result;
char * name;
switch (event->event_type) {
case JVMPI_EVENT_JVM_INIT_DONE:
result = JVMPI(CreateSystemThread)("Monitor dumper",
JVMPI_NORMAL_PRIORITY, monitor);
if (result != JNI_OK) {
fputs("Unable to create Monitor dumper thread\n",
stderr);
exit(1);
}
break;
case JVMPI_EVENT_JVM_SHUT_DOWN:
done = 1;
while (done) {
SLEEP(1);
}
break;
case JVMPI_EVENT_THREAD_START:
name = event->u.thread_start.thread_name;
printf("Start %#lx: \"%s\"\n",
(unsigned long)event->u.thread_start.thread_env_id,
name ? name : "(null)");
break;
case JVMPI_REQUESTED_EVENT|JVMPI_EVENT_MONITOR_DUMP:
dump(event->u.monitor_dump.begin, event->u.monitor_dump.end);
break;
}
}
#define DUMP_U1(v, ptr) v = (*ptr++)
#define DUMP_U4(v, ptr) v = u4(ptr); ptr += 4
#define DUMP_ID(v, ptr) memcpy(&v, ptr, sizeof(v)); ptr += sizeof(v)
void
dump(char * begin, char * end)
{
fputs("\nMonitor Dump:\n", stdout);
while (begin < end) {
char type;
void * id;
jint num;
jint i;
DUMP_U1(type, begin);
if (type == JVMPI_MONITOR_JAVA) {
DUMP_ID(id, begin);
printf("Monitor %#lx: ", (unsigned long)id);
} else if (type == JVMPI_MONITOR_RAW) {
DUMP_ID(id, begin);
printf("Raw Monitor \"%s\" ", id ? (char *)id :
"(null)");
DUMP_ID(id, begin);
printf("%#lx: ", (unsigned long)id);
} else {
printf("Unknown monitor type: %d\n", (int)type);
return;
}
DUMP_ID(id, begin);
printf("Owner: %#lx ", (unsigned long)id);
DUMP_U4(num, begin);
printf("Entry count: %ld\n", num);
DUMP_U4(num, begin);
printf(" %ld waiting to enter\n", num);
for (i = 0; i < num; ++i) {
DUMP_ID(id, begin);
printf(" %#lx\n", (unsigned long)id);
}
DUMP_U4(num, begin);
printf(" %ld awaiting notification\n", num);
for (i = 0; i < num; ++i) {
DUMP_ID(id, begin);
printf(" %#lx\n", (unsigned long)id);
}
}
}
(Review ID: 101035)
======================================================================
Name: elR10090 Date: 05/19/2001
This bug also affects the testbase_nsk test:
nsk/regression/b4311308
======================================================================
- relates to
-
JDK-4418568 NULL thread ID in MONITOR_DUMP
- Resolved
-
JDK-4318756 assert(owner() == Thread::current(), "recursive unlocking but wrong owner
- Closed
-
JDK-4318764 test reqevent010 causes java crash
- Closed
-
JDK-4329157 MONITOR_DUMP event info contains incorrect items
- Closed