Path: blob/master/src/java.base/share/classes/jdk/internal/misc/Signal.java
41159 views
/*1* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package jdk.internal.misc;2627import java.util.Hashtable;28import java.util.Objects;2930/**31* This class provides ANSI/ISO C signal support. A Java program can register32* signal handlers for the current process. There are two restrictions:33* <ul>34* <li>35* Java code cannot register a handler for signals that are already used36* by the Java VM implementation. The <code>Signal.handle</code>37* function raises an <code>IllegalArgumentException</code> if such an attempt38* is made.39* <li>40* When <code>Signal.handle</code> is called, the VM internally registers a41* special C signal handler. There is no way to force the Java signal handler42* to run synchronously before the C signal handler returns. Instead, when the43* VM receives a signal, the special C signal handler creates a new thread44* (at priority <code>Thread.MAX_PRIORITY</code>) to45* run the registered Java signal handler. The C signal handler immediately46* returns. Note that because the Java signal handler runs in a newly created47* thread, it may not actually be executed until some time after the C signal48* handler returns.49* </ul>50* <p>51* Signal objects are created based on their names. For example:52* <blockquote><pre>53* new Signal("INT");54* </pre></blockquote>55* constructs a signal object corresponding to <code>SIGINT</code>, which is56* typically produced when the user presses <code>Ctrl-C</code> at the command line.57* The <code>Signal</code> constructor throws <code>IllegalArgumentException</code>58* when it is passed an unknown signal.59* <p>60* This is an example of how Java code handles <code>SIGINT</code>:61* <blockquote><pre>62* Signal.Handler handler = new Signal.Handler () {63* public void handle(Signal sig) {64* ... // handle SIGINT65* }66* };67* Signal.handle(new Signal("INT"), handler);68* </pre></blockquote>69*70* @since 971*/72public final class Signal {73private static Hashtable<Signal, Signal.Handler> handlers = new Hashtable<>(4);74private static Hashtable<Integer, Signal> signals = new Hashtable<>(4);7576private int number;77private String name;7879/* Returns the signal number */80public int getNumber() {81return number;82}8384/**85* Returns the signal name.86*87* @return the name of the signal.88* @see jdk.internal.misc.Signal#Signal(String name)89*/90public String getName() {91return name;92}9394/**95* Compares the equality of two <code>Signal</code> objects.96*97* @param obj the object to compare with.98* @return whether two <code>Signal</code> objects are equal.99*/100public boolean equals(Object obj) {101if (this == obj) {102return true;103}104if (obj instanceof Signal other) {105return name.equals(other.name) && (number == other.number);106}107return false;108}109110/**111* Returns a hashcode for this Signal.112*113* @return a hash code value for this object.114*/115public int hashCode() {116return number;117}118119/**120* Returns a string representation of this signal. For example, "SIGINT"121* for an object constructed using <code>new Signal ("INT")</code>.122*123* @return a string representation of the signal124*/125public String toString() {126return "SIG" + name;127}128129/**130* Constructs a signal from its name.131*132* @param name the name of the signal.133* @exception IllegalArgumentException unknown signal134* @see jdk.internal.misc.Signal#getName()135*/136public Signal(String name) {137Objects.requireNonNull(name, "name");138// Signal names are the short names;139// the "SIG" prefix is not used for compatibility with previous JDKs140if (name.startsWith("SIG")) {141throw new IllegalArgumentException("Unknown signal: " + name);142}143this.name = name;144number = findSignal0(name);145if (number < 0) {146throw new IllegalArgumentException("Unknown signal: " + name);147}148}149150/**151* Registers a signal handler.152*153* @param sig a signal154* @param handler the handler to be registered with the given signal.155* @return the old handler156* @exception IllegalArgumentException the signal is in use by the VM157* @see jdk.internal.misc.Signal#raise(Signal sig)158* @see jdk.internal.misc.Signal.Handler159* @see jdk.internal.misc.Signal.Handler#SIG_DFL160* @see jdk.internal.misc.Signal.Handler#SIG_IGN161*/162public static synchronized Signal.Handler handle(Signal sig,163Signal.Handler handler)164throws IllegalArgumentException {165Objects.requireNonNull(sig, "sig");166Objects.requireNonNull(handler, "handler");167long newH = (handler instanceof NativeHandler) ?168((NativeHandler)handler).getHandler() : 2;169long oldH = handle0(sig.number, newH);170if (oldH == -1) {171throw new IllegalArgumentException172("Signal already used by VM or OS: " + sig);173}174signals.put(sig.number, sig);175synchronized (handlers) {176Signal.Handler oldHandler = handlers.get(sig);177handlers.remove(sig);178if (newH == 2) {179handlers.put(sig, handler);180}181if (oldH == 0) {182return Signal.Handler.SIG_DFL;183} else if (oldH == 1) {184return Signal.Handler.SIG_IGN;185} else if (oldH == 2) {186return oldHandler;187} else {188return new NativeHandler(oldH);189}190}191}192193/**194* Raises a signal in the current process.195*196* @param sig a signal197* @see jdk.internal.misc.Signal#handle(Signal sig, Signal.Handler handler)198*/199public static void raise(Signal sig) throws IllegalArgumentException {200Objects.requireNonNull(sig, "sig");201if (handlers.get(sig) == null) {202throw new IllegalArgumentException("Unhandled signal: " + sig);203}204raise0(sig.number);205}206207/* Called by the VM to execute Java signal handlers. */208private static void dispatch(final int number) {209final Signal sig = signals.get(number);210final Signal.Handler handler = handlers.get(sig);211212Runnable runnable = new Runnable () {213public void run() {214// Don't bother to reset the priority. Signal handler will215// run at maximum priority inherited from the VM signal216// dispatch thread.217// Thread.currentThread().setPriority(Thread.NORM_PRIORITY);218handler.handle(sig);219}220};221if (handler != null) {222new Thread(null, runnable, sig + " handler", 0, false).start();223}224}225226/* Find the signal number, given a name. Returns -1 for unknown signals. */227private static native int findSignal0(String sigName);228/* Registers a native signal handler, and returns the old handler.229* Handler values:230* 0 default handler231* 1 ignore the signal232* 2 call back to Signal.dispatch233* other arbitrary native signal handlers234*/235private static native long handle0(int sig, long nativeH);236/* Raise a given signal number */237private static native void raise0(int sig);238239/**240* This is the signal handler interface expected in <code>Signal.handle</code>.241*/242public interface Handler {243244/**245* The default signal handler246*/247public static final Signal.Handler SIG_DFL = new NativeHandler(0);248/**249* Ignore the signal250*/251public static final Signal.Handler SIG_IGN = new NativeHandler(1);252253/**254* Handle the given signal255*256* @param sig a signal object257*/258public void handle(Signal sig);259}260261262/*263* A package-private class implementing a signal handler in native code.264*/265static final class NativeHandler implements Signal.Handler {266267private final long handler;268269long getHandler() {270return handler;271}272273NativeHandler(long handler) {274this.handler = handler;275}276277public void handle(Signal sig) {278throw new UnsupportedOperationException("invoking native signal handle not supported");279}280281public String toString() {282return this == SIG_DFL ? "SIG_DFL" :283(this == SIG_IGN ? "SIG_IGN" : super.toString());284}285}286287}288289290