1 /* 2 * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.misc; 27 import java.util.Hashtable; 28 29 /** 30 * This class provides ANSI/ISO C signal support. A Java program can register 31 * signal handlers for the current process. There are two restrictions: 32 * <ul> 33 * <li> 34 * Java code cannot register a handler for signals that are already used 35 * by the Java VM implementation. The <code>Signal.handle</code> 36 * function raises an <code>IllegalArgumentException</code> if such an attempt 37 * is made. 38 * <li> 39 * When <code>Signal.handle</code> is called, the VM internally registers a 40 * special C signal handler. There is no way to force the Java signal handler 41 * to run synchronously before the C signal handler returns. Instead, when the 42 * VM receives a signal, the special C signal handler creates a new thread 43 * (at priority <code>Thread.MAX_PRIORITY</code>) to 44 * run the registered Java signal handler. The C signal handler immediately 45 * returns. Note that because the Java signal handler runs in a newly created 46 * thread, it may not actually be executed until some time after the C signal 47 * handler returns. 48 * </ul> 49 * <p> 50 * Signal objects are created based on their names. For example: 51 * <blockquote><pre> 52 * new Signal("INT"); 53 * </pre></blockquote> 54 * constructs a signal object corresponding to <code>SIGINT</code>, which is 55 * typically produced when the user presses <code>Ctrl-C</code> at the command line. 56 * The <code>Signal</code> constructor throws <code>IllegalArgumentException</code> 57 * when it is passed an unknown signal. 58 * <p> 59 * This is an example of how Java code handles <code>SIGINT</code>: 60 * <blockquote><pre> 61 * SignalHandler handler = new SignalHandler () { 62 * public void handle(Signal sig) { 63 * ... // handle SIGINT 64 * } 65 * }; 66 * Signal.handle(new Signal("INT"), handler); 67 * </pre></blockquote> 68 * 69 * @author Sheng Liang 70 * @author Bill Shannon 71 * @see sun.misc.SignalHandler 72 * @since 1.2 73 */ 74 public final class Signal { 75 private static Hashtable<Signal,SignalHandler> handlers = new Hashtable<>(4); 76 private static Hashtable<Integer,Signal> signals = new Hashtable<>(4); 77 78 private int number; 79 private String name; 80 81 /* Returns the signal number */ 82 public int getNumber() { 83 return number; 84 } 85 86 /** 87 * Returns the signal name. 88 * 89 * @return the name of the signal. 90 * @see sun.misc.Signal#Signal(String name) 91 */ 92 public String getName() { 93 return name; 94 } 95 96 /** 97 * Compares the equality of two <code>Signal</code> objects. 98 * 99 * @param other the object to compare with. 100 * @return whether two <code>Signal</code> objects are equal. 101 */ 102 public boolean equals(Object other) { 103 if (this == other) { 104 return true; 105 } 106 if (other == null || !(other instanceof Signal)) { 107 return false; 108 } 109 Signal other1 = (Signal)other; 110 return name.equals(other1.name) && (number == other1.number); 111 } 112 113 /** 114 * Returns a hashcode for this Signal. 115 * 116 * @return a hash code value for this object. 117 */ 118 public int hashCode() { 119 return number; 120 } 121 122 /** 123 * Returns a string representation of this signal. For example, "SIGINT" 124 * for an object constructed using <code>new Signal ("INT")</code>. 125 * 126 * @return a string representation of the signal 127 */ 128 public String toString() { 129 return "SIG" + name; 130 } 131 132 /** 133 * Constructs a signal from its name. 134 * 135 * @param name the name of the signal. 136 * @exception IllegalArgumentException unknown signal 137 * @see sun.misc.Signal#getName() 138 */ 139 public Signal(String name) { 140 number = findSignal(name); 141 this.name = name; 142 if (number < 0) { 143 throw new IllegalArgumentException("Unknown signal: " + name); 144 } 145 } 146 147 /** 148 * Registers a signal handler. 149 * 150 * @param sig a signal 151 * @param handler the handler to be registered with the given signal. 152 * @return the old handler 153 * @exception IllegalArgumentException the signal is in use by the VM 154 * @see sun.misc.Signal#raise(Signal sig) 155 * @see sun.misc.SignalHandler 156 * @see sun.misc.SignalHandler#SIG_DFL 157 * @see sun.misc.SignalHandler#SIG_IGN 158 */ 159 public static synchronized SignalHandler handle(Signal sig, 160 SignalHandler handler) 161 throws IllegalArgumentException { 162 long newH = (handler instanceof NativeSignalHandler) ? 163 ((NativeSignalHandler)handler).getHandler() : 2; 164 long oldH = handle0(sig.number, newH); 165 if (oldH == -1) { 166 throw new IllegalArgumentException 167 ("Signal already used by VM or OS: " + sig); 168 } 169 signals.put(sig.number, sig); 170 synchronized (handlers) { 171 SignalHandler oldHandler = handlers.get(sig); 172 handlers.remove(sig); 173 if (newH == 2) { 174 handlers.put(sig, handler); 175 } 176 if (oldH == 0) { 177 return SignalHandler.SIG_DFL; 178 } else if (oldH == 1) { 179 return SignalHandler.SIG_IGN; 180 } else if (oldH == 2) { 181 return oldHandler; 182 } else { 183 return new NativeSignalHandler(oldH); 184 } 185 } 186 } 187 188 /** 189 * Raises a signal in the current process. 190 * 191 * @param sig a signal 192 * @see sun.misc.Signal#handle(Signal sig, SignalHandler handler) 193 */ 194 public static void raise(Signal sig) throws IllegalArgumentException { 195 if (handlers.get(sig) == null) { 196 throw new IllegalArgumentException("Unhandled signal: " + sig); 197 } 198 raise0(sig.number); 199 } 200 201 /* Called by the VM to execute Java signal handlers. */ 202 private static void dispatch(final int number) { 203 final Signal sig = signals.get(number); 204 final SignalHandler handler = handlers.get(sig); 205 206 Runnable runnable = new Runnable () { 207 public void run() { 208 // Don't bother to reset the priority. Signal handler will 209 // run at maximum priority inherited from the VM signal 210 // dispatch thread. 211 // Thread.currentThread().setPriority(Thread.NORM_PRIORITY); 212 handler.handle(sig); 213 } 214 }; 215 if (handler != null) { 216 new ManagedLocalsThread(runnable, sig + " handler").start(); 217 } 218 } 219 220 /* Find the signal number, given a name. Returns -1 for unknown signals. */ 221 private static native int findSignal(String sigName); 222 /* Registers a native signal handler, and returns the old handler. 223 * Handler values: 224 * 0 default handler 225 * 1 ignore the signal 226 * 2 call back to Signal.dispatch 227 * other arbitrary native signal handlers 228 */ 229 private static native long handle0(int sig, long nativeH); 230 /* Raise a given signal number */ 231 private static native void raise0(int sig); 232 }