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 jdk.internal.misc.NativeSignal; 28 29 import java.util.Map; 30 import java.util.concurrent.ConcurrentHashMap; 31 import java.util.function.Consumer; 32 33 /** 34 * This class provides ANSI/ISO C signal support. A Java program can register 35 * signal handlers for the current process. There are two restrictions: 36 * <ul> 37 * <li> 38 * Java code cannot register a handler for signals that are already used 39 * by the Java VM implementation. The <code>Signal.handle</code> 40 * function raises an <code>IllegalArgumentException</code> if such an attempt 41 * is made. 42 * <li> 43 * When <code>Signal.handle</code> is called, the VM internally registers a 44 * special C signal handler. There is no way to force the Java signal handler 45 * to run synchronously before the C signal handler returns. Instead, when the 46 * VM receives a signal, the special C signal handler creates a new thread 47 * (at priority <code>Thread.MAX_PRIORITY</code>) to 48 * run the registered Java signal handler. The C signal handler immediately 49 * returns. Note that because the Java signal handler runs in a newly created 50 * thread, it may not actually be executed until some time after the C signal 51 * handler returns. 52 * </ul> 53 * <p> 54 * Signal objects are created based on their names. For example: 55 * <blockquote><pre> 56 * new Signal("INT"); 57 * </pre></blockquote> 58 * constructs a signal object corresponding to <code>SIGINT</code>, which is 59 * typically produced when the user presses <code>Ctrl-C</code> at the command line. 60 * The <code>Signal</code> constructor throws <code>IllegalArgumentException</code> 61 * when it is passed an unknown signal. 62 * <p> 63 * This is an example of how Java code handles <code>SIGINT</code>: 64 * <blockquote><pre> 65 * SignalHandler handler = new SignalHandler () { 66 * public void handle(Signal sig) { 67 * ... // handle SIGINT 68 * } 69 * }; 70 * Signal.handle(new Signal("INT"), handler); 71 * </pre></blockquote> 72 * 73 * @author Sheng Liang 74 * @author Bill Shannon 75 * @see sun.misc.SignalHandler 76 * @since 1.2 77 */ 78 public final class Signal { 79 80 private static final Map<Integer, UtHandler> handlers = new ConcurrentHashMap<>(4); 81 82 private final java.util.Signal utSignal; 83 84 /* Returns the signal number */ 85 public int getNumber() { 86 return utSignal.number(); 87 } 88 89 /** 90 * Returns the signal name. 91 * 92 * @return the name of the signal. 93 * @see sun.misc.Signal#Signal(String name) 94 */ 95 public String getName() { 96 return utSignal.name(); 97 } 98 99 /** 100 * Compares the equality of two <code>Signal</code> objects. 101 * 102 * @param other the object to compare with. 103 * @return whether two <code>Signal</code> objects are equal. 104 */ 105 public boolean equals(Object other) { 106 if (this == other) { 107 return true; 108 } 109 if (other == null || !(other instanceof Signal)) { 110 return false; 111 } 112 return utSignal == ((Signal) other).utSignal; 113 } 114 115 /** 116 * Returns a hashcode for this Signal. 117 * 118 * @return a hash code value for this object. 119 */ 120 public int hashCode() { 121 return getNumber(); 122 } 123 124 /** 125 * Returns a string representation of this signal. For example, "SIGINT" 126 * for an object constructed using <code>new Signal ("INT")</code>. 127 * 128 * @return a string representation of the signal 129 */ 130 public String toString() { 131 return getName(); 132 } 133 134 /** 135 * Constructs a signal from its name. 136 * 137 * @param name the name of the signal. 138 * @exception IllegalArgumentException unknown signal 139 * @see sun.misc.Signal#getName() 140 */ 141 public Signal(String name) { 142 this(java.util.Signal.of("SIG" + name)); 143 } 144 145 private Signal(java.util.Signal utSignal) { 146 this.utSignal = utSignal; 147 } 148 149 /** 150 * Registers a signal handler. 151 * 152 * @param sig a signal 153 * @param handler the handler to be registered with the given signal. 154 * @return the old handler 155 * @exception IllegalArgumentException the signal is in use by the VM 156 * @see sun.misc.Signal#raise(Signal sig) 157 * @see sun.misc.SignalHandler 158 * @see sun.misc.SignalHandler#SIG_DFL 159 * @see sun.misc.SignalHandler#SIG_IGN 160 */ 161 public static synchronized SignalHandler handle(Signal sig, 162 SignalHandler handler) 163 throws IllegalArgumentException { 164 165 UtHandler newUtHandler = handler == null ? null : UtHandler.create(handler); 166 UtHandler oldUtHandler = newUtHandler == null 167 ? handlers.remove(sig.getNumber()) 168 : handlers.put(sig.getNumber(), newUtHandler); 169 170 if (oldUtHandler != null) { 171 if (!oldUtHandler.unregisterFrom(sig.utSignal)) { 172 throw new IllegalStateException( 173 "Can't unregister old sun.misc.SignalHandler as some new " + 174 "handler has been registered with java.util.Signal API."); 175 } 176 } 177 178 if (newUtHandler != null) { 179 newUtHandler.registerTo(sig.utSignal); 180 } 181 182 return oldUtHandler == null ? null : oldUtHandler.signalHandler; 183 } 184 185 /** 186 * Raises a signal in the current process. 187 * 188 * @param sig a signal 189 * @see sun.misc.Signal#handle(Signal sig, SignalHandler handler) 190 */ 191 public static void raise(Signal sig) throws IllegalArgumentException { 192 if (handlers.get(sig.getNumber()) == null) { 193 throw new IllegalArgumentException("Unhandled signal: " + sig); 194 } 195 sig.utSignal.raise(); 196 } 197 198 // abstraction of Java and Native handlers for java.util.Signal API 199 // with delegation to sun.misc.[SignalHandler|NativeSignalHandler] 200 private static abstract class UtHandler { 201 final SignalHandler signalHandler; 202 203 static UtHandler create(SignalHandler signalHandler) { 204 return (signalHandler instanceof NativeSignalHandler) 205 ? new UtHandler.Native((NativeSignalHandler) signalHandler) 206 : new UtHandler.Java(signalHandler); 207 } 208 209 UtHandler(SignalHandler signalHandler) { 210 this.signalHandler = signalHandler; 211 } 212 213 abstract void registerTo(java.util.Signal utSignal); 214 215 abstract boolean unregisterFrom(java.util.Signal utSignal); 216 217 private static class Java extends UtHandler 218 implements Consumer<java.util.Signal> { 219 Java(SignalHandler signalHandler) { 220 super(signalHandler); 221 } 222 223 @Override 224 public void accept(java.util.Signal uSignal) { 225 signalHandler.handle(new Signal(uSignal)); 226 } 227 228 @Override 229 void registerTo(java.util.Signal utSignal) { 230 utSignal.register(this); 231 } 232 233 @Override 234 boolean unregisterFrom(java.util.Signal utSignal) { 235 return utSignal.unregister(this); 236 } 237 } 238 239 private static class Native extends UtHandler { 240 Native(NativeSignalHandler signalHandler) { 241 super(signalHandler); 242 } 243 244 @Override 245 void registerTo(java.util.Signal utSignal) { 246 ((NativeSignal) utSignal).register( 247 ((NativeSignalHandler) signalHandler).getHandler() 248 ); 249 } 250 251 @Override 252 boolean unregisterFrom(java.util.Signal utSignal) { 253 return ((NativeSignal) utSignal).unregister( 254 ((NativeSignalHandler) signalHandler).getHandler() 255 ); 256 } 257 } 258 } 259 }