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
26package sun.misc;
27
28import java.util.Objects;
29
30/**
31 * This class provides ANSI/ISO C signal support. A Java program can register
32 * 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 used
36 * by the Java VM implementation. The <code>Signal.handle</code>
37 * function raises an <code>IllegalArgumentException</code> if such an attempt
38 * is made.
39 * <li>
40 * When <code>Signal.handle</code> is called, the VM internally registers a
41 * special C signal handler. There is no way to force the Java signal handler
42 * to run synchronously before the C signal handler returns. Instead, when the
43 * VM receives a signal, the special C signal handler creates a new thread
44 * (at priority <code>Thread.MAX_PRIORITY</code>) to
45 * run the registered Java signal handler. The C signal handler immediately
46 * returns. Note that because the Java signal handler runs in a newly created
47 * thread, it may not actually be executed until some time after the C signal
48 * 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 is
56 * 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 * SignalHandler handler = new SignalHandler () {
63 *     public void handle(Signal sig) {
64 *       ... // handle SIGINT
65 *     }
66 * };
67 * Signal.handle(new Signal("INT"), handler);
68 * </pre></blockquote>
69 *
70 * @author   Sheng Liang
71 * @author   Bill Shannon
72 * @see     sun.misc.SignalHandler
73 * @since    1.2
74 */
75public final class Signal {
76
77    // Delegate to jdk.internal.misc.Signal.
78    private final jdk.internal.misc.Signal iSignal;
79
80    /* Returns the signal number */
81    public int getNumber() {
82        return iSignal.getNumber();
83    }
84
85    /**
86     * Returns the signal name.
87     *
88     * @return the name of the signal.
89     * @see sun.misc.Signal#Signal(String name)
90     */
91    public String getName() {
92        return iSignal.getName();
93    }
94
95    /**
96     * Compares the equality of two <code>Signal</code> objects.
97     *
98     * @param other the object to compare with.
99     * @return whether two <code>Signal</code> objects are equal.
100     */
101    public boolean equals(Object other) {
102        if (this == other) {
103            return true;
104        }
105        if (other == null || !(other instanceof Signal)) {
106            return false;
107        }
108        Signal other1 = (Signal)other;
109        return iSignal.equals(other1.iSignal);
110    }
111
112    /**
113     * Returns a hashcode for this Signal.
114     *
115     * @return  a hash code value for this object.
116     */
117    public int hashCode() {
118        return getNumber();
119    }
120
121    /**
122     * Returns a string representation of this signal. For example, "SIGINT"
123     * for an object constructed using <code>new Signal ("INT")</code>.
124     *
125     * @return a string representation of the signal
126     */
127    public String toString() {
128        return iSignal.toString();
129    }
130
131    /**
132     * Constructs a signal from its name.
133     *
134     * @param name the name of the signal.
135     * @exception IllegalArgumentException unknown signal
136     * @see sun.misc.Signal#getName()
137     */
138    public Signal(String name) {
139        iSignal = new jdk.internal.misc.Signal(name);
140    }
141
142    /**
143     * Registers a signal handler.
144     *
145     * @param sig a signal
146     * @param handler the handler to be registered with the given signal.
147     * @return the old handler
148     * @exception IllegalArgumentException the signal is in use by the VM
149     * @see sun.misc.Signal#raise(Signal sig)
150     * @see sun.misc.SignalHandler
151     * @see sun.misc.SignalHandler#SIG_DFL
152     * @see sun.misc.SignalHandler#SIG_IGN
153     */
154    public static synchronized SignalHandler handle(Signal sig,
155                                                    SignalHandler handler)
156        throws IllegalArgumentException {
157        jdk.internal.misc.Signal.Handler oldHandler = jdk.internal.misc.Signal.handle(sig.iSignal,
158                InternalMiscHandler.of(sig, handler));
159        return SunMiscHandler.of(sig.iSignal, oldHandler);
160    }
161
162    /**
163     * Raises a signal in the current process.
164     *
165     * @param sig a signal
166     * @see sun.misc.Signal#handle(Signal sig, SignalHandler handler)
167     */
168    public static void raise(Signal sig) throws IllegalArgumentException {
169        jdk.internal.misc.Signal.raise(sig.iSignal);
170    }
171
172    /*
173     * Wrapper class to proxy a SignalHandler to a jdk.internal.misc.Signal.Handler.
174     */
175    static final class InternalMiscHandler implements jdk.internal.misc.Signal.Handler {
176        private final SignalHandler handler;
177        private final Signal signal;
178
179        static jdk.internal.misc.Signal.Handler of(Signal signal, SignalHandler handler) {
180            if (handler == SignalHandler.SIG_DFL) {
181                return jdk.internal.misc.Signal.Handler.SIG_DFL;
182            } else if (handler == SignalHandler.SIG_IGN) {
183                return jdk.internal.misc.Signal.Handler.SIG_IGN;
184            } else if (handler instanceof SunMiscHandler) {
185                return ((SunMiscHandler)handler).iHandler;
186            } else {
187                return new InternalMiscHandler(signal, handler);
188            }
189        }
190
191        private InternalMiscHandler(Signal signal, SignalHandler handler) {
192            this.handler = handler;
193            this.signal = signal;
194        }
195
196        @Override
197        public void handle(jdk.internal.misc.Signal ignore) {
198            handler.handle(signal);
199        }
200    }
201
202    /*
203     * Wrapper class to proxy a jdk.internal.misc.Signal.Handler to a SignalHandler.
204     */
205    static final class SunMiscHandler implements SignalHandler {
206        private final jdk.internal.misc.Signal iSignal;
207        private final jdk.internal.misc.Signal.Handler iHandler;
208
209        static SignalHandler of(jdk.internal.misc.Signal signal, jdk.internal.misc.Signal.Handler handler) {
210            if (handler == jdk.internal.misc.Signal.Handler.SIG_DFL) {
211                return SignalHandler.SIG_DFL;
212            } else if (handler == jdk.internal.misc.Signal.Handler.SIG_IGN) {
213                return SignalHandler.SIG_IGN;
214            } else if (handler instanceof InternalMiscHandler) {
215                return ((InternalMiscHandler) handler).handler;
216            } else {
217                return new SunMiscHandler(signal, handler);
218            }
219        }
220
221        SunMiscHandler(jdk.internal.misc.Signal iSignal, jdk.internal.misc.Signal.Handler iHandler) {
222            this.iSignal = iSignal;
223            this.iHandler = iHandler;
224        }
225
226        @Override
227        public void handle(Signal sig) {
228            iHandler.handle(iSignal);
229        }
230
231        public String toString() {
232            return iHandler.toString();
233        }
234    }
235}
236