001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.apache.hadoop.util;
019
020 import org.apache.commons.logging.Log;
021 import org.apache.commons.logging.LogFactory;
022 import org.apache.hadoop.classification.InterfaceAudience;
023 import org.apache.hadoop.classification.InterfaceStability;
024
025 /**
026 * Facilitates hooking process termination for tests and debugging.
027 */
028 @InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
029 @InterfaceStability.Unstable
030 public final class ExitUtil {
031 private final static Log LOG = LogFactory.getLog(ExitUtil.class.getName());
032 private static volatile boolean systemExitDisabled = false;
033 private static volatile boolean terminateCalled = false;
034
035 public static class ExitException extends RuntimeException {
036 private static final long serialVersionUID = 1L;
037 public final int status;
038
039 public ExitException(int status, String msg) {
040 super(msg);
041 this.status = status;
042 }
043 }
044
045 /**
046 * Disable the use of System.exit for testing.
047 */
048 public static void disableSystemExit() {
049 systemExitDisabled = true;
050 }
051
052 /**
053 * @return true if terminate has been called
054 */
055 public static boolean terminateCalled() {
056 return terminateCalled;
057 }
058
059 /**
060 * Terminate the current process. Note that terminate is the *only* method
061 * that should be used to terminate the daemon processes.
062 * @param status exit code
063 * @param msg message used to create the ExitException
064 * @throws ExitException if System.exit is disabled for test purposes
065 */
066 public static void terminate(int status, String msg) throws ExitException {
067 LOG.info("Exiting with status " + status);
068 terminateCalled = true;
069 if (systemExitDisabled) {
070 throw new ExitException(status, msg);
071 }
072 System.exit(status);
073 }
074
075 /**
076 * Like {@link terminate(int, String)} without a message.
077 * @param status
078 * @throws ExitException
079 */
080 public static void terminate(int status) throws ExitException {
081 terminate(status, "ExitException");
082 }
083 }