--- /dev/null 2016-02-02 08:28:09.597457739 +0100
+++ new/src/java.base/share/classes/java/util/Signal.java 2016-02-02 22:57:28.860522302 +0100
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import jdk.internal.misc.NativeSignal;
+import sun.misc.InnocuousThread;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * Signal provides support for responding to and raising platform signals.
+ * Each signal has a current signal handler.
+ * The signals supported are implementation and operating system specific.
+ *
+ * {@link Signal#register(Consumer) Registering} a handler replaces the
+ * current handler with the provided handler.
+ * {@link Signal#unregister(Consumer) Unregistering} a handler restores the
+ * signal handling to the state before registering the handler.
+ * The signal handler is initially registered for the signals
+ * {@code SIGINT}, {@code SIGTERM}, and {@code SIGHUP}.
+ * The system registered handler terminates the Java Runtime
+ * by invoking {@link System#exit System.exit} with a
+ * value of {@code 128 + the signal number}. Other signals are ignored.
+ * Handlers for signals that are unknown or reserved by the
+ * Java implementation can not be registered.
+ *
+ * Handling and raising signals are sensitive operations. Access to
+ * Signal instances is restricted via {@code RuntimePermission("handleSignal")}
+ * if a SecurityManager is installed.
+ *
+ * Common signal names that follow ANSI/ISO C conventions include:
+ *
+ * - SIGINT - Interrupt as if the user typed {@code Ctrl-C}
+ *
- SIGTERM - A request for normal termination
+ *
- SIGHUP - The process is no longer connected to a controlling terminal
+ *
+ *
+ * Signal objects are created based on their names. For example:
+ *
{@code
+ * Signal s = Signal.of("SIGINT");
+ * }
+ * constructs a Signal for {@code SIGINT}, which is
+ * typically produced when the user presses {@code Ctrl-C}.
+ *
+ * To handle a signal a handler is registered for the Signal.
+ * For example, to respond to {@code Ctrl-C}:
+ *
{@code
+ * Consumer handler = s -> {
+ * ... // handle SIGINT
+ * };
+ * Signal.of("SIGINT").register(handler);
+ * }
+ *
+ * Signal is an interned object. There is a single instance for a particular
+ * signal name.
+ *
+ * Unless otherwise noted, passing a {@code null} argument to any method in this
+ * class causes a {@link java.lang.NullPointerException NullPointerException}
+ * to be thrown.
+ *
+ *
+ *
+ * @implNote Signal handling is asynchronous to the native signal mechanisms.
+ * The implementation handles the native signal and signals a Java Thread to
+ * deliver the signal to the registered handler.
+ * Since the Java signal handler runs in a newly created thread, it may not be
+ * executed until some time after the native signal handler returns.
+ *
+ * @since 9
+ */
+public class Signal {
+
+ /**
+ * Returns the named Signal.
+ *
+ * @param name the name of the signal
+ * @return the named Signal
+ * @throws UnsupportedOperationException if the signal is unknown or reserved
+ * @throws SecurityException if a SecurityManager is installed and
+ * the {@code RuntimePermission("handleSignal")} is denied
+ */
+ public static Signal of(String name) {
+ Objects.requireNonNull(name, "name");
+
+ Signal signal = SIGNAL_BY_NAME.get(name);
+ if (signal != null) {
+ return signal;
+ }
+
+ int number;
+ if (!name.startsWith("SIG") || name.length() <= 3 ||
+ (number = findSignal0(name.substring(3))) < 0) {
+ throw new UnsupportedOperationException("Unknown signal: " + name);
+ }
+
+ signal = SIGNAL_BY_NUMBER.computeIfAbsent(
+ number,
+ new Function() {
+ @Override
+ public Signal apply(Integer number) {
+ return new Signal.NativeImpl(name, number);
+ }
+ }
+ );
+
+ SIGNAL_BY_NAME.putIfAbsent(name, signal);
+
+ return signal;
+ }
+
+ private static final ConcurrentMap SIGNAL_BY_NAME = new ConcurrentHashMap<>(4);
+ private static final ConcurrentMap SIGNAL_BY_NUMBER = new ConcurrentHashMap<>(4);
+
+ private final String name;
+ private final int number;
+ volatile HandlerNode handlerNode;
+ long topNativeHandler;
+
+ Signal(String name, int number) {
+ this.name = name;
+ this.number = number;
+ }
+
+ /**
+ * Returns the signal name.
+ * Signal names are implementation specific.
+ *
+ * @return the signal name
+ */
+ public String name() { return name; }
+
+ /**
+ * Returns the signal number.
+ * Signal numbers are implementation specific.
+ *
+ * @return the signal number
+ */
+ public int number() { return number; }
+
+ /**
+ * Raises the signal in the current process.
+ * A consumer must have been registered for the signal.
+ * @throws UnsupportedOperationException if handling of the signal is
+ * not supported by the implementation
+ */
+ public void raise() { raise0(number); }
+
+ /**
+ * Register a handler of the Signal.
+ * Given handler replaces current signal handler.
+ *
+ * @param handler a signal handler
+ * @throws UnsupportedOperationException if handling of the signal is
+ * not supported by the implementation
+ */
+ public synchronized void register(Consumer handler) {
+ Objects.requireNonNull(handler, "handler");
+ HandlerNode oldNode = handlerNode;
+ HandlerNode newNode = new HandlerNode(oldNode, handler);
+ replace(oldNode, newNode);
+ }
+
+ /**
+ * Unregister a handler of the Signal.
+ * If given handler is the most recently registered handler for the signal,
+ * signal handling is restored to the state prior to registering given handler
+ * and the method returns {@code true}; otherwise the currently registered
+ * handler is left unchanged and {@code false} is returned.
+ *
+ * @param handler a signal handler; non-null
+ * @return {@code true} if given handler was the most recently registered handler
+ * and was unregistered, otherwise {@code false}
+ */
+ public synchronized boolean unregister(Consumer handler) {
+ Objects.requireNonNull(handler, "handler");
+ HandlerNode oldNode = handlerNode;
+ if (oldNode != null && !oldNode.isNative() && oldNode.handler == handler) {
+ replace(oldNode, oldNode.previous);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ void replace(HandlerNode oldNode, HandlerNode newNode) {
+ assert Thread.holdsLock(this);
+ if ((oldNode == null || oldNode.isNative()) &&
+ (newNode != null && !newNode.isNative())) {
+ // when transitioning from native to java handler, we must
+ // set handlerNode before setting native handler to avoid
+ // possible race...
+ handlerNode = newNode;
+ long oldNativeHandler;
+ try {
+ oldNativeHandler = handle1(newNode.nativeHandler);
+ } catch (RuntimeException | Error e) {
+ // ...but must restore it if unsuccessful
+ handlerNode = oldNode;
+ throw e;
+ }
+ if (oldNode == null) {
+ // save top-level native handler if replacing the null oldNode
+ topNativeHandler = oldNativeHandler;
+ }
+ } else {
+ // when transitioning from java to native handler, we must
+ // set native handler before setting handlerNode to avoid
+ // possible race; when transitioning from one native handler to another
+ // or when transitioning from one java handler to another,
+ // the order is not important...
+ handle1(newNode == null
+ ? topNativeHandler // restore top-level native handler if
+ // replacing with null newNode
+ : newNode.nativeHandler);
+ handlerNode = newNode;
+ }
+ }
+
+ long handle1(long nativeHandler) {
+ long oldNativeHandler = handle0(number, nativeHandler);
+ if (oldNativeHandler == -1L) {
+ throw new UnsupportedOperationException(
+ "Signal already used by VM or OS: " + name);
+ }
+ return oldNativeHandler;
+ }
+
+ /*
+ * Called by the VM to execute Java signal handlers.
+ */
+ private static void dispatch(int number) {
+ Signal signal = SIGNAL_BY_NUMBER.get(number);
+ if (signal != null) {
+ HandlerNode handlerNode = signal.handlerNode;
+ if (handlerNode != null) {
+ Consumer handler = handlerNode.handler;
+ if (handler != null) {
+ new InnocuousThread(() -> handler.accept(signal))
+ .start();
+ }
+ }
+ }
+ }
+
+ /**
+ * Find the signal number, given a name.
+ *
+ * @param sigName the signal name
+ * @return the signal number or -1 for unknown signals.
+ */
+ private static native int findSignal0(String sigName);
+
+ /**
+ * Registers a native signal handler, and returns the old handler.
+ * Handler values:
+ * 0 default handler
+ * 1 ignore the signal
+ * 2 call back to Signal.dispatch
+ * other arbitrary native signal handlers
+ * @param nativeH the index or address of the new signal handler
+ * @return the previous index or address
+ */
+ private static native long handle0(int sig, long nativeH);
+
+ /**
+ * Raise a given signal number.
+ * @param sig the signal number to raise
+ */
+ private static native void raise0(int sig);
+
+
+ private static final class HandlerNode {
+ final HandlerNode previous;
+ final Consumer handler;
+ final long nativeHandler;
+
+ HandlerNode(HandlerNode previous, Consumer handler) {
+ this.previous = previous;
+ this.handler = handler;
+ this.nativeHandler = 2L;
+ }
+
+ HandlerNode(HandlerNode previous, long nativeHandler) {
+ this.previous = previous;
+ this.handler = null;
+ this.nativeHandler = nativeHandler;
+ }
+
+ boolean isNative() {
+ return handler == null;
+ }
+ }
+
+ private static final class NativeImpl extends Signal implements NativeSignal {
+ NativeImpl(String name, int number) {
+ super(name, number);
+ }
+
+ @Override
+ public synchronized void register(long nativeHandler) {
+ HandlerNode oldNode = handlerNode;
+ HandlerNode newNode = new HandlerNode(oldNode, nativeHandler);
+ replace(oldNode, newNode);
+ }
+
+ @Override
+ public synchronized boolean unregister(long nativeHandler) {
+ HandlerNode oldNode = handlerNode;
+ if (oldNode != null && oldNode.isNative() && oldNode.nativeHandler == nativeHandler) {
+ replace(oldNode, oldNode.previous);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+}