8177901: JDWP exit error JVMTI_ERROR_WRONG_PHASE(112): on checking for an interface
authorsspitsyn
Tue, 26 Sep 2017 00:52:29 -0700
changeset 47525 e05aff6beada
parent 47524 97569cf468f4
child 47526 3d7757370ef3
child 47528 9a6795c1b007
child 47566 4011de223231
8177901: JDWP exit error JVMTI_ERROR_WRONG_PHASE(112): on checking for an interface Summary: Add synchronization between CommandLoop and cbVMDeath callback Reviewed-by: dholmes, dcubed
src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c
src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c
src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c
src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.h
--- a/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c	Mon Sep 25 21:25:46 2017 -0400
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c	Tue Sep 26 00:52:29 2017 -0700
@@ -1301,6 +1301,9 @@
 {
     enum exit_codes { EXIT_NO_ERRORS = 0, EXIT_JVMTI_ERROR = 1, EXIT_TRANSPORT_ERROR = 2 };
 
+    // Release commandLoop vmDeathLock if necessary
+    commandLoop_exitVmDeathLockOnError();
+
     // Prepare to exit. Log error and finish logging
     LOG_MISC(("Exiting with error %s(%d): %s", jvmtiErrorText(error), error,
                                                ((msg == NULL) ? "" : msg)));
--- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c	Mon Sep 25 21:25:46 2017 -0400
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c	Tue Sep 26 00:52:29 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1287,11 +1287,11 @@
     } debugMonitorExit(callbackBlock);
 
     /*
-     * The VM will die soon after the completion of this callback - we
-     * may need to do a final synchronization with the command loop to
-     * avoid the VM terminating with replying to the final (resume)
-     * command.
+     * The VM will die soon after the completion of this callback -
+     * we synchronize with both the command loop and the debug loop
+     * for a more orderly shutdown.
      */
+    commandLoop_sync();
     debugLoop_sync();
 
     LOG_MISC(("END cbVMDeath"));
--- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c	Mon Sep 25 21:25:46 2017 -0400
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c	Tue Sep 26 00:52:29 2017 -0700
@@ -29,6 +29,9 @@
 #include "threadControl.h"
 #include "invoker.h"
 
+
+#define COMMAND_LOOP_THREAD_NAME "JDWP Event Helper Thread"
+
 /*
  * Event helper thread command commandKinds
  */
@@ -121,6 +124,9 @@
 static jrawMonitorID commandQueueLock;
 static jrawMonitorID commandCompleteLock;
 static jrawMonitorID blockCommandLoopLock;
+static jrawMonitorID vmDeathLock;
+static volatile jboolean commandLoopEnteredVmDeathLock = JNI_FALSE;
+
 static jint maxQueueSize = 50 * 1024; /* TO DO: Make this configurable */
 static jboolean holdEvents;
 static jint currentQueueSize = 0;
@@ -700,9 +706,15 @@
              * handleCommand() to prevent any races.
              */
             jboolean doBlock = needBlockCommandLoop(command);
-            log_debugee_location("commandLoop(): command being handled", NULL, NULL, 0);
-            handleCommand(jni_env, command);
+            debugMonitorEnter(vmDeathLock);
+            commandLoopEnteredVmDeathLock = JNI_TRUE;
+            if (!gdata->vmDead) {
+                log_debugee_location("commandLoop(): command being handled", NULL, NULL, 0);
+                handleCommand(jni_env, command);
+            }
             completeCommand(command);
+            debugMonitorExit(vmDeathLock);
+            commandLoopEnteredVmDeathLock = JNI_FALSE;
             /* if we just finished a suspend-all cmd, then we block here */
             if (doBlock) {
                 doBlockCommandLoop();
@@ -725,10 +737,11 @@
     commandQueueLock = debugMonitorCreate("JDWP Event Helper Queue Monitor");
     commandCompleteLock = debugMonitorCreate("JDWP Event Helper Completion Monitor");
     blockCommandLoopLock = debugMonitorCreate("JDWP Event Block CommandLoop Monitor");
+    vmDeathLock = debugMonitorCreate("JDWP VM_DEATH CommandLoop Monitor");
 
     /* Start the event handler thread */
     func = &commandLoop;
-    (void)spawnNewThread(func, NULL, "JDWP Event Helper Thread");
+    (void)spawnNewThread(func, NULL, COMMAND_LOOP_THREAD_NAME);
 }
 
 void
@@ -759,6 +772,42 @@
     debugMonitorExit(commandQueueLock);
 }
 
+void commandLoop_exitVmDeathLockOnError()
+{
+    const char* MSG_BASE = "exitVmDeathLockOnError: error in JVMTI %s: %d\n";
+    jthread cur_thread = NULL;
+    jvmtiThreadInfo thread_info;
+    jvmtiError err = JVMTI_ERROR_NONE;
+
+    err = JVMTI_FUNC_PTR(gdata->jvmti, GetCurrentThread)
+              (gdata->jvmti, &cur_thread);
+    if (err != JVMTI_ERROR_NONE) {
+        LOG_ERROR((MSG_BASE, "GetCurrentThread", err));
+        return;
+    }
+
+    err = JVMTI_FUNC_PTR(gdata->jvmti, GetThreadInfo)
+              (gdata->jvmti, cur_thread, &thread_info);
+    if (err != JVMTI_ERROR_NONE) {
+        LOG_ERROR((MSG_BASE, "GetThreadInfo", err));
+        return;
+    }
+    if (strcmp(thread_info.name, COMMAND_LOOP_THREAD_NAME) != 0) {
+        return;
+    }
+    if (commandLoopEnteredVmDeathLock == JNI_TRUE) {
+        debugMonitorExit(vmDeathLock);
+        commandLoopEnteredVmDeathLock = JNI_FALSE;
+    }
+}
+
+void
+commandLoop_sync(void)
+{
+    debugMonitorEnter(vmDeathLock);
+    debugMonitorExit(vmDeathLock);
+}
+
 /* Change all references to global in the EventInfo struct */
 static void
 saveEventInfoRefs(JNIEnv *env, EventInfo *evinfo)
--- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.h	Mon Sep 25 21:25:46 2017 -0400
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.h	Tue Sep 26 00:52:29 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -54,6 +54,9 @@
 void eventHelper_lock(void);
 void eventHelper_unlock(void);
 
+void commandLoop_sync(void); /* commandLoop sync with cbVMDeath */
+void commandLoop_exitVmDeathLockOnError(void);
+
 /*
  * Private interface for coordinating between eventHelper.c: commandLoop()
  * and ThreadReferenceImpl.c: resume() and VirtualMachineImpl.c: resume().