GatherProcessInfoTimeoutHandler.java revision 1870:4aa2e64eff30
1/*
2 * Copyright (c) 2015, 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
24package jdk.test.failurehandler.jtreg;
25
26import com.sun.javatest.regtest.OS;
27import com.sun.javatest.regtest.TimeoutHandler;
28import jdk.test.failurehandler.*;
29
30import java.io.File;
31import java.io.FileWriter;
32import java.io.IOException;
33import java.io.PrintWriter;
34import java.lang.reflect.Field;
35import java.nio.file.Path;
36
37/**
38 * A timeout handler for jtreg, which gathers information about the timed out
39 * process and its children.
40 */
41public class GatherProcessInfoTimeoutHandler extends TimeoutHandler {
42    static {
43        try {
44            System.loadLibrary("timeoutHandler");
45        } catch (UnsatisfiedLinkError ignore) {
46            // not all os need timeoutHandler native-library
47        }
48    }
49    private static final String LOG_FILENAME = "processes.log";
50    private static final String OUTPUT_FILENAME = "processes.html";
51
52    public GatherProcessInfoTimeoutHandler(PrintWriter jtregLog, File outputDir,
53                                           File testJdk) {
54        super(jtregLog, outputDir, testJdk);
55    }
56
57    /**
58     * Runs various actions for jtreg timeout handler.
59     *
60     * <p>Please see method code for the actions.
61     */
62    @Override
63    protected void runActions(Process process, long pid)
64            throws InterruptedException {
65        Path workDir = outputDir.toPath();
66
67        String name = getClass().getName();
68        PrintWriter actionsLog;
69        try {
70            // try to open a separate file for aciton log
71            actionsLog = new PrintWriter(new FileWriter(
72                    workDir.resolve(LOG_FILENAME).toFile(), true));
73        } catch (IOException e) {
74            // use jtreg log as a fallback
75            actionsLog = log;
76            actionsLog.printf("ERROR: %s cannot open log file %s : %s", name,
77                    LOG_FILENAME, e.getMessage());
78        }
79        try {
80            actionsLog.printf("%s ---%n", name);
81
82            File output = workDir.resolve(OUTPUT_FILENAME).toFile();
83            try {
84                PrintWriter pw = new PrintWriter(new FileWriter(output, true));
85                runGatherer(name, workDir, actionsLog, pw, pid);
86            } catch (IOException e) {
87                actionsLog.printf("IOException: cannot open output file[%s] : %s",
88                        output, e.getMessage());
89                e.printStackTrace(actionsLog);
90            }
91        } finally {
92            actionsLog.printf("--- %s%n", name);
93            // don't close jtreg log
94            if (actionsLog != log) {
95                actionsLog.close();
96            } else {
97                log.flush();
98            }
99        }
100    }
101
102    @Override
103    protected long getProcessId(Process process) {
104        long result = super.getProcessId(process);
105        if (result == 0L) {
106            /* jtreg didn't find pid, most probably we are on JDK < 9
107               there is no Process::getPid */
108            if ("windows".equals(OS.current().family)) {
109                try {
110                    Field field = process.getClass().getDeclaredField("handle");
111                    boolean old = field.isAccessible();
112                    try {
113                        field.setAccessible(true);
114                        long handle = field.getLong(process);
115                        result = getWin32Pid(handle);
116                    } finally {
117                        field.setAccessible(old);
118                    }
119                } catch (ReflectiveOperationException e) {
120                    e.printStackTrace(log);
121                }
122            }
123        }
124        return result;
125    }
126
127    private native long getWin32Pid(long handle);
128
129    private void runGatherer(String name, Path workDir, PrintWriter log,
130                             PrintWriter out, long pid) {
131        try (HtmlPage html = new HtmlPage(out)) {
132            ProcessInfoGatherer gatherer = new GathererFactory(
133                    OS.current().family,
134                    workDir, log, testJdk.toPath()).getProcessInfoGatherer();
135            try (ElapsedTimePrinter timePrinter
136                         = new ElapsedTimePrinter(new Stopwatch(), name, log)) {
137                gatherer.gatherProcessInfo(html.getRootSection(), pid);
138            }
139        } catch (Throwable e) {
140            log.printf("ERROR: exception in timeout handler %s:", name);
141            e.printStackTrace(log);
142        }
143    }
144}
145