When does MONITOR_WAITED get thrown?

David Holmes david.holmes at oracle.com
Mon Sep 18 22:04:31 UTC 2017


Hi Jc,

I found  your example very difficult to follow. AFAICS you will 
potentially encounter monitor related events that are unrelated to the 
st.wait in your test code. And there are races in the test - as soon as 
st.wait releases the monitor lock then SecondThread can run, complete 
the sleep and print "Hello from A". I don't think it is specified 
exactly when the MONIOR_WAIT event is sent with respect to the releasing 
of the monitor lock.

David

On 19/09/2017 3:45 AM, JC Beyler wrote:
> Hi all,
> 
> When looking at the documentation of
> https://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html#MonitorWaited 
> , I see the following description:
> "Sent when a thread finishes waiting on an object."
> 
> However, there seems to be a slight issue when the MONITOR_WAIT event 
> handler throws an exception.
> 
> Consider the following code:
> 
> A) The monitor wait handler throws
> 
> static void JNICALL
> monitor_wait(jvmtiEnv* jvmti, JNIEnv *env,
>               jthread thread, jobject object, jlong timeout) {
>    fprintf(stderr, "Waiting!\n");
> 
>    jclass newExcCls = env->FindClass("java/lang/IllegalArgumentException");
>    // Unable to find the new exception class, give up.
>    if (newExcCls == 0) {
>      return;
>    }
>    env->ThrowNew(newExcCls, "Exception from monitor_wait");
> }
> 
> B) The monitor waited handler does a printf:
> static void JNICALL
> monitor_waited(jvmtiEnv* jvmti, JNIEnv *env,
>                 jthread thread, jobject object, jboolean timed_out) {
>    fprintf(stderr, "Waited!\n");
> }
> 
> B) A second thread that will be asked to wait:
>   class SecondThread extends Thread {
>    public void run() {
>      try {
>        Thread.sleep(1);
>      } catch(Exception e) {
>      }
>      System.out.println("Hello from A");
>    }
> }
> 
> C) The main thread with the wait:
> class Main extends Thread {
>    public static void main(String[] args) {
>      SecondThread st = new SecondThread();
> 
>      synchronized (st) {
>        st.start();
> 
>        try {
>          st.wait();
>        } catch(InterruptedException e) {
>          System.out.println("Exception caught!");
>        }
>      }
> 
>      System.out.println("Done");
>    }
> }
> 
> D) If I do this, what happens is that I get:
> 
> Waiting!
> Waited!
> Exception in thread "main" java.lang.IllegalArgumentException: Exception 
> from monitor_wait
> at java.lang.Object.wait(Native Method)
> at java.lang.Object.wait(Object.java:502)
> at Main.main(Main.java:9)
> Hello from A
> 
> - As we see, we get the print out from waiting, print out from waited 
> and then the exception in the waiting.
> 
> 
> E) If instead, we do st.wait(-100) in the main method, we get:
> Waiting!
> Exception in thread "main" java.lang.IllegalArgumentException: Exception 
> from monitor_wait
> at java.lang.Object.wait(Native Method)
> at Main.main(Main.java:9)
> Hello from A
> 
> Notes: the stack is slightly different, the printout waited is no longer 
> there however
> 
> F) If finally, we don't throw in the waiting handler but leave the 
> st.wait(-100) in place:
> Waiting!
> Exception in thread "main" java.lang.IllegalArgumentException: timeout 
> value is negative
> at java.lang.Object.wait(Native Method)
> at Main.main(Main.java:9)
> Hello from A
> 
> 
> The question thus becomes: is this normal that there is a slight 
> difference between D/E/F?
> 
> Should we try to fix it to have a single behavior in the three cases, 
> and if so, which would be the behavior that should be the default?
> 
> Let me know if you would like to see a full code to easily replicate, I 
> gave the big parts but left out the Agent_OnLoad method for example.
> 
> Thanks!
> Jc
> 


More information about the serviceability-dev mailing list