[NO ISSUE][HYR][*DB] Exit JVM from independent thread to avoid deadlocks

Change-Id: I21b2090ea3ef85e95ae90de04b08b4a6d22ebe42
Reviewed-on: https://asterix-gerrit.ics.uci.edu/1973
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Murtadha Hubail <mhubail@apache.org>
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/pom.xml b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/pom.xml
index b28cc79..fce37dd 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/pom.xml
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/pom.xml
@@ -43,6 +43,11 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
+      <groupId>org.apache.hyracks</groupId>
+      <artifactId>hyracks-util</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
       <groupId>io.netty</groupId>
       <artifactId>netty-all</artifactId>
     </dependency>
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java
index d32e577..a243bf8 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java
@@ -83,6 +83,7 @@
 import org.apache.hyracks.ipc.api.IIPCI;
 import org.apache.hyracks.ipc.impl.IPCSystem;
 import org.apache.hyracks.ipc.impl.JavaSerializationBasedPayloadSerializerDeserializer;
+import org.apache.hyracks.util.ExitUtil;
 import org.xml.sax.InputSource;
 
 public class ClusterControllerService implements IControllerService {
@@ -138,6 +139,10 @@
 
     private ShutdownRun shutdownCallback;
 
+    static {
+        ExitUtil.init();
+    }
+
     public ClusterControllerService(final CCConfig config) throws Exception {
         this(config, getApplication(config));
     }
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/ClusterShutdownWork.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/ClusterShutdownWork.java
index 0b89f55..613efad 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/ClusterShutdownWork.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/ClusterShutdownWork.java
@@ -30,6 +30,7 @@
 import org.apache.hyracks.control.common.work.IResultCallback;
 import org.apache.hyracks.control.common.work.SynchronizableWork;
 import org.apache.hyracks.ipc.exceptions.IPCException;
+import org.apache.hyracks.util.ExitUtil;
 
 public class ClusterShutdownWork extends SynchronizableWork {
     private static final Logger LOGGER = Logger.getLogger(ClusterShutdownWork.class.getName());
@@ -53,41 +54,36 @@
             }
             INodeManager nodeManager = ccs.getNodeManager();
             Collection<String> nodeIds = nodeManager.getAllNodeIds();
-            /**
+            /*
              * set up our listener for the node ACKs
              */
             final ShutdownRun shutdownStatus = new ShutdownRun(nodeIds);
             // set up the CC to listen for it
             ccs.setShutdownRun(shutdownStatus);
-            /**
+            /*
              * Shutdown all the nodes...
              */
             nodeManager.apply(this::shutdownNode);
 
-            ccs.getExecutor().execute(new Runnable() {
-                @Override
-                public void run() {
-                    try {
+            ccs.getExecutor().execute(() -> {
+                try {
+                    /*
+                     * wait for all our acks
+                     */
+                    LOGGER.info("Waiting for NCs to shutdown...");
+                    boolean cleanShutdown = shutdownStatus.waitForCompletion();
+                    if (!cleanShutdown) {
                         /*
-                         * wait for all our acks
+                         * best effort - just exit, user will have to kill misbehaving NCs
                          */
-                        LOGGER.info("Waiting for NCs to shutdown...");
-                        boolean cleanShutdown = shutdownStatus.waitForCompletion();
-                        if (!cleanShutdown) {
-                            /*
-                             * best effort - just exit, user will have to kill misbehaving NCs
-                             */
-                            LOGGER.severe("Clean shutdown of NCs timed out- giving up; unresponsive nodes: " +
-                                    shutdownStatus.getRemainingNodes());
-                        }
-                        callback.setValue(cleanShutdown);
-                        ccs.stop(terminateNCService);
-                        LOGGER.info("JVM Exiting.. Bye!");
-                        Runtime rt = Runtime.getRuntime();
-                        rt.exit(cleanShutdown ? 0 : 1);
-                    } catch (Exception e) {
-                        callback.setException(e);
+                        LOGGER.severe("Clean shutdown of NCs timed out- giving up; unresponsive nodes: " +
+                                shutdownStatus.getRemainingNodes());
                     }
+                    callback.setValue(cleanShutdown);
+                    ccs.stop(terminateNCService);
+                    ExitUtil.exit(cleanShutdown ? 0 : 1);
+                } catch (Exception e) {
+                    callback.setException(e);
                 }
             });
         } catch (Exception e) {