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

Reply via email to