1 /* 2 * Copyright (c) 2001, 2020, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package nsk.share; 25 26 /** 27 * Terminator is used to terminate a stress test with PASS exit status 28 * before the test is terminated as timed out (and so failed). 29 * 30 * <p>Terminator class holds a thread which sleeps for the given amount 31 * of time, and then wakes up and executes <tt>System.exit()</tt> 32 * with the given exit status. That thread is daemon, so it doesn't 33 * prevent application from exiting once all its threads finish 34 * before it's time for termination. Appointing terminator in zero 35 * delay implies immediate <tt>exit()</tt>. 36 * 37 * <p>There is a limitation: you may appoint no more than one terminator 38 * per application. 39 */ 40 public class Terminator { 41 /** 42 * Use specific <tt>appoint()</tt> method to appoint terminator. 43 * 44 * @see #appoint(int) 45 * @see #appoint(int,int) 46 */ 47 protected Terminator() {} 48 49 /** 50 * One terminator per application, or <tt>null</tt> (by default). 51 */ 52 private static Thread terminator = null; 53 54 /** 55 * <p>Return timeout (or waittime) value munus the margin 56 * value (which is assumed 1 minute by default). 57 * 58 * <p>Treat <tt>args[0]</tt> as <tt>$TIMEOUT</tt> value, or seek for 59 * <tt>-waittime=$WAITTIME</tt> value. If both parameters 60 * (or either none of them) are assigned, throw an exception to 61 * report parameters inconsistency. 62 * 63 * <p>Also, seek for <tt>-margin=...</tt> assignment, or assume margin 64 * is 1 minute. 65 * 66 * @param args Is usually obtained via the application's command-line. 67 * 68 * @throws IllegalArgumentException If <tt>args[]</tt> is inconsistent. 69 * 70 * @see #appoint(int) 71 * @see #appoint(int,int) 72 */ 73 public static int parseAppointment(String args[]) { 74 int timeout=-1, margin=1; 75 int timeouts=0, waittimes=0, margins=0; 76 for (int i=0; i<args.length; i++) { 77 if (args[i].startsWith("-")) { 78 if (args[i].startsWith("-waittime=")) { 79 timeout = Integer.parseInt(args[i].substring(10)); 80 waittimes++; 81 } 82 if (args[i].startsWith("-margin=")) { 83 margin = Integer.parseInt(args[i].substring(8)); 84 margins++; 85 } 86 } else { 87 if (i == 0) { 88 timeout = Integer.parseInt(args[i]); 89 timeouts++; 90 } 91 } 92 }; 93 if (timeouts==0 && waittimes==0) 94 throw new IllegalArgumentException( 95 "no $TIMEOUT, nor -waittime=$WAITTIME is set"); 96 if (waittimes > 1) 97 throw new IllegalArgumentException( 98 "more than one -waittime=... is set"); 99 if (margins > 1) 100 throw new IllegalArgumentException( 101 "more than one -margin=... is set"); 102 103 int result = timeout - margin; 104 if (result <= 0) 105 throw new IllegalArgumentException( 106 "delay appointment must be greater than "+margin+" minutes"); 107 return result; 108 } 109 110 /** 111 * Appoint terminator after the given amount of <tt>minutes</tt>, 112 * so that exit status would be 95 (to simulate JCK-like PASS 113 * status). 114 * 115 * @throws IllegalStateException If terminator is already appointed. 116 * 117 * @see #appoint(int,int) 118 * @see #parseAppointment(String[]) 119 */ 120 public static void appoint(int minutes) { 121 appoint(minutes,95); // JCK-like PASS status 122 } 123 124 /** 125 * Appoint Terminator for the given amount of <tt>minutes</tt>, 126 * so that the given <tt>status</tt> would be exited when time 127 * is over. 128 * 129 * @throws IllegalStateException If terminator is already appointed. 130 * 131 * @see #appoint(int) 132 * @see #parseAppointment(String[]) 133 */ 134 public static void appoint(int minutes, int status) { 135 if (terminator != null) 136 throw new IllegalStateException("Terminator is already appointed."); 137 138 final long timeToExit = System.currentTimeMillis() + 60*1000L*minutes; 139 final int exitStatus = status; 140 141 terminator = new Thread(Terminator.class.getName()) { 142 public void run() { 143 long timeToSleep = timeToExit - System.currentTimeMillis(); 144 if (timeToSleep > 0) 145 try { 146 // 147 // Use wait() instead of sleep(), because Java 2 148 // specification doesn't guarantee the method 149 // sleep() to yield to other threads. 150 // 151 Object someDummyObject = new Object(); 152 synchronized (someDummyObject) { 153 someDummyObject.wait(timeToSleep); 154 } 155 } catch (InterruptedException exception) { 156 exception.printStackTrace(System.err); 157 // 158 // OOPS, the dagger for terminator looks broken: 159 // 160 return; 161 }; 162 // 163 // OK, lets do it now: 164 // 165 System.err.println( 166 "#\n# Terminator: prescheduled program termination.\n#"); 167 System.exit(exitStatus); // terminator to all threads 168 } 169 }; 170 171 terminator.setPriority(Thread.MAX_PRIORITY); 172 terminator.setDaemon(true); 173 terminator.start(); 174 } 175 }