Path: blob/master/test/jdk/sun/misc/SunMiscSignalTest.java
41145 views
/*1* Copyright (c) 2016, 2019, 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*/2425import java.util.ArrayList;26import java.util.List;27import java.util.Objects;28import java.util.concurrent.Semaphore;29import java.util.concurrent.TimeUnit;3031import org.testng.Assert;32import org.testng.TestNG;33import org.testng.annotations.Test;34import org.testng.annotations.BeforeSuite;35import org.testng.annotations.DataProvider;3637import jdk.test.lib.Platform;38import jdk.test.lib.Utils;3940import sun.misc.Signal;41import sun.misc.SignalHandler;4243/*44* @test45* @library /test/lib46* @modules jdk.unsupported47* java.base/jdk.internal.misc48* @build jdk.test.lib.Utils49* jdk.test.lib.Asserts50* jdk.test.lib.JDKToolFinder51* jdk.test.lib.JDKToolLauncher52* jdk.test.lib.Platform53* jdk.test.lib.process.*54* @run testng/othervm -Xrs -DXrs=true SunMiscSignalTest55* @run testng/othervm SunMiscSignalTest56* @summary sun.misc.Signal test57*/5859@Test60public class SunMiscSignalTest {6162// Set to true to enable additional debug output63static boolean debug = true;6465// True to test while running with -Xrs66static boolean RUNNING_WITH_Xrs = Boolean.getBoolean("Xrs");6768/**69* Print a debug message if enabled.70*71* @param format the format72* @param args the arguments73*/74static void printf(String format, Object... args) {75if (debug) {76System.out.printf(" " + format, args);77}78}7980enum IsSupported {NO, YES}8182enum CanRegister {NO, YES}8384enum CanRaise {NO, YES}8586enum Invoked {NO, YES}8788enum RestrictedSignals {NORMAL, XRS}8990@BeforeSuite91static void setup() {92System.out.printf("-Xrs: %s%n", RUNNING_WITH_Xrs);93}9495// Provider of signals to be tested with variations for -Xrs and96// platform dependencies97// -Xrs restricted signals signals the VM will not handle SIGINT, SIGTERM, SIGHUP and others98@DataProvider(name = "supportedSignals")99static Object[][] supportedSignals() {100RestrictedSignals rs = RUNNING_WITH_Xrs ? RestrictedSignals.XRS : RestrictedSignals.NORMAL;101CanRegister registerXrs = RUNNING_WITH_Xrs ? CanRegister.NO : CanRegister.YES;102CanRaise raiseXrs = RUNNING_WITH_Xrs ? CanRaise.NO : CanRaise.YES;103Invoked invokedXrs = RUNNING_WITH_Xrs ? Invoked.NO : Invoked.YES;104105Object[][] commonSignals = new Object[][]{106{"INT", IsSupported.YES, registerXrs, raiseXrs, invokedXrs},107{"TERM", IsSupported.YES, registerXrs, raiseXrs, invokedXrs},108{"ABRT", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},109};110111Object[][] posixSignals = {112{"HUP", IsSupported.YES, registerXrs, raiseXrs, invokedXrs},113{"QUIT", IsSupported.YES, CanRegister.NO, CanRaise.NO, Invoked.NO},114{"USR1", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},115{"USR2", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},116{"PIPE", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},117{"ALRM", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},118{"CHLD", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},119{"CONT", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},120{"TSTP", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},121{"TTIN", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},122{"TTOU", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},123{"URG", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},124{"XCPU", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},125{"XFSZ", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},126{"VTALRM", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},127{"PROF", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},128{"WINCH", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},129{"IO", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},130{"SYS", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},131};132133Object[][] posixNonOSXSignals = {134{"BUS", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},135{"INFO", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},136};137138Object[][] posixOSXSignals = {139{"BUS", IsSupported.YES, CanRegister.NO, CanRaise.NO, Invoked.NO},140{"INFO", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},141};142143Object[][] windowsSignals = {144{"HUP", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},145{"QUIT", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},146{"BUS", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},147{"USR1", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},148{"USR2", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},149{"PIPE", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},150{"ALRM", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},151{"CHLD", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},152{"CONT", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},153{"TSTP", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},154{"TTIN", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},155{"TTOU", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},156{"URG", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},157{"XCPU", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},158{"XFSZ", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},159{"VTALRM", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},160{"PROF", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},161{"WINCH", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},162{"IO", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},163{"SYS", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},164};165166Object[][] combinedPosixSignals = concatArrays(posixSignals,167(Platform.isOSX() ? posixOSXSignals : posixNonOSXSignals));168return concatArrays(commonSignals, (Platform.isWindows() ? windowsSignals : combinedPosixSignals));169}170171// Provider of invalid signal names172@DataProvider(name = "invalidSunMiscSignalNames")173Object[][] invalidSunMiscSignalNames() {174return new Object[][]{175{""},176{"I"},177{"SIG"},178{"SIGabc"},179{"SIGINT"}, // prefix not allowed180{"abc"},181};182}183184static Object[][] concatArrays(Object[][]... arrays) {185int l = 0;186for (Object[][] a : arrays) {187l += a.length;188}189190Object[][] newArray = new Object[l][];191l = 0;192for (int i = 0; i < arrays.length; i++) {193System.arraycopy(arrays[i], 0, newArray, l, arrays[i].length);194l += arrays[i].length;195}196197return newArray;198}199200// Return true if the signal is one of the shutdown signals known to the VM201private static boolean isShutdownSignal(Signal signal) {202String name = signal.getName();203return name.equals("INT") || name.equals("HUP") || name.equals("TERM");204}205206/**207* Quick verification of supported signals using sun.misc.Signal.208*209* @param name the signal name210* @throws InterruptedException would be an error if thrown211*/212@Test(dataProvider = "supportedSignals")213static void testSunMisc(String name, IsSupported supported, CanRegister register,214CanRaise raise, Invoked invoked) throws InterruptedException {215Handler h = new Handler();216SignalHandler orig = null;217Signal signal = null;218try {219signal = new Signal(name);220Assert.assertEquals(supported, IsSupported.YES, "Unexpected support for " + name);221222Assert.assertEquals(signal.getName(), name, "getName() mismatch, ");223224Assert.assertEquals(signal.toString(), "SIG" + name, "toString() mismatch, ");225226try {227orig = Signal.handle(signal, h);228printf("oldHandler: %s%n", orig);229Assert.assertEquals(CanRegister.YES, register, "Unexpected handle succeeded " + name);230try {231Signal.raise(signal);232Assert.assertEquals(CanRaise.YES, raise, "Unexpected raise success for " + name);233Invoked inv = h.semaphore().tryAcquire(Utils.adjustTimeout(100L),234TimeUnit.MILLISECONDS) ? Invoked.YES : Invoked.NO;235if (!isShutdownSignal(signal)) {236// Normal case237Assert.assertEquals(inv, invoked, "handler not invoked;");238} else {239if (orig == SignalHandler.SIG_IGN) {240Assert.assertEquals(inv, Invoked.NO, "handler should not be invoked");241} else {242Assert.assertEquals(inv, invoked, "handler not invoked;");243}244}245} catch (IllegalArgumentException uoe3) {246Assert.assertNotEquals(CanRaise.YES, raise, "raise failed for " + name +247": " + uoe3.getMessage());248}249} catch (IllegalArgumentException uoe2) {250Assert.assertNotEquals(CanRegister.YES, register, "handle failed for: " + name +251": " + uoe2.getMessage());252}253} catch (IllegalArgumentException uoe) {254Assert.assertNotEquals(IsSupported.YES, supported, "Support missing for " + name +255": " + uoe.getMessage());256return;257} finally {258// Restore original signal handler259if (orig != null && signal != null) {260Signal.handle(signal, orig);261}262}263}264265// Test Signal is equal to itself and not equals to others266@Test(dataProvider = "supportedSignals")267static void testEquals(String name, IsSupported supported, CanRegister register,268CanRaise raise, Invoked invoked) {269Object[][] data = supportedSignals();270for (int i = 0; i < data.length; i++) {271IsSupported otherSupported = (IsSupported) data[i][1];272if (supported == IsSupported.NO || otherSupported == IsSupported.NO) {273continue;274}275String otherName = (String) data[i][0];276277Signal sig1 = new Signal(name);278Signal sig2 = new Signal(otherName);279if (name.equals(otherName)) {280Assert.assertEquals(sig1, sig2, "Equals failed; ");281Assert.assertEquals(sig1.hashCode(), sig2.hashCode(), "HashCode wrong; ");282} else {283Assert.assertNotEquals(sig1, sig2, "NotEquals failed; ");284Assert.assertNotEquals(sig1.hashCode(), sig2.hashCode(), "HashCode wrong; ");285}286}287}288289@Test(dataProvider = "invalidSunMiscSignalNames")290static void testSunMiscIAE(String name) {291try {292new Signal(name);293Assert.fail("Should have thrown IAE for signal: " + name);294} catch (IllegalArgumentException iae) {295Assert.assertEquals(iae.getMessage(), "Unknown signal: " + name, "getMessage() incorrect; ");296}297}298299// Note: JDK 8 did not check/throw NPE, passing null resulted in a segv300@Test(expectedExceptions = NullPointerException.class)301static void nullSignal() {302new Signal(null);303}304305// Test expected exception when raising a signal when no handler defined306@Test307static void testRaiseNoConsumer() {308Signal signal = new Signal("INT");309SignalHandler orig = null;310try {311orig = Signal.handle(signal, SignalHandler.SIG_DFL);312printf("oldHandler: %s%n", orig);313if (orig == SignalHandler.SIG_IGN) {314// SIG_IGN for TERM means it cannot be handled315return;316}317Signal.raise(signal);318Assert.fail("Should have thrown IllegalArgumentException");319} catch (IllegalArgumentException iae) {320printf("IAE message: %s%n", iae.getMessage());321} finally {322// Restore original signal handler323if (orig != null && signal != null) {324Signal.handle(signal, orig);325}326}327}328329/**330* The thread that runs the handler for sun.misc.Signal should be a331* Daemon thread.332*/333@Test334static void isDaemonThread() throws InterruptedException {335if (RUNNING_WITH_Xrs) {336return;337}338Handler handler = new Handler();339Signal signal = new Signal("INT");340SignalHandler orig = Signal.handle(signal, handler);341printf("oldHandler: %s%n", orig);342if (orig == SignalHandler.SIG_IGN) {343// SIG_IGN for INT means it cannot be handled344return;345}346347Signal.raise(signal);348boolean handled = handler.semaphore()349.tryAcquire(Utils.adjustTimeout(100L), TimeUnit.MILLISECONDS);350if (!handled) {351// For debug try again352printf("Second try to see signal");353handled = handler.semaphore()354.tryAcquire(Utils.adjustTimeout(2L), TimeUnit.SECONDS);355}356Assert.assertEquals(handled, !RUNNING_WITH_Xrs,357"raising s.m.Signal did not get a callback;");358359Assert.assertTrue(handler.wasDaemon(), "Thread.isDaemon running the handler; ");360}361362// Check that trying to invoke SIG_DFL.handle throws UnsupportedOperationException.363@Test(expectedExceptions = UnsupportedOperationException.class)364static void cannotHandleSIGDFL() {365Signal signal = new Signal("INT");366Assert.assertNotNull(SignalHandler.SIG_DFL, "SIG_DFL null; ");367SignalHandler.SIG_DFL.handle(signal);368}369370// Check that trying to invoke SIG_IGN.handle throws UnsupportedOperationException.371@Test(expectedExceptions = UnsupportedOperationException.class)372static void cannotHandleSIGIGN() {373Signal signal = new Signal("INT");374Assert.assertNotNull(SignalHandler.SIG_IGN, "SIG_IGN null; ");375SignalHandler.SIG_IGN.handle(signal);376}377378// Check that setting a Signal handler returns the previous handler.379@Test()380static void checkLastHandler() {381if (RUNNING_WITH_Xrs) {382return;383}384Signal signal = new Signal("TERM");385Handler h1 = new Handler();386Handler h2 = new Handler();387SignalHandler orig = Signal.handle(signal, h1);388if (orig == SignalHandler.SIG_IGN) {389// SIG_IGN for TERM means it cannot be handled390return;391}392393try {394SignalHandler prev = Signal.handle(signal, h2);395Assert.assertSame(prev, h1, "prev handler mismatch");396397prev = Signal.handle(signal, h1);398Assert.assertSame(prev, h2, "prev handler mismatch");399} finally {400if (orig != null && signal != null) {401Signal.handle(signal, orig);402}403}404}405406/**407* Test Handler, a SignalHandler for Signal notifications.408* Signals a semaphore when invoked and records whether409* the thread calling the Handler was a daemon.410*/411static class Handler implements SignalHandler {412// A semaphore to check for accept being called413Semaphore sema = new Semaphore(0);414415Boolean wasDaemon = null;416417Semaphore semaphore() {418return sema;419}420421synchronized Boolean wasDaemon() {422return wasDaemon;423}424425/**426* Releases the semaphore when called as SignalHandler.handle.427*428* @param signal the Signal that occurred429*/430@Override431public void handle(Signal signal) {432synchronized (this) {433wasDaemon = Thread.currentThread().isDaemon();434}435sema.release();436printf("sun.misc.handle sig: %s, num: %d%n", signal.getName(), signal.getNumber());437}438439public String toString() {440return "Handler: sem: " + sema.getQueueLength() +441", wasDaemon: " + Objects.toString(wasDaemon());442}443}444445// Main can be used to run the tests from the command line with only testng.jar.446@SuppressWarnings("raw_types")447@Test(enabled = false)448public static void main(String[] args) {449Class<?>[] testclass = {SunMiscSignalTest.class};450TestNG testng = new TestNG();451testng.setTestClasses(testclass);452testng.run();453}454455}456457458