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 package java.util; 26 27 import jdk.internal.misc.NativeSignal; 28 import sun.misc.InnocuousThread; 29 30 import java.util.concurrent.ConcurrentHashMap; 31 import java.util.concurrent.ConcurrentMap; 32 import java.util.function.BiConsumer; 33 import java.util.function.Consumer; 34 import java.util.function.Function; 35 36 /** 37 * Signal provides support for responding to and raising platform signals. 38 * Each signal has a current signal handler. 39 * The signals supported are implementation and operating system specific. 40 * <p> 41 * {@link Signal#register(BiConsumer) Registering} a handler replaces the 42 * current handler with the provided handler. Provided handler receives, when 43 * invoked, a {@code Signal} instance being handler and a {@code Runnable} object 44 * representing the replaced handler, which may be invoked to chain the handling 45 * of the signal. 46 * {@link Signal#unregister(BiConsumer) Unregistering} a handler restores the 47 * signal handling to the state before registering the handler. 48 * The signal handler is initially registered for the signals 49 * {@code SIGINT}, {@code SIGTERM}, and {@code SIGHUP}. 50 * The system registered handler terminates the Java Runtime 51 * by invoking {@link System#exit System.exit} with a 52 * value of {@code 128 + the signal number}. Other signals are ignored. 53 * Handlers for signals that are unknown or reserved by the 54 * Java implementation can not be registered. 55 * <p> 56 * Handling and raising signals are sensitive operations. Access to 57 * Signal instances is restricted via {@code RuntimePermission("handleSignal")} 58 * if a SecurityManager is installed. 59 * <p> 60 * Common signal names that follow ANSI/ISO C conventions include: 61 * <ul> 62 * <li>SIGINT - Interrupt as if the user typed {@code Ctrl-C} 63 * <li>SIGTERM - A request for normal termination 64 * <li>SIGHUP - The process is no longer connected to a controlling terminal 65 * </ul> 66 * <p> 67 * Signal objects are created based on their names. For example: 68 * <blockquote>{@code 69 * Signal s = Signal.of("SIGINT"); 70 * }</blockquote> 71 * constructs a Signal for {@code SIGINT}, which is 72 * typically produced when the user presses {@code Ctrl-C}. 73 * <p> 74 * To handle a signal a handler is registered for the Signal. 75 * For example, to respond to {@code Ctrl-C}: 76 * <pre>{@code 77 * BiConsumer<Signal, Runnable> handler = (s, r) -> { 78 * ... // handle SIGINT 79 * ... // may invoke r.run() as part to chain previous handler 80 * }; 81 * Signal.of("SIGINT").register(handler); 82 * }</pre> 83 * <p> 84 * Signal is a <a href="{@docRoot}/java/lang/doc-files/ValueBased.html">value-based</a> 85 * class; use of identity-sensitive operations (including reference equality 86 * ({@code ==}), identity hash code, or synchronization) on instances of 87 * {@code Signal} may have unpredictable results and should be avoided. 88 * The {@code equals} method should be used for comparisons. 89 * <p> 90 * Unless otherwise noted, passing a {@code null} argument to any method in this 91 * class causes a {@link java.lang.NullPointerException NullPointerException} 92 * to be thrown. 93 * <p> 94 * 95 * 96 * @implNote Signal handling is asynchronous to the native signal mechanisms. 97 * The implementation handles the native signal and signals a Java Thread to 98 * deliver the signal to the registered handler. 99 * Since the Java signal handler runs in a newly created thread, it may not be 100 * executed until some time after the native signal handler returns. 101 * 102 * @since 9 103 */ 104 public class Signal { 105 106 /** 107 * Returns the named Signal. 108 * 109 * @param name the name of the signal 110 * @return the named Signal 111 * @throws UnsupportedOperationException if the signal is unknown or reserved 112 * @throws SecurityException if a SecurityManager is installed and 113 * the {@code RuntimePermission("handleSignal")} is denied 114 */ 115 public static Signal of(String name) { 116 Signal signal = SIGNAL_BY_NAME.get(name); 117 if (signal != null) { 118 return signal; 119 } 120 121 int number; 122 if (!name.startsWith("SIG") || name.length() <= 3 || 123 (number = findSignal0(name.substring(3))) < 0) { 124 throw new UnsupportedOperationException("Unknown signal: " + name); 125 } 126 127 signal = SIGNAL_BY_NUMBER.computeIfAbsent( 128 number, 129 new Function<Integer, Signal>() { 130 @Override 131 public Signal apply(Integer number) { 132 return new Signal.NativeImpl(name, number); 133 } 134 } 135 ); 136 137 SIGNAL_BY_NAME.putIfAbsent(name, signal); 138 139 return signal; 140 } 141 142 private static final ConcurrentMap<String, Signal> SIGNAL_BY_NAME = new ConcurrentHashMap<>(4); 143 private static final ConcurrentMap<Integer, Signal> SIGNAL_BY_NUMBER = new ConcurrentHashMap<>(4); 144 145 private final String name; 146 private final int number; 147 volatile HandlerChain handlerChain; 148 long savedNativeHandler; 149 150 Signal(String name, int number) { 151 this.name = name; 152 this.number = number; 153 } 154 155 /** 156 * Returns the signal name. 157 * Signal names are implementation specific. 158 * 159 * @return the signal name 160 */ 161 public String name() { return name; } 162 163 /** 164 * Returns the signal number. 165 * Signal numbers are implementation specific. 166 * 167 * @return the signal number 168 */ 169 public int number() { return number; } 170 171 /** 172 * Raises the signal in the current process. 173 * A consumer must have been registered for the signal. 174 * @throws UnsupportedOperationException if handling of the signal is 175 * not supported by the implementation 176 */ 177 public void raise() { raise0(number); } 178 179 /** 180 * Register a handler of the Signal. 181 * Given handler replaces current signal handler, but can 182 * invoke replaced handler by invoking the passed-in {@code Runnable} 183 * object. 184 * 185 * @param handler a signal handler 186 * @throws UnsupportedOperationException if handling of the signal is 187 * not supported by the implementation 188 */ 189 public synchronized void register(BiConsumer<Signal, Runnable> handler) { 190 HandlerChain oldChain = handlerChain; 191 handlerChain = new HandlerChain.Java(oldChain, handler); 192 if (oldChain == null) { 193 // set native to dispatch to Singnal.dispatch() 194 // and save top-level native handler 195 savedNativeHandler = handle1(2); 196 } else if (oldChain instanceof HandlerChain.Native) { 197 // set native to dispatch to Signal.dispatch() only 198 // (the old native handler is saved in oldChain) 199 handle1(2); 200 } 201 } 202 203 /** 204 * Unregister a handler of the Signal. 205 * If given handler is the most recently registered handler for the signal, 206 * signal handling is restored to the state prior to registering given handler 207 * and the method returns {@code true}; otherwise the currently registered 208 * handler is left unchanged and {@code false} is returned. 209 * 210 * @param handler a signal handler; non-null 211 * @return {@code true} if given handler was the most recently registered handler 212 * and was unregistered, otherwise {@code false} 213 */ 214 public synchronized boolean unregister(BiConsumer<Signal, Runnable> handler) { 215 HandlerChain oldChain = handlerChain; 216 if (oldChain instanceof HandlerChain.Java && 217 ((HandlerChain.Java) oldChain).handler == handler) { 218 if (oldChain.next == null) { 219 // restore saved top-level native handler 220 handle1(savedNativeHandler); 221 } else if (oldChain.next instanceof HandlerChain.Native) { 222 // restore next native handler 223 handle1(((HandlerChain.Native) oldChain.next).nativeHandler); 224 } 225 handlerChain = oldChain.next; 226 return true; 227 } else { 228 return false; 229 } 230 } 231 232 long handle1(long nativeHandler) { 233 long oldNativeHandler = handle0(number, nativeHandler); 234 if (oldNativeHandler == -1L) { 235 throw new UnsupportedOperationException( 236 "Signal already used by VM or OS: " + name); 237 } 238 return oldNativeHandler; 239 } 240 241 /* 242 * Called by the VM to execute Java signal handlers. 243 */ 244 private static void dispatch(int number) { 245 Signal signal = SIGNAL_BY_NUMBER.get(number); 246 if (signal != null) { 247 HandlerChain handlerChain = signal.handlerChain; 248 if (handlerChain != null) { 249 new InnocuousThread(() -> handlerChain.accept(signal)) 250 .start(); 251 } 252 } 253 } 254 255 /** 256 * Find the signal number, given a name. 257 * 258 * @param sigName the signal name 259 * @return the signal number or -1 for unknown signals. 260 */ 261 private static native int findSignal0(String sigName); 262 263 /* Registers a native signal handler, and returns the old handler. 264 * Handler values: 265 * 0 default handler 266 * 1 ignore the signal 267 * 2 call back to Signal.dispatch 268 * other arbitrary native signal handlers 269 * @param nativeH the index or address of the new signal handler 270 * @return the previous index or address 271 */ 272 private static native long handle0(int sig, long nativeH); 273 274 /* 275 * Raise a given signal number. 276 * @param sig the signal number to raise 277 */ 278 private static native void raise0(int sig); 279 280 281 private static abstract class HandlerChain implements Consumer<Signal> { 282 final HandlerChain next; 283 284 HandlerChain(HandlerChain next) { 285 this.next = next; 286 } 287 288 @Override 289 public void accept(Signal signal) { 290 if (next != null) { 291 next.accept(signal); 292 } 293 } 294 295 private static class Java extends HandlerChain { 296 final BiConsumer<Signal, Runnable> handler; 297 298 Java(HandlerChain next, BiConsumer<Signal, Runnable> handler) { 299 super(next); 300 this.handler = handler; 301 } 302 303 @Override 304 public void accept(Signal signal) { 305 handler.accept(signal, () -> super.accept(signal)); 306 } 307 } 308 309 private static class Native extends HandlerChain { 310 final long nativeHandler; 311 312 Native(HandlerChain next, long nativeHandler) { 313 super(next); 314 this.nativeHandler = nativeHandler; 315 } 316 317 @Override 318 public void accept(Signal signal) { 319 throw new UnsupportedOperationException( 320 "Can't invoke native handler from Java"); 321 } 322 } 323 } 324 325 private static final class NativeImpl extends Signal implements NativeSignal { 326 NativeImpl(String name, int number) { 327 super(name, number); 328 } 329 330 @Override 331 public synchronized void registerNative(long nativeHandler) { 332 HandlerChain oldChain = handlerChain; 333 handlerChain = new HandlerChain.Native(oldChain, nativeHandler); 334 if (oldChain == null) { 335 // set native to given native handler 336 // and save top-level native handler 337 savedNativeHandler = handle1(nativeHandler); 338 } else { 339 // set native to dispatch to given native handler only 340 handle1(nativeHandler); 341 } 342 } 343 344 @Override 345 public synchronized boolean unregisterNative(long nativeHandler) { 346 HandlerChain oldChain = handlerChain; 347 if (oldChain instanceof HandlerChain.Native && 348 ((HandlerChain.Native) oldChain).nativeHandler == nativeHandler) { 349 if (oldChain.next == null) { 350 // restore saved top-level native handler 351 handle1(savedNativeHandler); 352 } else if (oldChain.next instanceof HandlerChain.Native) { 353 // restore next native handler 354 handle1(((HandlerChain.Native) oldChain.next).nativeHandler); 355 } else { 356 assert oldChain.next instanceof HandlerChain.Java; 357 // restore native to dispatch to Java 358 handle1(2L); 359 } 360 handlerChain = oldChain.next; 361 return true; 362 } else { 363 return false; 364 } 365 } 366 } 367 }