1/* 2 * Copyright (c) 1998, 2016, 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 26package jdk.internal.misc; 27 28import java.util.Hashtable; 29import java.util.Objects; 30 31/** 32 * This class provides ANSI/ISO C signal support. A Java program can register 33 * signal handlers for the current process. There are two restrictions: 34 * <ul> 35 * <li> 36 * Java code cannot register a handler for signals that are already used 37 * by the Java VM implementation. The <code>Signal.handle</code> 38 * function raises an <code>IllegalArgumentException</code> if such an attempt 39 * is made. 40 * <li> 41 * When <code>Signal.handle</code> is called, the VM internally registers a 42 * special C signal handler. There is no way to force the Java signal handler 43 * to run synchronously before the C signal handler returns. Instead, when the 44 * VM receives a signal, the special C signal handler creates a new thread 45 * (at priority <code>Thread.MAX_PRIORITY</code>) to 46 * run the registered Java signal handler. The C signal handler immediately 47 * returns. Note that because the Java signal handler runs in a newly created 48 * thread, it may not actually be executed until some time after the C signal 49 * handler returns. 50 * </ul> 51 * <p> 52 * Signal objects are created based on their names. For example: 53 * <blockquote><pre> 54 * new Signal("INT"); 55 * </pre></blockquote> 56 * constructs a signal object corresponding to <code>SIGINT</code>, which is 57 * typically produced when the user presses <code>Ctrl-C</code> at the command line. 58 * The <code>Signal</code> constructor throws <code>IllegalArgumentException</code> 59 * when it is passed an unknown signal. 60 * <p> 61 * This is an example of how Java code handles <code>SIGINT</code>: 62 * <blockquote><pre> 63 * Signal.Handler handler = new Signal.Handler () { 64 * public void handle(Signal sig) { 65 * ... // handle SIGINT 66 * } 67 * }; 68 * Signal.handle(new Signal("INT"), handler); 69 * </pre></blockquote> 70 * 71 * @since 9 72 */ 73public final class Signal { 74 private static Hashtable<Signal, Signal.Handler> handlers = new Hashtable<>(4); 75 private static Hashtable<Integer, Signal> signals = new Hashtable<>(4); 76 77 private int number; 78 private String name; 79 80 /* Returns the signal number */ 81 public int getNumber() { 82 return number; 83 } 84 85 /** 86 * Returns the signal name. 87 * 88 * @return the name of the signal. 89 * @see jdk.internal.misc.Signal#Signal(String name) 90 */ 91 public String getName() { 92 return name; 93 } 94 95 /** 96 * Compares the equality of two <code>Signal</code> objects. 97 * 98 * @param other the object to compare with. 99 * @return whether two <code>Signal</code> objects are equal. 100 */ 101 public boolean equals(Object other) { 102 if (this == other) { 103 return true; 104 } 105 if (other == null || !(other instanceof Signal)) { 106 return false; 107 } 108 Signal other1 = (Signal)other; 109 return name.equals(other1.name) && (number == other1.number); 110 } 111 112 /** 113 * Returns a hashcode for this Signal. 114 * 115 * @return a hash code value for this object. 116 */ 117 public int hashCode() { 118 return number; 119 } 120 121 /** 122 * Returns a string representation of this signal. For example, "SIGINT" 123 * for an object constructed using <code>new Signal ("INT")</code>. 124 * 125 * @return a string representation of the signal 126 */ 127 public String toString() { 128 return "SIG" + name; 129 } 130 131 /** 132 * Constructs a signal from its name. 133 * 134 * @param name the name of the signal. 135 * @exception IllegalArgumentException unknown signal 136 * @see jdk.internal.misc.Signal#getName() 137 */ 138 public Signal(String name) { 139 Objects.requireNonNull(name, "name"); 140 // Signal names are the short names; 141 // the "SIG" prefix is not used for compatibility with previous JDKs 142 if (name.startsWith("SIG")) { 143 throw new IllegalArgumentException("Unknown signal: " + name); 144 } 145 this.name = name; 146 number = findSignal0(name); 147 if (number < 0) { 148 throw new IllegalArgumentException("Unknown signal: " + name); 149 } 150 } 151 152 /** 153 * Registers a signal handler. 154 * 155 * @param sig a signal 156 * @param handler the handler to be registered with the given signal. 157 * @return the old handler 158 * @exception IllegalArgumentException the signal is in use by the VM 159 * @see jdk.internal.misc.Signal#raise(Signal sig) 160 * @see jdk.internal.misc.Signal.Handler 161 * @see jdk.internal.misc.Signal.Handler#SIG_DFL 162 * @see jdk.internal.misc.Signal.Handler#SIG_IGN 163 */ 164 public static synchronized Signal.Handler handle(Signal sig, 165 Signal.Handler handler) 166 throws IllegalArgumentException { 167 Objects.requireNonNull(sig, "sig"); 168 Objects.requireNonNull(handler, "handler"); 169 long newH = (handler instanceof NativeHandler) ? 170 ((NativeHandler)handler).getHandler() : 2; 171 long oldH = handle0(sig.number, newH); 172 if (oldH == -1) { 173 throw new IllegalArgumentException 174 ("Signal already used by VM or OS: " + sig); 175 } 176 signals.put(sig.number, sig); 177 synchronized (handlers) { 178 Signal.Handler oldHandler = handlers.get(sig); 179 handlers.remove(sig); 180 if (newH == 2) { 181 handlers.put(sig, handler); 182 } 183 if (oldH == 0) { 184 return Signal.Handler.SIG_DFL; 185 } else if (oldH == 1) { 186 return Signal.Handler.SIG_IGN; 187 } else if (oldH == 2) { 188 return oldHandler; 189 } else { 190 return new NativeHandler(oldH); 191 } 192 } 193 } 194 195 /** 196 * Raises a signal in the current process. 197 * 198 * @param sig a signal 199 * @see jdk.internal.misc.Signal#handle(Signal sig, Signal.Handler handler) 200 */ 201 public static void raise(Signal sig) throws IllegalArgumentException { 202 Objects.requireNonNull(sig, "sig"); 203 if (handlers.get(sig) == null) { 204 throw new IllegalArgumentException("Unhandled signal: " + sig); 205 } 206 raise0(sig.number); 207 } 208 209 /* Called by the VM to execute Java signal handlers. */ 210 private static void dispatch(final int number) { 211 final Signal sig = signals.get(number); 212 final Signal.Handler handler = handlers.get(sig); 213 214 Runnable runnable = new Runnable () { 215 public void run() { 216 // Don't bother to reset the priority. Signal handler will 217 // run at maximum priority inherited from the VM signal 218 // dispatch thread. 219 // Thread.currentThread().setPriority(Thread.NORM_PRIORITY); 220 handler.handle(sig); 221 } 222 }; 223 if (handler != null) { 224 new Thread(null, runnable, sig + " handler", 0, false).start(); 225 } 226 } 227 228 /* Find the signal number, given a name. Returns -1 for unknown signals. */ 229 private static native int findSignal0(String sigName); 230 /* Registers a native signal handler, and returns the old handler. 231 * Handler values: 232 * 0 default handler 233 * 1 ignore the signal 234 * 2 call back to Signal.dispatch 235 * other arbitrary native signal handlers 236 */ 237 private static native long handle0(int sig, long nativeH); 238 /* Raise a given signal number */ 239 private static native void raise0(int sig); 240 241 /** 242 * This is the signal handler interface expected in <code>Signal.handle</code>. 243 */ 244 public interface Handler { 245 246 /** 247 * The default signal handler 248 */ 249 public static final Signal.Handler SIG_DFL = new NativeHandler(0); 250 /** 251 * Ignore the signal 252 */ 253 public static final Signal.Handler SIG_IGN = new NativeHandler(1); 254 255 /** 256 * Handle the given signal 257 * 258 * @param sig a signal object 259 */ 260 public void handle(Signal sig); 261 } 262 263 264 /* 265 * A package-private class implementing a signal handler in native code. 266 */ 267 static final class NativeHandler implements Signal.Handler { 268 269 private final long handler; 270 271 long getHandler() { 272 return handler; 273 } 274 275 NativeHandler(long handler) { 276 this.handler = handler; 277 } 278 279 public void handle(Signal sig) { 280 throw new UnsupportedOperationException("invoking native signal handle not supported"); 281 } 282 283 public String toString() { 284 return this == SIG_DFL ? "SIG_DFL" : 285 (this == SIG_IGN ? "SIG_IGN" : super.toString()); 286 } 287 } 288 289} 290