Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-2035716 | 1.4.0 | Daniel Daugherty | P2 | Resolved | Fixed | beta |
Name: cl74495 Date: 07/26/2000
With "Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)" our
JVMPI client is seeing MONITOR_WAITED events before the thread that
owns the monitor (and did the notify) has released the monitor. This
is a change from 1.2.2.
The effect is that for our thread analysis tool, it incorrectly
reports data races and fails to report thread stalls. It also impacts
a performance monitor feature under consideration, because the timeout
send with the MONITOR_WAITED event will not accurately reflect the
amount of time the thread really spent waiting. The false-positive
data races are a serious enough problem to prevent a release of the
product that supports HotSpot.
Compile Waits.java (below), and make jvmpi_tool.dll from the C++ source
below. Run as:
java -Xrunjvmpi_tool Wait
The program will hang (this is as it should be) and the output will
look something like:
00766274: Finalizer
00766F34: Reference Handler
00762A54: main
00769594: Signal Dispatcher
00762A54: MONITOR_WAIT: object 02AA5DB8, timeout 0
0076CC24: A
0076CC24: MONITOR_WAIT: object 02AA5DB8, timeout 0
0076DF74: B
00762A54: MONITOR_WAITED: object 02AA5DB8, timeout 0
0076CC24: MONITOR_WAITED: object 02AA5DB8, timeout 0
Note that threads "A" and "main" both received MONITOR_WAITED
events, despite the fact that thread "B" is in an infinite loop
and still holds the monitor. Compare this with output from 1.2.2:
008104E0: Signal dispatcher
00810D40: Reference Handler
00811E80: Finalizer
00825B80: SymcJIT-LazyCompilation-PA
007C1170: main
007C1170: MONITOR_WAIT: object 01A75D60, timeout 0
00846890: A
00846890: MONITOR_WAIT: object 01A75D60, timeout 0
00847100: B
00825360: SymcJIT-LazyCompilation-0
Notice the MONITOR_WAITED event is never sent. And IBM's 1.3, which
uses a locking scheme similar to HotSpot gets this right as well, so
don't tell me you can't do it. :-)
-------------- Waits.java --------------
import java.lang.*;
public class Waits
{
public static NaiveBarrier barrier;
public static void main(String[] args)
{
new Waits().go();
}
public void go()
{
barrier = new NaiveBarrier(3);
new Thread(new SubThread(), "A").start();
new Thread(new SubThread(), "B").start();
barrier.reach();
}
protected static class SubThread implements Runnable
{
public void run() {
Waits.barrier.reach();
}
}
protected static class NaiveBarrier {
protected int barrierSize;
protected int waitingThreads = 0;
public NaiveBarrier (int size) {
barrierSize = size;
}
public synchronized void reach () {
try {
if (++waitingThreads == barrierSize) {
notifyAll();
// Spin forever
for (;;) {}
} else {
wait();
}
} catch (InterruptedException ie) {
} finally {
--waitingThreads;
}
}
}
}
--------------------------------------------
#include <stdio.h>
#include <jvmpi.h>
#define JVMPI(m) (jvmpi->m)
static JVMPI_Interface *jvmpi;
static void notify(JVMPI_Event *);
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_THREAD_START, NULL);
JVMPI(EnableEvent)(JVMPI_EVENT_MONITOR_WAIT, NULL);
JVMPI(EnableEvent)(JVMPI_EVENT_MONITOR_WAITED, NULL);
if (options && *options) {
int val = atoi(options);
if (val) {
delay = val;
}
}
return JNI_OK;
}
static bool inited;
void
notify(JVMPI_Event * event)
{
switch (event->event_type) {
case JVMPI_EVENT_JVM_INIT_DONE:
inited = true;
break;
case JVMPI_EVENT_THREAD_START:
printf("%p: %s\n",
event->u.thread_start.thread_env_id,
event->u.thread_start.thread_name);
break;
case JVMPI_EVENT_MONITOR_WAIT:
if (inited) {
printf("%p: MONITOR_WAIT: object %p, timeout %ld\n",
event->env_id,
event->u.monitor_wait.object,
(long) event->u.monitor_wait.timeout);
}
break;
case JVMPI_EVENT_MONITOR_WAITED:
if (inited) {
printf("%p: MONITOR_WAITED: object %p, timeout %ld\n",
event->env_id,
event->u.monitor_wait.object,
(long) event->u.monitor_wait.timeout);
}
break;
default:
break;
}
}
-------------- jvmpi_tool.cpp --------------
(Review ID: 107439)
======================================================================
- backported by
-
JDK-2035716 JVMPI_EVENT_MONITOR_WAITED sent before wait is actually complete
-
- Resolved
-