001/*
002 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package jdk.internal.jvmci.hotspot;
024
025import java.io.*;
026import java.lang.management.*;
027
028import jdk.internal.jvmci.options.*;
029
030/**
031 * An option that encapsulates and configures a print stream.
032 */
033public class PrintStreamOption extends OptionValue<String> {
034
035    public PrintStreamOption() {
036        super(null);
037    }
038
039    /**
040     * The print stream to which output will be written.
041     *
042     * Declared {@code volatile} to enable safe use of double-checked locking in
043     * {@link #getStream()} and {@link #setValue(Object)}.
044     */
045    private volatile PrintStream ps;
046
047    /**
048     * Replace any instance of %p with a an identifying name. Try to get it from the RuntimeMXBean
049     * name.
050     *
051     * @return the name of the file to log to
052     */
053    private String getFilename() {
054        String name = getValue();
055        if (name.contains("%p")) {
056            String runtimeName = ManagementFactory.getRuntimeMXBean().getName();
057            try {
058                int index = runtimeName.indexOf('@');
059                if (index != -1) {
060                    long pid = Long.parseLong(runtimeName.substring(0, index));
061                    runtimeName = Long.toString(pid);
062                }
063                name = name.replaceAll("%p", runtimeName);
064            } catch (NumberFormatException e) {
065
066            }
067        }
068        return name;
069    }
070
071    /**
072     * Gets the print stream configured by this option. If no file is configured, the print stream
073     * will output to {@link CompilerToVM#writeDebugOutput(byte[], int, int)}.
074     */
075    public PrintStream getStream() {
076        if (ps == null) {
077            if (getValue() != null) {
078                synchronized (this) {
079                    if (ps == null) {
080                        try {
081                            final boolean enableAutoflush = true;
082                            ps = new PrintStream(new FileOutputStream(getFilename()), enableAutoflush);
083                            /* Add the JVM and Java arguments to the log file to help identity it. */
084                            String inputArguments = String.join(" ", ManagementFactory.getRuntimeMXBean().getInputArguments());
085                            ps.println("VM Arguments: " + inputArguments);
086                            String cmd = System.getProperty("sun.java.command");
087                            if (cmd != null) {
088                                ps.println("sun.java.command=" + cmd);
089                            }
090                        } catch (FileNotFoundException e) {
091                            throw new RuntimeException("couldn't open file: " + getValue(), e);
092                        }
093                    }
094                }
095            } else {
096                OutputStream ttyOut = new OutputStream() {
097                    CompilerToVM vm;
098
099                    private CompilerToVM vm() {
100                        if (vm == null) {
101                            vm = HotSpotJVMCIRuntime.runtime().getCompilerToVM();
102                        }
103                        return vm;
104                    }
105
106                    @Override
107                    public void write(byte[] b, int off, int len) throws IOException {
108                        if (b == null) {
109                            throw new NullPointerException();
110                        } else if (off < 0 || off > b.length || len < 0 || (off + len) > b.length || (off + len) < 0) {
111                            throw new IndexOutOfBoundsException();
112                        } else if (len == 0) {
113                            return;
114                        }
115                        vm().writeDebugOutput(b, off, len);
116                    }
117
118                    @Override
119                    public void write(int b) throws IOException {
120                        write(new byte[]{(byte) b}, 0, 1);
121                    }
122
123                    @Override
124                    public void flush() throws IOException {
125                        vm().flushDebugOutput();
126                    }
127                };
128                ps = new PrintStream(ttyOut);
129            }
130        }
131        return ps;
132    }
133
134    @Override
135    public void setValue(Object v) {
136        if (ps != null) {
137            synchronized (this) {
138                if (ps != null) {
139                    ps.close();
140                    ps = null;
141                }
142            }
143        }
144        super.setValue(v);
145    }
146}