147
148 private void addJdks(Path[] jdkPaths) {
149 if (jdkPaths != null && jdkPaths.length != 0) {
150 Path[] result = new Path[jdkPaths.length + paths.length];
151 for (int i = 0; i < jdkPaths.length; ++i) {
152 result[i] = jdkPaths[i].resolve("bin");
153 }
154 System.arraycopy(paths, 0, result, jdkPaths.length, paths.length);
155 paths = result;
156 }
157 }
158
159 private ExitCode run(PrintWriter log, Writer out, ProcessBuilder pb,
160 ActionParameters params) {
161 char[] lineChars = new char[40];
162 Arrays.fill(lineChars, '-');
163 String line = new String(lineChars);
164 Stopwatch stopwatch = new Stopwatch();
165 stopwatch.start();
166
167 log.printf("%s%n[%tF %<tT] %s%n%1$s%n", line, new Date(), pb.command());
168 Process process;
169 KillerTask killer;
170
171 ExitCode result = ExitCode.NEVER_STARTED;
172
173 try {
174 process = pb.start();
175 killer = new KillerTask(process);
176 killer.schedule(params.timeout);
177 Utils.copyStream(new InputStreamReader(process.getInputStream()),
178 out);
179 try {
180 result = new ExitCode(process.waitFor());
181 killer.cancel();
182 } catch (InterruptedException e) {
183 Thread.currentThread().interrupt();
184 if (!killer.cancel()) {
185 log.println(
186 "WARNING: interrupted when waiting for the tool:");
187 e.printStackTrace(log);
188 }
189 }
190 if (killer.hasTimedOut()) {
191 log.printf(
192 "WARNING: tool timed out: killed process after %d ms%n",
193 TimeUnit.MILLISECONDS.toMicros(params.timeout));
194 result = ExitCode.TIMED_OUT;
195 }
196 } catch (IOException e) {
197 e.printStackTrace(log);
198 result = ExitCode.LAUNCH_ERROR;
199 }
200
201 stopwatch.stop();
202 log.printf("%s%n[%tF %<tT] exit code : %d time : %d ms%n%1$s%n",
203 line, new Date(), result.value,
204 TimeUnit.MILLISECONDS.toSeconds(stopwatch.getElapsedTimeNs()));
205 return result;
206 }
207
208 public void runPatternAction(SimpleAction action, HtmlSection section) {
209 if (action != null) {
210 HtmlSection subSection = action.getSection(section);
211 PrintWriter log = subSection.getWriter();
212 ProcessBuilder pb = action.prepareProcess(log, this);
213 exec(subSection, pb, action.getParameters());
214 }
215 }
216
217 public void runPatternAction(PatternAction action, HtmlSection section,
218 String value) {
219 if (action != null) {
220 ProcessBuilder pb = action.prepareProcess(section, this, value);
221 HtmlSection subSection = action.getSection(section);
222 exec(subSection, pb, action.getParameters());
223 }
224 }
230 }
231 pb.redirectErrorStream(true);
232 boolean result = false;
233 String pidStr = "" + pid;
234 try {
235 Process process = pb.start();
236 try (BufferedReader reader = new BufferedReader(
237 new InputStreamReader(process.getInputStream()))) {
238 String line;
239 while ((line = reader.readLine()) != null){
240 if (pidStr.equals(line)) {
241 result = true;
242 }
243 }
244 }
245 process.waitFor();
246 } catch (IOException e) {
247 log.printf("WARNING: can't run jps : %s%n", e.getMessage());
248 e.printStackTrace(log);
249 } catch (InterruptedException e) {
250 Thread.currentThread().interrupt();
251 e.printStackTrace(log);
252 }
253 return result;
254 }
255
256 private static class KillerTask extends TimerTask {
257 private static final Timer WATCHDOG = new Timer("WATCHDOG", true);
258 private final Process process;
259 private boolean timedOut;
260
261 public KillerTask(Process process) {
262 this.process = process;
263 }
264
265 public void run() {
266 try {
267 process.exitValue();
268 } catch (IllegalThreadStateException e) {
269 // !prepareProcess.isAlive()
270 process.destroy();
271 timedOut = true;
272 }
273 }
274
275 public boolean hasTimedOut() {
276 return timedOut;
277 }
278
279 public void schedule(long timeout) {
280 if (timeout > 0) {
281 WATCHDOG.schedule(this, timeout);
282 }
283 }
284 }
285
286 private void exec(HtmlSection section, ProcessBuilder process,
287 ActionParameters params) {
288 if (process == null) {
289 return;
290 }
291 PrintWriter sectionWriter = section.getWriter();
292 if (params.repeat > 1) {
293 for (int i = 0, n = params.repeat; i < n; ++i) {
294 HtmlSection iteration = section.createChildren(
295 String.format("iteration_%d", i));
296 PrintWriter writer = iteration.getWriter();
297 ExitCode exitCode = run(writer, writer, process, params);
298 if (params.stopOnError && !ExitCode.OK.equals(exitCode)) {
299 sectionWriter.printf(
300 "ERROR: non zero exit code[%d] -- break.",
301 exitCode.value);
302 break;
303 }
304 try {
305 Thread.sleep(params.pause);
306 } catch (InterruptedException e) {
307 Thread.currentThread().interrupt();
308 e.printStackTrace(sectionWriter);
309 }
310 }
311 } else {
312 run(section.getWriter(), section.getWriter(), process, params);
313 }
314 }
315
316 /**
317 * Special values for prepareProcess exit code.
318 *
319 * <p>Can we clash with normal codes?
320 * On Solaris and Linux, only [0..255] are returned.
321 * On Windows, prepareProcess exit codes are stored in unsigned int.
322 * On MacOSX no limits (except it should fit C int type)
323 * are defined in the exit() man pages.
324 */
325 private static class ExitCode {
326 /** Process exits gracefully */
327 public static final ExitCode OK = new ExitCode(0);
328 /** Error launching prepareProcess */
329 public static final ExitCode LAUNCH_ERROR = new ExitCode(-1);
330 /** Application prepareProcess has been killed by watchdog due to timeout */
|
147
148 private void addJdks(Path[] jdkPaths) {
149 if (jdkPaths != null && jdkPaths.length != 0) {
150 Path[] result = new Path[jdkPaths.length + paths.length];
151 for (int i = 0; i < jdkPaths.length; ++i) {
152 result[i] = jdkPaths[i].resolve("bin");
153 }
154 System.arraycopy(paths, 0, result, jdkPaths.length, paths.length);
155 paths = result;
156 }
157 }
158
159 private ExitCode run(PrintWriter log, Writer out, ProcessBuilder pb,
160 ActionParameters params) {
161 char[] lineChars = new char[40];
162 Arrays.fill(lineChars, '-');
163 String line = new String(lineChars);
164 Stopwatch stopwatch = new Stopwatch();
165 stopwatch.start();
166
167 log.printf("%s%n[%tF %<tT] %s timeout=%s%n%1$s%n", line, new Date(), pb.command(), params.timeout);
168
169 Process process;
170 KillerTask killer;
171
172 ExitCode result = ExitCode.NEVER_STARTED;
173
174 try {
175 process = pb.start();
176 killer = new KillerTask(process);
177 killer.schedule(params.timeout);
178 Utils.copyStream(new InputStreamReader(process.getInputStream()),
179 out);
180 try {
181 result = new ExitCode(process.waitFor());
182 } catch (InterruptedException e) {
183 log.println("WARNING: interrupted when waiting for the tool:%n");
184 e.printStackTrace(log);
185 } finally {
186 killer.cancel();
187 }
188 if (killer.hasTimedOut()) {
189 log.printf(
190 "WARNING: tool timed out: killed process after %d ms%n",
191 params.timeout);
192 result = ExitCode.TIMED_OUT;
193 }
194 } catch (IOException e) {
195 log.printf("WARNING: caught IOException while running tool%n");
196 e.printStackTrace(log);
197 result = ExitCode.LAUNCH_ERROR;
198 }
199
200 stopwatch.stop();
201 log.printf("%s%n[%tF %<tT] exit code: %d time: %d ms%n%1$s%n",
202 line, new Date(), result.value,
203 TimeUnit.NANOSECONDS.toMillis(stopwatch.getElapsedTimeNs()));
204 return result;
205 }
206
207 public void runPatternAction(SimpleAction action, HtmlSection section) {
208 if (action != null) {
209 HtmlSection subSection = action.getSection(section);
210 PrintWriter log = subSection.getWriter();
211 ProcessBuilder pb = action.prepareProcess(log, this);
212 exec(subSection, pb, action.getParameters());
213 }
214 }
215
216 public void runPatternAction(PatternAction action, HtmlSection section,
217 String value) {
218 if (action != null) {
219 ProcessBuilder pb = action.prepareProcess(section, this, value);
220 HtmlSection subSection = action.getSection(section);
221 exec(subSection, pb, action.getParameters());
222 }
223 }
229 }
230 pb.redirectErrorStream(true);
231 boolean result = false;
232 String pidStr = "" + pid;
233 try {
234 Process process = pb.start();
235 try (BufferedReader reader = new BufferedReader(
236 new InputStreamReader(process.getInputStream()))) {
237 String line;
238 while ((line = reader.readLine()) != null){
239 if (pidStr.equals(line)) {
240 result = true;
241 }
242 }
243 }
244 process.waitFor();
245 } catch (IOException e) {
246 log.printf("WARNING: can't run jps : %s%n", e.getMessage());
247 e.printStackTrace(log);
248 } catch (InterruptedException e) {
249 log.printf("WARNING: interrupted%n");
250 e.printStackTrace(log);
251 }
252 return result;
253 }
254
255 private static class KillerTask extends TimerTask {
256 private static final Timer WATCHDOG = new Timer("WATCHDOG", true);
257 private final Process process;
258 private boolean timedOut;
259
260 public KillerTask(Process process) {
261 this.process = process;
262 }
263
264 public void run() {
265 try {
266 process.exitValue();
267 } catch (IllegalThreadStateException e) {
268 process.destroyForcibly();
269 timedOut = true;
270 }
271 }
272
273 public boolean hasTimedOut() {
274 return timedOut;
275 }
276
277 public void schedule(long timeout) {
278 if (timeout > 0) {
279 WATCHDOG.schedule(this, timeout);
280 }
281 }
282 }
283
284 private void exec(HtmlSection section, ProcessBuilder process,
285 ActionParameters params) {
286 if (process == null) {
287 return;
288 }
289 PrintWriter sectionWriter = section.getWriter();
290 if (params.repeat > 1) {
291 for (int i = 0, n = params.repeat; i < n; ++i) {
292 HtmlSection iteration = section.createChildren(
293 String.format("iteration_%d", i));
294 PrintWriter writer = iteration.getWriter();
295 ExitCode exitCode = run(writer, writer, process, params);
296 if (params.stopOnError && !ExitCode.OK.equals(exitCode)) {
297 sectionWriter.printf(
298 "ERROR: non zero exit code[%d] -- break.",
299 exitCode.value);
300 break;
301 }
302 // sleep, if this is not the last iteration
303 if (i < n - 1) {
304 try {
305 Thread.sleep(params.pause);
306 } catch (InterruptedException e) {
307 sectionWriter.printf(
308 "WARNING: interrupted while sleeping between invocations");
309 e.printStackTrace(sectionWriter);
310 }
311 }
312 }
313 } else {
314 run(section.getWriter(), section.getWriter(), process, params);
315 }
316 }
317
318 /**
319 * Special values for prepareProcess exit code.
320 *
321 * <p>Can we clash with normal codes?
322 * On Solaris and Linux, only [0..255] are returned.
323 * On Windows, prepareProcess exit codes are stored in unsigned int.
324 * On MacOSX no limits (except it should fit C int type)
325 * are defined in the exit() man pages.
326 */
327 private static class ExitCode {
328 /** Process exits gracefully */
329 public static final ExitCode OK = new ExitCode(0);
330 /** Error launching prepareProcess */
331 public static final ExitCode LAUNCH_ERROR = new ExitCode(-1);
332 /** Application prepareProcess has been killed by watchdog due to timeout */
|