Fri, 12 Jul 2013 13:11:12 -0700
8020278: NPE in javadoc
Reviewed-by: mcimadamore, vromero
ohrstrom@1504 | 1 | /* |
ohrstrom@1504 | 2 | * Copyright (c) 2011-2012, Oracle and/or its affiliates. All rights reserved. |
ohrstrom@1504 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
ohrstrom@1504 | 4 | * |
ohrstrom@1504 | 5 | * This code is free software; you can redistribute it and/or modify it |
ohrstrom@1504 | 6 | * under the terms of the GNU General Public License version 2 only, as |
ohrstrom@1504 | 7 | * published by the Free Software Foundation. Oracle designates this |
ohrstrom@1504 | 8 | * particular file as subject to the "Classpath" exception as provided |
ohrstrom@1504 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
ohrstrom@1504 | 10 | * |
ohrstrom@1504 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
ohrstrom@1504 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
ohrstrom@1504 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
ohrstrom@1504 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
ohrstrom@1504 | 15 | * accompanied this code). |
ohrstrom@1504 | 16 | * |
ohrstrom@1504 | 17 | * You should have received a copy of the GNU General Public License version |
ohrstrom@1504 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
ohrstrom@1504 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
ohrstrom@1504 | 20 | * |
ohrstrom@1504 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
ohrstrom@1504 | 22 | * or visit www.oracle.com if you need additional information or have any |
ohrstrom@1504 | 23 | * questions. |
ohrstrom@1504 | 24 | */ |
ohrstrom@1504 | 25 | package com.sun.tools.sjavac.server; |
ohrstrom@1504 | 26 | |
ohrstrom@1504 | 27 | import java.io.BufferedReader; |
ohrstrom@1504 | 28 | import java.io.File; |
ohrstrom@1504 | 29 | import java.io.IOException; |
ohrstrom@1504 | 30 | import java.io.InputStreamReader; |
ohrstrom@1504 | 31 | import java.io.PrintWriter; |
ohrstrom@1504 | 32 | import java.io.FileNotFoundException; |
ohrstrom@1504 | 33 | import java.net.URI; |
ohrstrom@1504 | 34 | import java.util.HashSet; |
ohrstrom@1504 | 35 | import java.util.Set; |
ohrstrom@1504 | 36 | import java.util.HashMap; |
ohrstrom@1504 | 37 | import java.util.Map; |
ohrstrom@1504 | 38 | |
ohrstrom@1504 | 39 | import java.net.InetAddress; |
ohrstrom@1504 | 40 | import java.net.InetSocketAddress; |
ohrstrom@1504 | 41 | import java.net.ServerSocket; |
ohrstrom@1504 | 42 | import java.net.Socket; |
ohrstrom@1504 | 43 | import java.net.SocketAddress; |
ohrstrom@1504 | 44 | import java.util.ArrayList; |
ohrstrom@1504 | 45 | import java.util.Random; |
ohrstrom@1504 | 46 | |
ohrstrom@1504 | 47 | import com.sun.tools.sjavac.Util; |
ohrstrom@1504 | 48 | import com.sun.tools.sjavac.ProblemException; |
ohrstrom@1504 | 49 | import java.io.*; |
ohrstrom@1504 | 50 | import java.util.*; |
ohrstrom@1504 | 51 | |
ohrstrom@1504 | 52 | /** |
ohrstrom@1504 | 53 | * The JavacServer class contains methods both to setup a server that responds to requests and methods to connect to this server. |
ohrstrom@1504 | 54 | * |
ohrstrom@1504 | 55 | * <p><b>This is NOT part of any supported API. If you write code that depends on this, you do so at your own risk. This code and its internal interfaces are |
ohrstrom@1504 | 56 | * subject to change or deletion without notice.</b></p> |
ohrstrom@1504 | 57 | */ |
ohrstrom@1504 | 58 | public class JavacServer { |
ohrstrom@1504 | 59 | // Responding to this tcp/ip port on localhost. |
ohrstrom@1504 | 60 | |
ohrstrom@1504 | 61 | private final ServerSocket serverSocket; |
ohrstrom@1504 | 62 | // The secret cookie shared between server and client through the port file. |
ohrstrom@1504 | 63 | private final long myCookie; |
ohrstrom@1504 | 64 | // When the server was started. |
ohrstrom@1504 | 65 | private long serverStart; |
ohrstrom@1504 | 66 | // Accumulated build time for all requests, not counting idle time. |
ohrstrom@1504 | 67 | private long totalBuildTime; |
ohrstrom@1504 | 68 | // The javac server specific log file. |
ohrstrom@1504 | 69 | PrintWriter theLog; |
ohrstrom@1504 | 70 | // The compiler pool that maintains the compiler threads. |
ohrstrom@1504 | 71 | CompilerPool compilerPool; |
ohrstrom@1504 | 72 | // For the client, all port files fetched, one per started javac server. |
ohrstrom@1504 | 73 | // Though usually only one javac server is started by a client. |
ohrstrom@1504 | 74 | private static Map<String, PortFile> allPortFiles; |
ohrstrom@1504 | 75 | private static Map<String, Long> maxServerMemory; |
ohrstrom@1504 | 76 | final static int ERROR_FATAL = -1; |
ohrstrom@1504 | 77 | final static int ERROR_BUT_TRY_AGAIN = -4712; |
ohrstrom@1504 | 78 | final static String PROTOCOL_COOKIE_VERSION = "----THE-COOKIE-V2----"; |
ohrstrom@1504 | 79 | final static String PROTOCOL_CWD = "----THE-CWD----"; |
ohrstrom@1504 | 80 | final static String PROTOCOL_ID = "----THE-ID----"; |
ohrstrom@1504 | 81 | final static String PROTOCOL_ARGS = "----THE-ARGS----"; |
ohrstrom@1504 | 82 | final static String PROTOCOL_SOURCES_TO_COMPILE = "----THE-SOURCES-TO-COMPILE----"; |
ohrstrom@1504 | 83 | final static String PROTOCOL_VISIBLE_SOURCES = "----THE-VISIBLE-SOURCES----"; |
ohrstrom@1504 | 84 | final static String PROTOCOL_END = "----THE-END----"; |
ohrstrom@1504 | 85 | final static String PROTOCOL_STDOUT = "----THE-STDOUT----"; |
ohrstrom@1504 | 86 | final static String PROTOCOL_STDERR = "----THE-STDERR----"; |
ohrstrom@1504 | 87 | final static String PROTOCOL_PACKAGE_ARTIFACTS = "----THE-PACKAGE_ARTIFACTS----"; |
ohrstrom@1504 | 88 | final static String PROTOCOL_PACKAGE_DEPENDENCIES = "----THE-PACKAGE_DEPENDENCIES----"; |
ohrstrom@1504 | 89 | final static String PROTOCOL_PACKAGE_PUBLIC_APIS = "----THE-PACKAGE-PUBLIC-APIS----"; |
ohrstrom@1504 | 90 | final static String PROTOCOL_SYSINFO = "----THE-SYSINFO----"; |
ohrstrom@1504 | 91 | final static String PROTOCOL_RETURN_CODE = "----THE-RETURN-CODE----"; |
ohrstrom@1504 | 92 | // Check if the portfile is gone, every 5 seconds. |
ohrstrom@1504 | 93 | static int CHECK_PORTFILE_INTERVAL = 5; |
ohrstrom@1504 | 94 | // Wait 2 seconds for response, before giving up on javac server. |
ohrstrom@1504 | 95 | static int CONNECTION_TIMEOUT = 2; |
ohrstrom@1504 | 96 | static int WAIT_BETWEEN_CONNECT_ATTEMPTS = 1; |
ohrstrom@1504 | 97 | static int MAX_NUM_CONNECT_ATTEMPTS = 3; |
ohrstrom@1504 | 98 | |
ohrstrom@1504 | 99 | /** |
ohrstrom@1504 | 100 | * Acquire the port file. Synchronized since several threads inside an smart javac wrapper client acquires the same port file at the same time. |
ohrstrom@1504 | 101 | */ |
ohrstrom@1504 | 102 | private static synchronized PortFile getPortFile(String filename) throws FileNotFoundException { |
ohrstrom@1504 | 103 | if (allPortFiles == null) { |
ohrstrom@1504 | 104 | allPortFiles = new HashMap<String, PortFile>(); |
ohrstrom@1504 | 105 | } |
ohrstrom@1504 | 106 | PortFile pf = allPortFiles.get(filename); |
ohrstrom@1504 | 107 | if (pf == null) { |
ohrstrom@1504 | 108 | pf = new PortFile(filename); |
ohrstrom@1504 | 109 | allPortFiles.put(filename, pf); |
ohrstrom@1504 | 110 | } |
ohrstrom@1504 | 111 | return pf; |
ohrstrom@1504 | 112 | } |
ohrstrom@1504 | 113 | |
ohrstrom@1504 | 114 | /** |
ohrstrom@1504 | 115 | * Get the cookie used for this server. |
ohrstrom@1504 | 116 | */ |
ohrstrom@1504 | 117 | long getCookie() { |
ohrstrom@1504 | 118 | return myCookie; |
ohrstrom@1504 | 119 | } |
ohrstrom@1504 | 120 | |
ohrstrom@1504 | 121 | /** |
ohrstrom@1504 | 122 | * Get the port used for this server. |
ohrstrom@1504 | 123 | */ |
ohrstrom@1504 | 124 | int getPort() { |
ohrstrom@1504 | 125 | return serverSocket.getLocalPort(); |
ohrstrom@1504 | 126 | } |
ohrstrom@1504 | 127 | |
ohrstrom@1504 | 128 | /** |
ohrstrom@1504 | 129 | * Sum up the total build time for this javac server. |
ohrstrom@1504 | 130 | */ |
ohrstrom@1504 | 131 | public void addBuildTime(long inc) { |
ohrstrom@1504 | 132 | totalBuildTime += inc; |
ohrstrom@1504 | 133 | } |
ohrstrom@1504 | 134 | |
ohrstrom@1504 | 135 | /** |
ohrstrom@1504 | 136 | * Log this message. |
ohrstrom@1504 | 137 | */ |
ohrstrom@1504 | 138 | public void log(String msg) { |
ohrstrom@1504 | 139 | if (theLog != null) { |
ohrstrom@1504 | 140 | theLog.println(msg); |
ohrstrom@1504 | 141 | } else { |
ohrstrom@1504 | 142 | System.err.println(msg); |
ohrstrom@1504 | 143 | } |
ohrstrom@1504 | 144 | } |
ohrstrom@1504 | 145 | |
ohrstrom@1504 | 146 | /** |
ohrstrom@1504 | 147 | * Make sure the log is flushed. |
ohrstrom@1504 | 148 | */ |
ohrstrom@1504 | 149 | public void flushLog() { |
ohrstrom@1504 | 150 | if (theLog != null) { |
ohrstrom@1504 | 151 | theLog.flush(); |
ohrstrom@1504 | 152 | } |
ohrstrom@1504 | 153 | } |
ohrstrom@1504 | 154 | |
ohrstrom@1504 | 155 | /** |
ohrstrom@1504 | 156 | * Start a server using a settings string. Typically: "--startserver:portfile=/tmp/myserver,poolsize=3" and the string "portfile=/tmp/myserver,poolsize=3" |
ohrstrom@1504 | 157 | * is sent as the settings parameter. Returns 0 on success, -1 on failure. |
ohrstrom@1504 | 158 | */ |
ohrstrom@1504 | 159 | public static int startServer(String settings, PrintStream err) { |
ohrstrom@1504 | 160 | try { |
ohrstrom@1504 | 161 | String portfile = Util.extractStringOption("portfile", settings); |
ohrstrom@1504 | 162 | // The log file collects more javac server specific log information. |
ohrstrom@1504 | 163 | String logfile = Util.extractStringOption("logfile", settings); |
ohrstrom@1504 | 164 | // The stdouterr file collects all the System.out and System.err writes to disk. |
ohrstrom@1504 | 165 | String stdouterrfile = Util.extractStringOption("stdouterrfile", settings); |
ohrstrom@1504 | 166 | // We could perhaps use System.setOut and setErr here. |
ohrstrom@1504 | 167 | // But for the moment we rely on the client to spawn a shell where stdout |
ohrstrom@1504 | 168 | // and stderr are redirected already. |
ohrstrom@1504 | 169 | // The pool size is a limit the number of concurrent compiler threads used. |
ohrstrom@1504 | 170 | // The server might use less than these to avoid memory problems. |
ohrstrom@1504 | 171 | int poolsize = Util.extractIntOption("poolsize", settings); |
ohrstrom@1504 | 172 | if (poolsize <= 0) { |
ohrstrom@1504 | 173 | // If not set, default to the number of cores. |
ohrstrom@1504 | 174 | poolsize = Runtime.getRuntime().availableProcessors(); |
ohrstrom@1504 | 175 | } |
ohrstrom@1504 | 176 | |
ohrstrom@1504 | 177 | // How many seconds of inactivity will the server accept before quitting? |
ohrstrom@1504 | 178 | int keepalive = Util.extractIntOption("keepalive", settings); |
ohrstrom@1504 | 179 | if (keepalive <= 0) { |
ohrstrom@1504 | 180 | keepalive = 120; |
ohrstrom@1504 | 181 | } |
ohrstrom@1504 | 182 | // The port file is locked and the server port and cookie is written into it. |
ohrstrom@1504 | 183 | PortFile portFile = getPortFile(portfile); |
ohrstrom@1504 | 184 | JavacServer s; |
ohrstrom@1504 | 185 | |
ohrstrom@1504 | 186 | synchronized (portFile) { |
ohrstrom@1504 | 187 | portFile.lock(); |
ohrstrom@1504 | 188 | portFile.getValues(); |
ohrstrom@1504 | 189 | if (portFile.containsPortInfo()) { |
ohrstrom@1504 | 190 | err.println("Javac server not started because portfile exists!"); |
ohrstrom@1504 | 191 | portFile.unlock(); |
ohrstrom@1504 | 192 | return -1; |
ohrstrom@1504 | 193 | } |
ohrstrom@1504 | 194 | s = new JavacServer(poolsize, logfile); |
ohrstrom@1504 | 195 | portFile.setValues(s.getPort(), s.getCookie()); |
ohrstrom@1504 | 196 | portFile.unlock(); |
ohrstrom@1504 | 197 | } |
ohrstrom@1504 | 198 | |
ohrstrom@1504 | 199 | // Run the server. Will delete the port file when shutting down. |
ohrstrom@1504 | 200 | // It will shut down automatically when no new requests have come in |
ohrstrom@1504 | 201 | // during the last 125 seconds. |
ohrstrom@1504 | 202 | s.run(portFile, err, keepalive); |
ohrstrom@1504 | 203 | // The run loop for the server has exited. |
ohrstrom@1504 | 204 | return 0; |
ohrstrom@1504 | 205 | } catch (Exception e) { |
ohrstrom@1504 | 206 | e.printStackTrace(err); |
ohrstrom@1504 | 207 | return -1; |
ohrstrom@1504 | 208 | } |
ohrstrom@1504 | 209 | } |
ohrstrom@1504 | 210 | |
ohrstrom@1504 | 211 | /** |
ohrstrom@1504 | 212 | * Dispatch a compilation request to a javac server. |
ohrstrom@1504 | 213 | * |
ohrstrom@1504 | 214 | * @param args are the command line args to javac and is allowed to contain source files, @file and other command line options to javac. |
ohrstrom@1504 | 215 | * |
ohrstrom@1504 | 216 | * The generated classes, h files and other artifacts from the javac invocation are stored by the javac server to disk. |
ohrstrom@1504 | 217 | * |
ohrstrom@1504 | 218 | * @param sources_to_compile The sources to compile. |
ohrstrom@1504 | 219 | * |
ohrstrom@1504 | 220 | * @param visibleSources If visible sources has a non zero size, then visible_sources are the only files in the file system that the javac server can see! |
ohrstrom@1504 | 221 | * (Sources to compile are always visible.) The visible sources are those supplied by the (filtered) -sourcepath |
ohrstrom@1504 | 222 | * |
ohrstrom@1504 | 223 | * @param visibleClasses If visible classes for a specific root/jar has a non zero size, then visible_classes are the only class files that the javac server |
ohrstrom@1504 | 224 | * can see, in that root/jar. It maps from a classpath root or a jar file to the set of visible classes for that root/jar. |
ohrstrom@1504 | 225 | * |
ohrstrom@1504 | 226 | * The server return meta data about the build in the following parameters. |
ohrstrom@1504 | 227 | * @param package_artifacts, map from package name to set of created artifacts for that package. |
ohrstrom@1504 | 228 | * @param package_dependencies, map from package name to set of packages that it depends upon. |
ohrstrom@1504 | 229 | * @param package_pubapis, map from package name to unique string identifying its pub api. |
ohrstrom@1504 | 230 | */ |
ohrstrom@1504 | 231 | public static int useServer(String settings, String[] args, |
ohrstrom@1504 | 232 | Set<URI> sourcesToCompile, |
ohrstrom@1504 | 233 | Set<URI> visibleSources, |
ohrstrom@1504 | 234 | Map<URI, Set<String>> visibleClasses, |
ohrstrom@1504 | 235 | Map<String, Set<URI>> packageArtifacts, |
ohrstrom@1504 | 236 | Map<String, Set<String>> packageDependencies, |
ohrstrom@1504 | 237 | Map<String, String> packagePubapis, |
ohrstrom@1504 | 238 | SysInfo sysinfo, |
ohrstrom@1504 | 239 | PrintStream out, |
ohrstrom@1504 | 240 | PrintStream err) { |
ohrstrom@1504 | 241 | try { |
ohrstrom@1504 | 242 | // The id can perhaps be used in the future by the javac server to reuse the |
ohrstrom@1504 | 243 | // JavaCompiler instance for several compiles using the same id. |
ohrstrom@1504 | 244 | String id = Util.extractStringOption("id", settings); |
ohrstrom@1504 | 245 | String portfile = Util.extractStringOption("portfile", settings); |
ohrstrom@1504 | 246 | String logfile = Util.extractStringOption("logfile", settings); |
ohrstrom@1504 | 247 | String stdouterrfile = Util.extractStringOption("stdouterrfile", settings); |
ohrstrom@1504 | 248 | String background = Util.extractStringOption("background", settings); |
ohrstrom@1504 | 249 | if (background == null || !background.equals("false")) { |
ohrstrom@1504 | 250 | background = "true"; |
ohrstrom@1504 | 251 | } |
ohrstrom@1504 | 252 | // The sjavac option specifies how the server part of sjavac is spawned. |
ohrstrom@1504 | 253 | // If you have the experimental sjavac in your path, you are done. If not, you have |
ohrstrom@1504 | 254 | // to point to a com.sun.tools.sjavac.Main that supports --startserver |
ohrstrom@1504 | 255 | // for example by setting: sjavac=java%20-jar%20...javac.jar%com.sun.tools.sjavac.Main |
ohrstrom@1504 | 256 | String sjavac = Util.extractStringOption("sjavac", settings); |
ohrstrom@1504 | 257 | int poolsize = Util.extractIntOption("poolsize", settings); |
ohrstrom@1504 | 258 | int keepalive = Util.extractIntOption("keepalive", settings); |
ohrstrom@1504 | 259 | |
ohrstrom@1504 | 260 | if (keepalive <= 0) { |
ohrstrom@1504 | 261 | // Default keepalive for server is 120 seconds. |
ohrstrom@1504 | 262 | // I.e. it will accept 120 seconds of inactivity before quitting. |
ohrstrom@1504 | 263 | keepalive = 120; |
ohrstrom@1504 | 264 | } |
ohrstrom@1504 | 265 | if (portfile == null) { |
ohrstrom@1504 | 266 | err.println("No portfile was specified!"); |
ohrstrom@1504 | 267 | return -1; |
ohrstrom@1504 | 268 | } |
ohrstrom@1504 | 269 | if (logfile == null) { |
ohrstrom@1504 | 270 | logfile = portfile + ".javaclog"; |
ohrstrom@1504 | 271 | } |
ohrstrom@1504 | 272 | if (stdouterrfile == null) { |
ohrstrom@1504 | 273 | stdouterrfile = portfile + ".stdouterr"; |
ohrstrom@1504 | 274 | } |
ohrstrom@1504 | 275 | // Default to sjavac and hope it is in the path. |
ohrstrom@1504 | 276 | if (sjavac == null) { |
ohrstrom@1504 | 277 | sjavac = "sjavac"; |
ohrstrom@1504 | 278 | } |
ohrstrom@1504 | 279 | |
ohrstrom@1504 | 280 | int attempts = 0; |
ohrstrom@1504 | 281 | int rc = -1; |
ohrstrom@1504 | 282 | do { |
ohrstrom@1504 | 283 | PortFile port_file = getPortFile(portfile); |
ohrstrom@1504 | 284 | synchronized (port_file) { |
ohrstrom@1504 | 285 | port_file.lock(); |
ohrstrom@1504 | 286 | port_file.getValues(); |
ohrstrom@1504 | 287 | port_file.unlock(); |
ohrstrom@1504 | 288 | } |
ohrstrom@1504 | 289 | if (!port_file.containsPortInfo()) { |
ohrstrom@1504 | 290 | String cmd = fork(sjavac, port_file.getFilename(), logfile, poolsize, keepalive, err, stdouterrfile, background); |
ohrstrom@1504 | 291 | |
ohrstrom@1504 | 292 | if (background.equals("true") && !port_file.waitForValidValues()) { |
ohrstrom@1504 | 293 | // Ouch the server did not start! Lets print its stdouterrfile and the command used. |
ohrstrom@1504 | 294 | printFailedAttempt(cmd, stdouterrfile, err); |
ohrstrom@1504 | 295 | // And give up. |
ohrstrom@1504 | 296 | return -1; |
ohrstrom@1504 | 297 | } |
ohrstrom@1504 | 298 | } |
ohrstrom@1504 | 299 | rc = connectAndCompile(port_file, id, args, sourcesToCompile, visibleSources, |
ohrstrom@1504 | 300 | packageArtifacts, packageDependencies, packagePubapis, sysinfo, |
ohrstrom@1504 | 301 | out, err); |
ohrstrom@1504 | 302 | // Try again until we manage to connect. Any error after that |
ohrstrom@1504 | 303 | // will cause the compilation to fail. |
ohrstrom@1504 | 304 | if (rc == ERROR_BUT_TRY_AGAIN) { |
ohrstrom@1504 | 305 | // We could not connect to the server. Try again. |
ohrstrom@1504 | 306 | attempts++; |
ohrstrom@1504 | 307 | try { |
ohrstrom@1504 | 308 | Thread.sleep(WAIT_BETWEEN_CONNECT_ATTEMPTS); |
ohrstrom@1504 | 309 | } catch (InterruptedException e) { |
ohrstrom@1504 | 310 | } |
ohrstrom@1504 | 311 | } |
ohrstrom@1504 | 312 | } while (rc == ERROR_BUT_TRY_AGAIN && attempts < MAX_NUM_CONNECT_ATTEMPTS); |
ohrstrom@1504 | 313 | return rc; |
ohrstrom@1504 | 314 | } catch (Exception e) { |
ohrstrom@1504 | 315 | e.printStackTrace(err); |
ohrstrom@1504 | 316 | return -1; |
ohrstrom@1504 | 317 | } |
ohrstrom@1504 | 318 | } |
ohrstrom@1504 | 319 | |
ohrstrom@1504 | 320 | private static void printFailedAttempt(String cmd, String f, PrintStream err) { |
ohrstrom@1504 | 321 | err.println("---- Failed to start javac server with this command -----"); |
ohrstrom@1504 | 322 | err.println(cmd); |
ohrstrom@1504 | 323 | try { |
ohrstrom@1504 | 324 | BufferedReader in = new BufferedReader(new FileReader(f)); |
ohrstrom@1504 | 325 | err.println("---- stdout/stderr output from attempt to start javac server -----"); |
ohrstrom@1504 | 326 | for (;;) { |
ohrstrom@1504 | 327 | String l = in.readLine(); |
ohrstrom@1504 | 328 | if (l == null) { |
ohrstrom@1504 | 329 | break; |
ohrstrom@1504 | 330 | } |
ohrstrom@1504 | 331 | err.println(l); |
ohrstrom@1504 | 332 | } |
ohrstrom@1504 | 333 | err.println("------------------------------------------------------------------"); |
ohrstrom@1504 | 334 | } catch (Exception e) { |
ohrstrom@1504 | 335 | err.println("The stdout/stderr output in file " + f + " does not exist and the server did not start."); |
ohrstrom@1504 | 336 | } |
ohrstrom@1504 | 337 | } |
ohrstrom@1504 | 338 | |
ohrstrom@1504 | 339 | /** |
ohrstrom@1504 | 340 | * Spawn the server instance. |
ohrstrom@1504 | 341 | */ |
ohrstrom@1504 | 342 | |
ohrstrom@1504 | 343 | private JavacServer(int poolSize, String logfile) throws IOException { |
ohrstrom@1504 | 344 | serverStart = System.currentTimeMillis(); |
ohrstrom@1504 | 345 | // Create a server socket on a random port that is bound to the localhost/127.0.0.1 interface. |
ohrstrom@1504 | 346 | // I.e only local processes can connect to this port. |
ohrstrom@1504 | 347 | serverSocket = new ServerSocket(0, 128, InetAddress.getByName(null)); |
ohrstrom@1504 | 348 | compilerPool = new CompilerPool(poolSize, this); |
ohrstrom@1504 | 349 | Random rnd = new Random(); |
ohrstrom@1504 | 350 | myCookie = rnd.nextLong(); |
ohrstrom@1504 | 351 | theLog = new PrintWriter(logfile); |
ohrstrom@1504 | 352 | log("Javac server started. port=" + getPort() + " date=" + (new java.util.Date()) + " with poolsize=" + poolSize); |
ohrstrom@1504 | 353 | flushLog(); |
ohrstrom@1504 | 354 | } |
ohrstrom@1504 | 355 | |
ohrstrom@1504 | 356 | /** |
ohrstrom@1504 | 357 | * Fork a background process. Returns the command line used that can be printed if something failed. |
ohrstrom@1504 | 358 | */ |
ohrstrom@1504 | 359 | private static String fork(String sjavac, String portfile, String logfile, int poolsize, int keepalive, |
ohrstrom@1504 | 360 | final PrintStream err, String stdouterrfile, String background) |
ohrstrom@1504 | 361 | throws IOException, ProblemException { |
ohrstrom@1504 | 362 | if (stdouterrfile != null && stdouterrfile.trim().equals("")) { |
ohrstrom@1504 | 363 | stdouterrfile = null; |
ohrstrom@1504 | 364 | } |
ohrstrom@1504 | 365 | final String startserver = "--startserver:portfile=" + portfile + ",logfile=" + logfile + ",stdouterrfile=" + stdouterrfile + ",poolsize=" + poolsize + ",keepalive="+ keepalive; |
ohrstrom@1504 | 366 | |
ohrstrom@1504 | 367 | if (background.equals("true")) { |
ohrstrom@1504 | 368 | sjavac += "%20" + startserver; |
ohrstrom@1504 | 369 | sjavac = sjavac.replaceAll("%20", " "); |
ohrstrom@1504 | 370 | sjavac = sjavac.replaceAll("%2C", ","); |
ohrstrom@1504 | 371 | // If the java/sh/cmd launcher fails the failure will be captured by stdouterr because of the redirection here. |
ohrstrom@1504 | 372 | String[] cmd = {"/bin/sh", "-c", sjavac + " >> " + stdouterrfile + " 2>&1"}; |
ohrstrom@1504 | 373 | if (!(new File("/bin/sh")).canExecute()) { |
ohrstrom@1504 | 374 | ArrayList<String> wincmd = new ArrayList<String>(); |
ohrstrom@1504 | 375 | wincmd.add("cmd"); |
ohrstrom@1504 | 376 | wincmd.add("/c"); |
ohrstrom@1504 | 377 | wincmd.add("start"); |
ohrstrom@1504 | 378 | wincmd.add("cmd"); |
ohrstrom@1504 | 379 | wincmd.add("/c"); |
ohrstrom@1504 | 380 | wincmd.add(sjavac + " >> " + stdouterrfile + " 2>&1"); |
ohrstrom@1504 | 381 | cmd = wincmd.toArray(new String[wincmd.size()]); |
ohrstrom@1504 | 382 | } |
ohrstrom@1504 | 383 | Process pp = null; |
ohrstrom@1504 | 384 | try { |
ohrstrom@1504 | 385 | pp = Runtime.getRuntime().exec(cmd); |
ohrstrom@1504 | 386 | } catch (Exception e) { |
ohrstrom@1504 | 387 | e.printStackTrace(err); |
ohrstrom@1504 | 388 | e.printStackTrace(new PrintWriter(stdouterrfile)); |
ohrstrom@1504 | 389 | } |
ohrstrom@1504 | 390 | StringBuilder rs = new StringBuilder(); |
ohrstrom@1504 | 391 | for (String s : cmd) { |
ohrstrom@1504 | 392 | rs.append(s + " "); |
ohrstrom@1504 | 393 | } |
ohrstrom@1504 | 394 | return rs.toString(); |
ohrstrom@1504 | 395 | } |
ohrstrom@1504 | 396 | |
ohrstrom@1504 | 397 | // Do not spawn a background server, instead run it within the same JVM. |
ohrstrom@1504 | 398 | Thread t = new Thread() { |
ohrstrom@1504 | 399 | @Override |
ohrstrom@1504 | 400 | public void run() { |
ohrstrom@1504 | 401 | try { |
ohrstrom@1504 | 402 | JavacServer.startServer(startserver, err); |
ohrstrom@1504 | 403 | } catch (Throwable t) { |
ohrstrom@1504 | 404 | t.printStackTrace(err); |
ohrstrom@1504 | 405 | } |
ohrstrom@1504 | 406 | } |
ohrstrom@1504 | 407 | }; |
ohrstrom@1504 | 408 | t.start(); |
ohrstrom@1504 | 409 | return ""; |
ohrstrom@1504 | 410 | } |
ohrstrom@1504 | 411 | |
ohrstrom@1504 | 412 | /** |
ohrstrom@1504 | 413 | * Expect this key on the next line read from the reader. |
ohrstrom@1504 | 414 | */ |
ohrstrom@1504 | 415 | private static boolean expect(BufferedReader in, String key) throws IOException { |
ohrstrom@1504 | 416 | String s = in.readLine(); |
ohrstrom@1504 | 417 | if (s != null && s.equals(key)) { |
ohrstrom@1504 | 418 | return true; |
ohrstrom@1504 | 419 | } |
ohrstrom@1504 | 420 | return false; |
ohrstrom@1504 | 421 | } |
ohrstrom@1504 | 422 | |
ohrstrom@1504 | 423 | /** |
ohrstrom@1504 | 424 | * Make a request to the server only to get the maximum possible heap size to use for compilations. |
ohrstrom@1504 | 425 | * |
ohrstrom@1504 | 426 | * @param port_file The port file used to synchronize creation of this server. |
ohrstrom@1504 | 427 | * @param id The identify of the compilation. |
ohrstrom@1504 | 428 | * @param out Standard out information. |
ohrstrom@1504 | 429 | * @param err Standard err information. |
ohrstrom@1504 | 430 | * @return The maximum heap size in bytes. |
ohrstrom@1504 | 431 | */ |
ohrstrom@1504 | 432 | public static SysInfo connectGetSysInfo(String serverSettings, PrintStream out, PrintStream err) { |
ohrstrom@1504 | 433 | SysInfo sysinfo = new SysInfo(-1, -1); |
ohrstrom@1504 | 434 | String id = Util.extractStringOption("id", serverSettings); |
ohrstrom@1504 | 435 | String portfile = Util.extractStringOption("portfile", serverSettings); |
ohrstrom@1504 | 436 | try { |
ohrstrom@1504 | 437 | PortFile pf = getPortFile(portfile); |
ohrstrom@1504 | 438 | useServer(serverSettings, new String[0], |
ohrstrom@1504 | 439 | new HashSet<URI>(), |
ohrstrom@1504 | 440 | new HashSet<URI>(), |
ohrstrom@1504 | 441 | new HashMap<URI, Set<String>>(), |
ohrstrom@1504 | 442 | new HashMap<String, Set<URI>>(), |
ohrstrom@1504 | 443 | new HashMap<String, Set<String>>(), |
ohrstrom@1504 | 444 | new HashMap<String, String>(), |
ohrstrom@1504 | 445 | sysinfo, out, err); |
ohrstrom@1504 | 446 | } catch (Exception e) { |
ohrstrom@1504 | 447 | e.printStackTrace(err); |
ohrstrom@1504 | 448 | } |
ohrstrom@1504 | 449 | return sysinfo; |
ohrstrom@1504 | 450 | } |
ohrstrom@1504 | 451 | |
ohrstrom@1504 | 452 | /** |
ohrstrom@1504 | 453 | * Connect and compile using the javac server settings and the args. When using more advanced features, the sources_to_compile and visible_sources are |
ohrstrom@1504 | 454 | * supplied to the server and meta data is returned in package_artifacts, package_dependencies and package_pubapis. |
ohrstrom@1504 | 455 | */ |
ohrstrom@1504 | 456 | private static int connectAndCompile(PortFile portFile, String id, String[] args, |
ohrstrom@1504 | 457 | Set<URI> sourcesToCompile, |
ohrstrom@1504 | 458 | Set<URI> visibleSources, |
ohrstrom@1504 | 459 | Map<String, Set<URI>> packageArtifacts, |
ohrstrom@1504 | 460 | Map<String, Set<String>> packageDependencies, |
ohrstrom@1504 | 461 | Map<String, String> packagePublicApis, |
ohrstrom@1504 | 462 | SysInfo sysinfo, |
ohrstrom@1504 | 463 | PrintStream out, |
ohrstrom@1504 | 464 | PrintStream err) { |
ohrstrom@1504 | 465 | int rc = -3; |
ohrstrom@1504 | 466 | try { |
ohrstrom@1504 | 467 | int port = portFile.getPort(); |
ohrstrom@1504 | 468 | if (port == 0) { |
ohrstrom@1504 | 469 | return ERROR_BUT_TRY_AGAIN; |
ohrstrom@1504 | 470 | } |
ohrstrom@1504 | 471 | long cookie = portFile.getCookie(); |
ohrstrom@1504 | 472 | |
ohrstrom@1504 | 473 | // Acquire the localhost/127.0.0.1 address. |
ohrstrom@1504 | 474 | InetAddress addr = InetAddress.getByName(null); |
ohrstrom@1504 | 475 | SocketAddress sockaddr = new InetSocketAddress(addr, port); |
ohrstrom@1504 | 476 | Socket sock = new Socket(); |
ohrstrom@1504 | 477 | int timeoutMs = CONNECTION_TIMEOUT * 1000; |
ohrstrom@1504 | 478 | try { |
ohrstrom@1504 | 479 | sock.connect(sockaddr, timeoutMs); |
ohrstrom@1504 | 480 | } catch (java.net.ConnectException e) { |
ohrstrom@1504 | 481 | err.println("Could not connect to javac server found in portfile: " + portFile.getFilename() + " " + e); |
ohrstrom@1504 | 482 | return ERROR_BUT_TRY_AGAIN; |
ohrstrom@1504 | 483 | } |
ohrstrom@1504 | 484 | if (!sock.isConnected()) { |
ohrstrom@1504 | 485 | err.println("Could not connect to javac server found in portfile: " + portFile.getFilename()); |
ohrstrom@1504 | 486 | return ERROR_BUT_TRY_AGAIN; |
ohrstrom@1504 | 487 | } |
ohrstrom@1504 | 488 | BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream())); |
ohrstrom@1504 | 489 | PrintWriter sockout = new PrintWriter(sock.getOutputStream()); |
ohrstrom@1504 | 490 | |
ohrstrom@1504 | 491 | sockout.println(PROTOCOL_COOKIE_VERSION); |
ohrstrom@1504 | 492 | sockout.println("" + cookie); |
ohrstrom@1504 | 493 | sockout.println(PROTOCOL_CWD); |
ohrstrom@1504 | 494 | sockout.println(System.getProperty("user.dir")); |
ohrstrom@1504 | 495 | sockout.println(PROTOCOL_ID); |
ohrstrom@1504 | 496 | sockout.println(id); |
ohrstrom@1504 | 497 | sockout.println(PROTOCOL_ARGS); |
ohrstrom@1504 | 498 | for (String s : args) { |
ohrstrom@1504 | 499 | StringBuffer buf = new StringBuffer(); |
ohrstrom@1504 | 500 | String[] paths = s.split(File.pathSeparator); |
ohrstrom@1504 | 501 | int c = 0; |
ohrstrom@1504 | 502 | for (String path : paths) { |
ohrstrom@1504 | 503 | File f = new File(path); |
ohrstrom@1504 | 504 | if (f.isFile() || f.isDirectory()) { |
ohrstrom@1504 | 505 | buf.append(f.getAbsolutePath()); |
ohrstrom@1504 | 506 | c++; |
ohrstrom@1504 | 507 | if (c < paths.length) { |
ohrstrom@1504 | 508 | buf.append(File.pathSeparator); |
ohrstrom@1504 | 509 | } |
ohrstrom@1504 | 510 | } else { |
ohrstrom@1504 | 511 | buf = new StringBuffer(s); |
ohrstrom@1504 | 512 | break; |
ohrstrom@1504 | 513 | } |
ohrstrom@1504 | 514 | } |
ohrstrom@1504 | 515 | sockout.println(buf.toString()); |
ohrstrom@1504 | 516 | } |
ohrstrom@1504 | 517 | sockout.println(PROTOCOL_SOURCES_TO_COMPILE); |
ohrstrom@1504 | 518 | for (URI uri : sourcesToCompile) { |
ohrstrom@1504 | 519 | sockout.println(uri.toString()); |
ohrstrom@1504 | 520 | } |
ohrstrom@1504 | 521 | sockout.println(PROTOCOL_VISIBLE_SOURCES); |
ohrstrom@1504 | 522 | for (URI uri : visibleSources) { |
ohrstrom@1504 | 523 | sockout.println(uri.toString()); |
ohrstrom@1504 | 524 | } |
ohrstrom@1504 | 525 | sockout.println(PROTOCOL_END); |
ohrstrom@1504 | 526 | sockout.flush(); |
ohrstrom@1504 | 527 | |
ohrstrom@1504 | 528 | StringBuffer stdout = new StringBuffer(); |
ohrstrom@1504 | 529 | StringBuffer stderr = new StringBuffer(); |
ohrstrom@1504 | 530 | |
ohrstrom@1504 | 531 | if (!expect(in, PROTOCOL_STDOUT)) { |
ohrstrom@1504 | 532 | return ERROR_FATAL; |
ohrstrom@1504 | 533 | } |
ohrstrom@1504 | 534 | // Load stdout |
ohrstrom@1504 | 535 | for (;;) { |
ohrstrom@1504 | 536 | String l = in.readLine(); |
ohrstrom@1504 | 537 | if (l == null) { |
ohrstrom@1504 | 538 | return ERROR_FATAL; |
ohrstrom@1504 | 539 | } |
ohrstrom@1504 | 540 | if (l.equals(PROTOCOL_STDERR)) { |
ohrstrom@1504 | 541 | break; |
ohrstrom@1504 | 542 | } |
ohrstrom@1504 | 543 | stdout.append(l); |
ohrstrom@1504 | 544 | stdout.append('\n'); |
ohrstrom@1504 | 545 | } |
ohrstrom@1504 | 546 | // Load stderr |
ohrstrom@1504 | 547 | for (;;) { |
ohrstrom@1504 | 548 | String l = in.readLine(); |
ohrstrom@1504 | 549 | if (l == null) { |
ohrstrom@1504 | 550 | return ERROR_FATAL; |
ohrstrom@1504 | 551 | } |
ohrstrom@1504 | 552 | if (l.equals(PROTOCOL_PACKAGE_ARTIFACTS)) { |
ohrstrom@1504 | 553 | break; |
ohrstrom@1504 | 554 | } |
ohrstrom@1504 | 555 | stderr.append(l); |
ohrstrom@1504 | 556 | stderr.append('\n'); |
ohrstrom@1504 | 557 | } |
ohrstrom@1504 | 558 | // Load the package artifacts |
ohrstrom@1504 | 559 | Set<URI> lastUriSet = null; |
ohrstrom@1504 | 560 | for (;;) { |
ohrstrom@1504 | 561 | String l = in.readLine(); |
ohrstrom@1504 | 562 | if (l == null) { |
ohrstrom@1504 | 563 | return ERROR_FATAL; |
ohrstrom@1504 | 564 | } |
ohrstrom@1504 | 565 | if (l.equals(PROTOCOL_PACKAGE_DEPENDENCIES)) { |
ohrstrom@1504 | 566 | break; |
ohrstrom@1504 | 567 | } |
ohrstrom@1504 | 568 | if (l.length() > 1 && l.charAt(0) == '+') { |
ohrstrom@1504 | 569 | String pkg = l.substring(1); |
ohrstrom@1504 | 570 | lastUriSet = new HashSet<URI>(); |
ohrstrom@1504 | 571 | packageArtifacts.put(pkg, lastUriSet); |
ohrstrom@1504 | 572 | } else if (l.length() > 1 && lastUriSet != null) { |
ohrstrom@1504 | 573 | lastUriSet.add(new URI(l.substring(1))); |
ohrstrom@1504 | 574 | } |
ohrstrom@1504 | 575 | } |
ohrstrom@1504 | 576 | // Load package dependencies |
ohrstrom@1504 | 577 | Set<String> lastPackageSet = null; |
ohrstrom@1504 | 578 | for (;;) { |
ohrstrom@1504 | 579 | String l = in.readLine(); |
ohrstrom@1504 | 580 | if (l == null) { |
ohrstrom@1504 | 581 | return ERROR_FATAL; |
ohrstrom@1504 | 582 | } |
ohrstrom@1504 | 583 | if (l.equals(PROTOCOL_PACKAGE_PUBLIC_APIS)) { |
ohrstrom@1504 | 584 | break; |
ohrstrom@1504 | 585 | } |
ohrstrom@1504 | 586 | if (l.length() > 1 && l.charAt(0) == '+') { |
ohrstrom@1504 | 587 | String pkg = l.substring(1); |
ohrstrom@1504 | 588 | lastPackageSet = new HashSet<String>(); |
ohrstrom@1504 | 589 | packageDependencies.put(pkg, lastPackageSet); |
ohrstrom@1504 | 590 | } else if (l.length() > 1 && lastPackageSet != null) { |
ohrstrom@1504 | 591 | lastPackageSet.add(l.substring(1)); |
ohrstrom@1504 | 592 | } |
ohrstrom@1504 | 593 | } |
ohrstrom@1504 | 594 | // Load package pubapis |
ohrstrom@1504 | 595 | Map<String, StringBuffer> tmp = new HashMap<String, StringBuffer>(); |
ohrstrom@1504 | 596 | StringBuffer lastPublicApi = null; |
ohrstrom@1504 | 597 | for (;;) { |
ohrstrom@1504 | 598 | String l = in.readLine(); |
ohrstrom@1504 | 599 | if (l == null) { |
ohrstrom@1504 | 600 | return ERROR_FATAL; |
ohrstrom@1504 | 601 | } |
ohrstrom@1504 | 602 | if (l.equals(PROTOCOL_SYSINFO)) { |
ohrstrom@1504 | 603 | break; |
ohrstrom@1504 | 604 | } |
ohrstrom@1504 | 605 | if (l.length() > 1 && l.charAt(0) == '+') { |
ohrstrom@1504 | 606 | String pkg = l.substring(1); |
ohrstrom@1504 | 607 | lastPublicApi = new StringBuffer(); |
ohrstrom@1504 | 608 | tmp.put(pkg, lastPublicApi); |
ohrstrom@1504 | 609 | } else if (l.length() > 1 && lastPublicApi != null) { |
ohrstrom@1504 | 610 | lastPublicApi.append(l.substring(1)); |
ohrstrom@1504 | 611 | lastPublicApi.append("\n"); |
ohrstrom@1504 | 612 | } |
ohrstrom@1504 | 613 | } |
ohrstrom@1504 | 614 | for (String p : tmp.keySet()) { |
ohrstrom@1504 | 615 | assert (packagePublicApis.get(p) == null); |
ohrstrom@1504 | 616 | String api = tmp.get(p).toString(); |
ohrstrom@1504 | 617 | packagePublicApis.put(p, api); |
ohrstrom@1504 | 618 | } |
ohrstrom@1504 | 619 | // Now reading the max memory possible. |
ohrstrom@1504 | 620 | for (;;) { |
ohrstrom@1504 | 621 | String l = in.readLine(); |
ohrstrom@1504 | 622 | if (l == null) { |
ohrstrom@1504 | 623 | return ERROR_FATAL; |
ohrstrom@1504 | 624 | } |
ohrstrom@1504 | 625 | if (l.equals(PROTOCOL_RETURN_CODE)) { |
ohrstrom@1504 | 626 | break; |
ohrstrom@1504 | 627 | } |
ohrstrom@1504 | 628 | if (l.startsWith("num_cores=") && sysinfo != null) { |
ohrstrom@1504 | 629 | sysinfo.numCores = Integer.parseInt(l.substring(10)); |
ohrstrom@1504 | 630 | } |
ohrstrom@1504 | 631 | if (l.startsWith("max_memory=") && sysinfo != null) { |
ohrstrom@1504 | 632 | sysinfo.maxMemory = Long.parseLong(l.substring(11)); |
ohrstrom@1504 | 633 | } |
ohrstrom@1504 | 634 | } |
ohrstrom@1504 | 635 | String l = in.readLine(); |
ohrstrom@1504 | 636 | if (l == null) { |
ohrstrom@1504 | 637 | err.println("No return value from the server!"); |
ohrstrom@1504 | 638 | return ERROR_FATAL; |
ohrstrom@1504 | 639 | } |
ohrstrom@1504 | 640 | rc = Integer.parseInt(l); |
ohrstrom@1504 | 641 | out.print(stdout); |
ohrstrom@1504 | 642 | err.print(stderr); |
ohrstrom@1504 | 643 | } catch (Exception e) { |
ohrstrom@1504 | 644 | e.printStackTrace(err); |
ohrstrom@1504 | 645 | } |
ohrstrom@1504 | 646 | return rc; |
ohrstrom@1504 | 647 | } |
ohrstrom@1504 | 648 | |
ohrstrom@1504 | 649 | /** |
ohrstrom@1504 | 650 | * Run the server thread until it exits. Either because of inactivity or because the port file has been deleted by someone else, or overtaken by some other |
ohrstrom@1504 | 651 | * javac server. |
ohrstrom@1504 | 652 | */ |
ohrstrom@1504 | 653 | private void run(PortFile portFile, PrintStream err, int keepalive) { |
ohrstrom@1504 | 654 | boolean fileDeleted = false; |
ohrstrom@1504 | 655 | long timeSinceLastCompile; |
ohrstrom@1504 | 656 | try { |
ohrstrom@1504 | 657 | // Every 5 second (check_portfile_interval) we test if the portfile has disappeared => quit |
ohrstrom@1504 | 658 | // Or if the last request was finished more than 125 seconds ago => quit |
ohrstrom@1504 | 659 | // 125 = seconds_of_inactivity_before_shutdown+check_portfile_interval |
ohrstrom@1504 | 660 | serverSocket.setSoTimeout(CHECK_PORTFILE_INTERVAL*1000); |
ohrstrom@1504 | 661 | for (;;) { |
ohrstrom@1504 | 662 | try { |
ohrstrom@1504 | 663 | Socket s = serverSocket.accept(); |
ohrstrom@1504 | 664 | CompilerThread ct = compilerPool.grabCompilerThread(); |
ohrstrom@1504 | 665 | ct.setSocket(s); |
ohrstrom@1504 | 666 | compilerPool.execute(ct); |
ohrstrom@1504 | 667 | flushLog(); |
ohrstrom@1504 | 668 | } catch (java.net.SocketTimeoutException e) { |
ohrstrom@1504 | 669 | if (compilerPool.numActiveRequests() > 0) { |
ohrstrom@1504 | 670 | // Never quit while there are active requests! |
ohrstrom@1504 | 671 | continue; |
ohrstrom@1504 | 672 | } |
ohrstrom@1504 | 673 | // If this is the timeout after the portfile |
ohrstrom@1504 | 674 | // has been deleted by us. Then we truly stop. |
ohrstrom@1504 | 675 | if (fileDeleted) { |
ohrstrom@1504 | 676 | log("Quitting because of "+(keepalive+CHECK_PORTFILE_INTERVAL)+" seconds of inactivity!"); |
ohrstrom@1504 | 677 | break; |
ohrstrom@1504 | 678 | } |
ohrstrom@1504 | 679 | // Check if the portfile is still there. |
ohrstrom@1504 | 680 | if (!portFile.exists()) { |
ohrstrom@1504 | 681 | // Time to quit because the portfile was deleted by another |
ohrstrom@1504 | 682 | // process, probably by the makefile that is done building. |
ohrstrom@1504 | 683 | log("Quitting because portfile was deleted!"); |
ohrstrom@1504 | 684 | flushLog(); |
ohrstrom@1504 | 685 | break; |
ohrstrom@1504 | 686 | } |
ohrstrom@1504 | 687 | // Check if portfile.stop is still there. |
ohrstrom@1504 | 688 | if (portFile.markedForStop()) { |
ohrstrom@1504 | 689 | // Time to quit because another process touched the file |
ohrstrom@1504 | 690 | // server.port.stop to signal that the server should stop. |
ohrstrom@1504 | 691 | // This is necessary on some operating systems that lock |
ohrstrom@1504 | 692 | // the port file hard! |
ohrstrom@1504 | 693 | log("Quitting because a portfile.stop file was found!"); |
ohrstrom@1504 | 694 | portFile.delete(); |
ohrstrom@1504 | 695 | flushLog(); |
ohrstrom@1504 | 696 | break; |
ohrstrom@1504 | 697 | } |
ohrstrom@1504 | 698 | // Does the portfile still point to me? |
ohrstrom@1504 | 699 | if (!portFile.stillMyValues()) { |
ohrstrom@1504 | 700 | // Time to quit because another build has started. |
ohrstrom@1504 | 701 | log("Quitting because portfile is now owned by another javac server!"); |
ohrstrom@1504 | 702 | flushLog(); |
ohrstrom@1504 | 703 | break; |
ohrstrom@1504 | 704 | } |
ohrstrom@1504 | 705 | |
ohrstrom@1504 | 706 | // Check how long since the last request finished. |
ohrstrom@1504 | 707 | long diff = System.currentTimeMillis() - compilerPool.lastRequestFinished(); |
ohrstrom@1504 | 708 | if (diff < keepalive * 1000) { |
ohrstrom@1504 | 709 | // Do not quit if we have waited less than 120 seconds. |
ohrstrom@1504 | 710 | continue; |
ohrstrom@1504 | 711 | } |
ohrstrom@1504 | 712 | // Ok, time to quit because of inactivity. Perhaps the build |
ohrstrom@1504 | 713 | // was killed and the portfile not cleaned up properly. |
ohrstrom@1504 | 714 | portFile.delete(); |
ohrstrom@1504 | 715 | fileDeleted = true; |
ohrstrom@1504 | 716 | log("" + keepalive + " seconds of inactivity quitting in " |
ohrstrom@1504 | 717 | + CHECK_PORTFILE_INTERVAL + " seconds!"); |
ohrstrom@1504 | 718 | flushLog(); |
ohrstrom@1504 | 719 | // Now we have a second 5 second grace |
ohrstrom@1504 | 720 | // period where javac remote requests |
ohrstrom@1504 | 721 | // that have loaded the data from the |
ohrstrom@1504 | 722 | // recently deleted portfile can connect |
ohrstrom@1504 | 723 | // and complete their requests. |
ohrstrom@1504 | 724 | } |
ohrstrom@1504 | 725 | } |
ohrstrom@1504 | 726 | } catch (Exception e) { |
ohrstrom@1504 | 727 | e.printStackTrace(err); |
ohrstrom@1504 | 728 | e.printStackTrace(theLog); |
ohrstrom@1504 | 729 | flushLog(); |
ohrstrom@1504 | 730 | } finally { |
ohrstrom@1504 | 731 | compilerPool.shutdown(); |
ohrstrom@1504 | 732 | } |
ohrstrom@1504 | 733 | long realTime = System.currentTimeMillis() - serverStart; |
ohrstrom@1504 | 734 | log("Shutting down."); |
ohrstrom@1504 | 735 | log("Total wall clock time " + realTime + "ms build time " + totalBuildTime + "ms"); |
ohrstrom@1504 | 736 | flushLog(); |
ohrstrom@1504 | 737 | } |
ohrstrom@1504 | 738 | |
ohrstrom@1504 | 739 | public static void cleanup(String... args) { |
ohrstrom@1504 | 740 | String settings = Util.findServerSettings(args); |
ohrstrom@1504 | 741 | if (settings == null) return; |
ohrstrom@1504 | 742 | String portfile = Util.extractStringOption("portfile", settings); |
ohrstrom@1504 | 743 | String background = Util.extractStringOption("background", settings); |
ohrstrom@1504 | 744 | if (background != null && background.equals("false")) { |
ohrstrom@1504 | 745 | // If the server runs within this jvm, then delete the portfile, |
ohrstrom@1504 | 746 | // since this jvm is about to exit soon. |
ohrstrom@1504 | 747 | File f = new File(portfile); |
ohrstrom@1504 | 748 | f.delete(); |
ohrstrom@1504 | 749 | } |
ohrstrom@1504 | 750 | } |
ohrstrom@1504 | 751 | } |