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