8048457: Sjavac should not use portfiles, sockets, etc if background=false
8044131: Restructure client / server protocol code
Summary: Changes protocol code to use Object input/output streams. Avoids spawning server if background=false. Refactors idleness checks, pooling and port file monitoring.
Reviewed-by: jjg, jfranck
--- a/langtools/src/share/classes/com/sun/tools/sjavac/BuildState.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/BuildState.java Wed Aug 13 14:44:59 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,10 +36,10 @@
* from a build. There are usually two build states, the previous one (prev),
* loaded from the javac_state file, and the current one (now).
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class BuildState {
private Map<String,Module> modules = new HashMap<>();
--- a/langtools/src/share/classes/com/sun/tools/sjavac/CleanProperties.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/CleanProperties.java Wed Aug 13 14:44:59 2014 +0200
@@ -36,19 +36,18 @@
import java.util.Properties;
import com.sun.tools.sjavac.options.Options;
-import com.sun.tools.sjavac.server.JavacService;
+import com.sun.tools.sjavac.server.Sjavac;
/**
* The clean properties transform should not be necessary.
* Eventually we will cleanup the property file sources in the OpenJDK instead.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
-public class CleanProperties implements Transformer
-{
+public class CleanProperties implements Transformer {
public void setExtra(String e) {
// Any extra information is ignored for clean properties.
}
@@ -57,7 +56,7 @@
// Any extra information is ignored for clean properties.
}
- public boolean transform(JavacService javacService,
+ public boolean transform(Sjavac sjavac,
Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSrcs,
Map<URI,Set<String>> visibleClasses,
@@ -70,8 +69,7 @@
boolean incremental,
int numCores,
PrintStream out,
- PrintStream err)
- {
+ PrintStream err) {
boolean rc = true;
for (String pkgName : pkgSrcs.keySet()) {
String pkgNameF = pkgName.replace('.',File.separatorChar);
@@ -87,9 +85,12 @@
return rc;
}
- boolean clean(String pkgName, String pkgNameF, File src, File destRoot, int debugLevel,
- Map<String,Set<URI>> packageArtifacts)
- {
+ boolean clean(String pkgName,
+ String pkgNameF,
+ File src,
+ File destRoot,
+ int debugLevel,
+ Map<String,Set<URI>> packageArtifacts) {
// Load the properties file.
Properties p = new Properties();
try {
--- a/langtools/src/share/classes/com/sun/tools/sjavac/CompileChunk.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/CompileChunk.java Wed Aug 13 14:44:59 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,10 +33,10 @@
* A compile chunk is a list of sources/packages to be compiled. Possibly a subset of
* the total number of sources/packages to be compiled for this sjavac invocation.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class CompileChunk implements Comparable<CompileChunk> {
public int numPackages;
--- a/langtools/src/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java Wed Aug 13 14:44:59 2014 +0200
@@ -30,13 +30,12 @@
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
-import java.util.Random;
import java.util.Set;
import java.util.Map;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.server.CompilationResult;
-import com.sun.tools.sjavac.server.JavacService;
+import com.sun.tools.sjavac.server.Sjavac;
import com.sun.tools.sjavac.server.SysInfo;
/**
@@ -67,7 +66,7 @@
args = a;
}
- public boolean transform(final JavacService javacService,
+ public boolean transform(final Sjavac sjavac,
Map<String,Set<URI>> pkgSrcs,
final Set<URI> visibleSources,
final Map<URI,Set<String>> visibleClasses,
@@ -86,12 +85,12 @@
boolean concurrentCompiles = true;
// Fetch the id.
- final String id = Util.extractStringOption("id", javacService.serverSettings());
+ final String id = Util.extractStringOption("id", sjavac.serverSettings());
// Only keep portfile and sjavac settings..
- String psServerSettings = Util.cleanSubOptions(Util.set("portfile","sjavac","background","keepalive"), javacService.serverSettings());
+ String psServerSettings = Util.cleanSubOptions(Util.set("portfile","sjavac","background","keepalive"), sjavac.serverSettings());
// Get maximum heap size from the server!
- SysInfo sysinfo = javacService.getSysInfo();
+ SysInfo sysinfo = sjavac.getSysInfo();
if (sysinfo.numCores == -1) {
Log.error("Could not query server for sysinfo!");
return false;
@@ -216,7 +215,7 @@
requests[i] = new Thread() {
@Override
public void run() {
- rn[ii] = javacService.compile("n/a",
+ rn[ii] = sjavac.compile("n/a",
id + "-" + ii,
args.prepJavacArgs(),
Collections.<File>emptyList(),
--- a/langtools/src/share/classes/com/sun/tools/sjavac/CompileProperties.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/CompileProperties.java Wed Aug 13 14:44:59 2014 +0200
@@ -38,20 +38,19 @@
import java.util.Map;
import com.sun.tools.sjavac.options.Options;
-import com.sun.tools.sjavac.server.JavacService;
+import com.sun.tools.sjavac.server.Sjavac;
/**
* Compile properties transform a properties file into a Java source file.
* Java has built in support for reading properties from either a text file
* in the source or a compiled java source file.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
-public class CompileProperties implements Transformer
-{
+public class CompileProperties implements Transformer {
// Any extra information passed from the command line, for example if:
// -tr .proppp=com.sun.tools.javac.smart.CompileProperties,sun.util.resources.LocaleNamesBundle
// then extra will be "sun.util.resources.LocaleNamesBundle"
@@ -64,7 +63,7 @@
public void setExtra(Options a) {
}
- public boolean transform(JavacService javacService,
+ public boolean transform(Sjavac sjavac,
Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSrcs,
Map<URI,Set<String>> visibleClasses,
--- a/langtools/src/share/classes/com/sun/tools/sjavac/CopyFile.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/CopyFile.java Wed Aug 13 14:44:59 2014 +0200
@@ -32,16 +32,16 @@
import java.util.Map;
import com.sun.tools.sjavac.options.Options;
-import com.sun.tools.sjavac.server.JavacService;
+import com.sun.tools.sjavac.server.Sjavac;
/**
* The copy file transform simply copies a matching file from -src to -d .
* Such files are typically images, xml documents and other data files.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class CopyFile implements Transformer {
@@ -51,7 +51,7 @@
public void setExtra(Options a) {
}
- public boolean transform(JavacService javacService,
+ public boolean transform(Sjavac sjavac,
Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSrcs,
Map<URI,Set<String>> visibleClasses,
--- a/langtools/src/share/classes/com/sun/tools/sjavac/JavacState.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/JavacState.java Wed Aug 13 14:44:59 2014 +0200
@@ -26,7 +26,6 @@
package com.sun.tools.sjavac;
import java.io.*;
-import java.nio.file.Path;
import java.util.Collections;
import java.util.Date;
import java.util.Set;
@@ -39,20 +38,18 @@
import java.util.*;
import com.sun.tools.sjavac.options.Options;
-import com.sun.tools.sjavac.options.SourceLocation;
-import com.sun.tools.sjavac.server.JavacService;
+import com.sun.tools.sjavac.server.Sjavac;
/**
* The javac state class maintains the previous (prev) and the current (now)
* build states and everything else that goes into the javac_state file.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
-public class JavacState
-{
+public class JavacState {
// The arguments to the compile. If not identical, then it cannot
// be an incremental build!
String theArgs;
@@ -655,7 +652,7 @@
/**
* Compile all the java sources. Return true, if it needs to be called again!
*/
- public boolean performJavaCompilations(JavacService javacService,
+ public boolean performJavaCompilations(Sjavac sjavac,
Options args,
Set<String> recentlyCompiled,
boolean[] rcValue) {
@@ -663,7 +660,7 @@
suffixRules.put(".java", compileJavaPackages);
compileJavaPackages.setExtra(args);
- rcValue[0] = perform(javacService, binDir, suffixRules);
+ rcValue[0] = perform(sjavac, binDir, suffixRules);
recentlyCompiled.addAll(taintedPackages());
clearTaintedPackages();
boolean again = !packagesWithChangedPublicApis.isEmpty();
@@ -693,10 +690,9 @@
* For all packages, find all sources belonging to the package, group the sources
* based on their transformers and apply the transformers on each source code group.
*/
- private boolean perform(JavacService javacService,
+ private boolean perform(Sjavac sjavac,
File outputDir,
- Map<String,Transformer> suffixRules)
- {
+ Map<String,Transformer> suffixRules) {
boolean rc = true;
// Group sources based on transforms. A source file can only belong to a single transform.
Map<Transformer,Map<String,Set<URI>>> groupedSources = new HashMap<>();
@@ -720,7 +716,7 @@
Map<String,String> packagePublicApis =
Collections.synchronizedMap(new HashMap<String, String>());
- boolean r = t.transform(javacService,
+ boolean r = t.transform(sjavac,
srcs,
visibleSrcs,
visibleClasses,
@@ -798,9 +794,7 @@
* Used to detect bugs where the makefile and sjavac have different opinions on which files
* should be compiled.
*/
- public void compareWithMakefileList(File makefileSourceList)
- throws ProblemException
- {
+ public void compareWithMakefileList(File makefileSourceList) throws ProblemException {
// If we are building on win32 using for example cygwin the paths in the makefile source list
// might be /cygdrive/c/.... which does not match c:\....
// We need to adjust our calculated sources to be identical, if necessary.
--- a/langtools/src/share/classes/com/sun/tools/sjavac/Log.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/Log.java Wed Aug 13 14:44:59 2014 +0200
@@ -31,10 +31,10 @@
* Utility class only for sjavac logging.
* The log level can be set using for example --log=DEBUG on the sjavac command line.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class Log {
private static PrintStream out, err;
--- a/langtools/src/share/classes/com/sun/tools/sjavac/Main.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/Main.java Wed Aug 13 14:44:59 2014 +0200
@@ -31,19 +31,21 @@
import java.nio.file.Path;
import java.nio.file.Files;
+import com.sun.tools.sjavac.client.SjavacClient;
+import com.sun.tools.sjavac.comp.SjavacImpl;
+import com.sun.tools.sjavac.comp.PooledSjavac;
import com.sun.tools.sjavac.options.Options;
import com.sun.tools.sjavac.options.SourceLocation;
-import com.sun.tools.sjavac.server.JavacService;
-import com.sun.tools.sjavac.server.JavacServer;
-import com.sun.tools.sjavac.server.JavacServiceClient;
+import com.sun.tools.sjavac.server.Sjavac;
+import com.sun.tools.sjavac.server.SjavacServer;
/**
* The main class of the smart javac wrapper tool.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class Main {
@@ -163,13 +165,19 @@
return;
}
// Spawn a background server.
- int rc = JavacServer.startServer(args[0], System.err);
- System.exit(rc);
+ try {
+ SjavacServer server = new SjavacServer(args[0], System.err);
+ int rc = server.startServer();
+ System.exit(rc);
+ } catch (IOException ioex) {
+ Log.error("IOException caught: " + ioex);
+ System.exit(-1);
+ }
}
Main main = new Main();
int rc = main.go(args, System.out, System.err);
// Remove the portfile, but only if this background=false was used.
- JavacServer.cleanup(args);
+ SjavacServer.cleanup(args);
System.exit(rc);
}
@@ -341,15 +349,22 @@
// Collect the name of all compiled packages.
Set<String> recently_compiled = new HashSet<>();
boolean[] rc = new boolean[1];
+ Sjavac sjavac;
+ boolean background = Util.extractBooleanOption("background", options.getServerConf(), true);
do {
// Clean out artifacts in tainted packages.
javac_state.deleteClassArtifactsInTaintedPackages();
- // Create a JavacService to delegate the actual compilation to.
- // Currently sjavac always connects to a server through a socket
- // regardless if sjavac runs as a background service or not.
- // This will most likely change in the future.
- JavacService javacService = new JavacServiceClient(options);
- again = javac_state.performJavaCompilations(javacService, options, recently_compiled, rc);
+ // Create an sjavac implementation to be used for compilation
+ if (background) {
+ sjavac = new SjavacClient(options);
+ } else {
+ int poolsize = Util.extractIntOption("poolsize", options.getServerConf());
+ if (poolsize <= 0)
+ poolsize = Runtime.getRuntime().availableProcessors();
+ sjavac = new PooledSjavac(new SjavacImpl(), poolsize);
+ }
+
+ again = javac_state.performJavaCompilations(sjavac, options, recently_compiled, rc);
if (!rc[0]) break;
} while (again);
// Only update the state if the compile went well.
@@ -360,6 +375,8 @@
// Remove artifacts that were generated during the last compile, but not this one.
javac_state.removeSuperfluousArtifacts(recently_compiled);
}
+ if (!background)
+ sjavac.shutdown();
return rc[0] ? 0 : -1;
} catch (ProblemException e) {
Log.error(e.getMessage());
--- a/langtools/src/share/classes/com/sun/tools/sjavac/Module.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/Module.java Wed Aug 13 14:44:59 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,10 +36,10 @@
* The module is the root of a set of packages/sources/artifacts.
* At the moment there is only one module in use, the empty/no-name/default module.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class Module implements Comparable<Module> {
private String name;
--- a/langtools/src/share/classes/com/sun/tools/sjavac/Package.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/Package.java Wed Aug 13 14:44:59 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -54,10 +54,10 @@
* the visible recompilation of the dependent packages indicates how much circular
* dependencies your code has.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class Package implements Comparable<Package> {
// The module this package belongs to. (There is a legacy module with an empty string name,
--- a/langtools/src/share/classes/com/sun/tools/sjavac/ProblemException.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/ProblemException.java Wed Aug 13 14:44:59 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,10 +28,10 @@
/**
* Used to signal serious problems when running sjavac.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class ProblemException extends Exception {
static final long serialVersionUID = -3387516993124229949L;
--- a/langtools/src/share/classes/com/sun/tools/sjavac/Source.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/Source.java Wed Aug 13 14:44:59 2014 +0200
@@ -37,10 +37,10 @@
* The class also knows how to find source files (scanRoot) given include/exclude
* patterns and a root.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class Source implements Comparable<Source> {
// The package the source belongs to.
--- a/langtools/src/share/classes/com/sun/tools/sjavac/Transformer.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/Transformer.java Wed Aug 13 14:44:59 2014 +0200
@@ -31,7 +31,7 @@
import java.util.Map;
import com.sun.tools.sjavac.options.Options;
-import com.sun.tools.sjavac.server.JavacService;
+import com.sun.tools.sjavac.server.Sjavac;
/**
* The transform interface is used to transform content inside a package, from one form to another.
@@ -39,13 +39,12 @@
* but can also be an unpredictable number of generated source files (eg idl2java)
* or a single predictable output file (eg when copying,cleaning or compiling a properties file).
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
-public interface Transformer
-{
+public interface Transformer {
/**
* The transform method takes a set of package names, mapped to their source files and to the
* pubapis of the packages.
@@ -83,7 +82,7 @@
* If num_cores is set to a non-zero value. The transform should attempt to use no more than these
* number of threads for heavy work.
*/
- boolean transform(JavacService javacService,
+ boolean transform(Sjavac sjavac,
Map<String,Set<URI>> pkgSrcs,
Set<URI> visibleSources,
Map<URI,Set<String>> visibleClasses,
--- a/langtools/src/share/classes/com/sun/tools/sjavac/Util.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/Util.java Wed Aug 13 14:44:59 2014 +0200
@@ -26,8 +26,6 @@
package com.sun.tools.sjavac;
import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashSet;
@@ -37,10 +35,10 @@
/**
* Utilities.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class Util {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/client/SjavacClient.java Wed Aug 13 14:44:59 2014 +0200
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.sjavac.client;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.URI;
+import java.util.List;
+import java.util.Set;
+
+import com.sun.tools.sjavac.Log;
+import com.sun.tools.sjavac.ProblemException;
+import com.sun.tools.sjavac.Util;
+import com.sun.tools.sjavac.server.CompilationResult;
+import com.sun.tools.sjavac.server.PortFile;
+import com.sun.tools.sjavac.server.Sjavac;
+import com.sun.tools.sjavac.server.SjavacServer;
+import com.sun.tools.sjavac.server.SysInfo;
+import com.sun.tools.sjavac.options.Options;
+
+/**
+ * Sjavac implementation that delegates requests to a SjavacServer.
+ *
+ * <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 subject to change or
+ * deletion without notice.</b>
+ */
+public class SjavacClient implements Sjavac {
+
+ // The id can perhaps be used in the future by the javac server to reuse the
+ // JavaCompiler instance for several compiles using the same id.
+ private final String id;
+ private final String portfileName;
+ private final String logfile;
+ private final String stdouterrfile;
+ private final boolean background;
+
+ // Default keepalive for server is 120 seconds.
+ // I.e. it will accept 120 seconds of inactivity before quitting.
+ private final int keepalive;
+ private final int poolsize;
+
+ // The sjavac option specifies how the server part of sjavac is spawned.
+ // If you have the experimental sjavac in your path, you are done. If not, you have
+ // to point to a com.sun.tools.sjavac.Main that supports --startserver
+ // for example by setting: sjavac=java%20-jar%20...javac.jar%com.sun.tools.sjavac.Main
+ private final String sjavacForkCmd;
+
+ // Wait 2 seconds for response, before giving up on javac server.
+ static int CONNECTION_TIMEOUT = 2000;
+ static int MAX_CONNECT_ATTEMPTS = 3;
+ static int WAIT_BETWEEN_CONNECT_ATTEMPTS = 2000;
+
+ // Store the server conf settings here.
+ private final String settings;
+
+ public SjavacClient(Options options) {
+ String tmpServerConf = options.getServerConf();
+ String serverConf = (tmpServerConf!=null)? tmpServerConf : "";
+ String tmpId = Util.extractStringOption("id", serverConf);
+ id = (tmpId!=null) ? tmpId : "id"+(((new java.util.Random()).nextLong())&Long.MAX_VALUE);
+ String p = Util.extractStringOption("portfile", serverConf);
+ portfileName = (p!=null) ? p : options.getStateDir().toFile().getAbsolutePath()+File.separatorChar+"javac_server";
+ logfile = Util.extractStringOption("logfile", serverConf, portfileName + ".javaclog");
+ stdouterrfile = Util.extractStringOption("stdouterrfile", serverConf, portfileName + ".stdouterr");
+ background = Util.extractBooleanOption("background", serverConf, true);
+ sjavacForkCmd = Util.extractStringOption("sjavac", serverConf, "sjavac");
+ int poolsize = Util.extractIntOption("poolsize", serverConf);
+ keepalive = Util.extractIntOption("keepalive", serverConf, 120);
+
+ this.poolsize = poolsize > 0 ? poolsize : Runtime.getRuntime().availableProcessors();
+ settings = (serverConf.equals("")) ? "id="+id+",portfile="+portfileName : serverConf;
+ }
+
+ /**
+ * Hand out the server settings.
+ * @return The server settings, possibly a default value.
+ */
+ public String serverSettings() {
+ return settings;
+ }
+
+ /**
+ * Make a request to the server only to get the maximum possible heap size to use for compilations.
+ *
+ * @param port_file The port file used to synchronize creation of this server.
+ * @param id The identify of the compilation.
+ * @param out Standard out information.
+ * @param err Standard err information.
+ * @return The maximum heap size in bytes.
+ */
+ @Override
+ public SysInfo getSysInfo() {
+ try (Socket socket = tryConnect()) {
+ // The ObjectInputStream constructor will block until the
+ // corresponding ObjectOutputStream has written and flushed the
+ // header, so it is important that the ObjectOutputStreams on server
+ // and client are opened before the ObjectInputStreams.
+ ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
+ ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
+ oos.writeObject(id);
+ oos.writeObject(SjavacServer.CMD_SYS_INFO);
+ oos.flush();
+ return (SysInfo) ois.readObject();
+ } catch (IOException | ClassNotFoundException ex) {
+ Log.error("[CLIENT] Exception caught: " + ex);
+ StringWriter sw = new StringWriter();
+ ex.printStackTrace(new PrintWriter(sw));
+ }
+ return null;
+ }
+
+ @Override
+ public CompilationResult compile(String protocolId,
+ String invocationId,
+ String[] args,
+ List<File> explicitSources,
+ Set<URI> sourcesToCompile,
+ Set<URI> visibleSources) {
+ CompilationResult result;
+ try (Socket socket = tryConnect()) {
+ // The ObjectInputStream constructor will block until the
+ // corresponding ObjectOutputStream has written and flushed the
+ // header, so it is important that the ObjectOutputStreams on server
+ // and client are opened before the ObjectInputStreams.
+ ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
+ ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
+ oos.writeObject(id);
+ oos.writeObject(SjavacServer.CMD_COMPILE);
+ oos.writeObject(protocolId);
+ oos.writeObject(invocationId);
+ oos.writeObject(args);
+ oos.writeObject(explicitSources);
+ oos.writeObject(sourcesToCompile);
+ oos.writeObject(visibleSources);
+ oos.flush();
+ result = (CompilationResult) ois.readObject();
+ } catch (IOException | ClassNotFoundException ex) {
+ Log.error("Exception caught: " + ex);
+ result = new CompilationResult(CompilationResult.ERROR_FATAL);
+ result.stderr = ex.getMessage();
+ }
+ return result;
+ }
+
+ private Socket tryConnect() throws IOException {
+
+ PortFile portFile;
+ try {
+ // This should be taken care of at a higher level (JDK-8048451)
+ portFile = SjavacServer.getPortFile(portfileName);
+ } catch (FileNotFoundException e) {
+ // Reached for instance if directory of port file does not exist
+ Log.error("Port file inaccessable: " + e);
+ throw new RuntimeException(e);
+ }
+ for (int i = 0; i < MAX_CONNECT_ATTEMPTS; i++) {
+ Log.info(String.format("Trying to connect (attempt %d of %d)",
+ i+1, MAX_CONNECT_ATTEMPTS));
+ try {
+ if (!makeSureServerIsRunning(portFile))
+ continue;
+ Socket socket = new Socket();
+ InetAddress localhost = InetAddress.getByName(null);
+ socket.connect(new InetSocketAddress(localhost, portFile.getPort()),
+ CONNECTION_TIMEOUT);
+ return socket;
+ } catch (ProblemException | IOException ex) {
+ Log.error("Caught exception during tryConnect: " + ex);
+ }
+
+ try {
+ Thread.sleep(WAIT_BETWEEN_CONNECT_ATTEMPTS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ throw new IOException("Could not connect to server");
+ }
+
+ private boolean makeSureServerIsRunning(PortFile portFile)
+ throws IOException, ProblemException, FileNotFoundException {
+
+ synchronized (portFile) {
+ portFile.lock();
+ portFile.getValues();
+ portFile.unlock();
+ }
+
+ if (!portFile.containsPortInfo()) {
+ String forkCmd = SjavacServer.fork(sjavacForkCmd,
+ portFile.getFilename(),
+ logfile,
+ poolsize,
+ keepalive,
+ System.err,
+ stdouterrfile,
+ background);
+ if (!portFile.waitForValidValues()) {
+ // This can be simplified once JDK-8048457 has been addressed
+ // since we won't have an SjavacClient if background = false
+ if (background) {
+ // There seems be some problem with spawning the external
+ // process (for instance no fork command provided and no
+ // sjavac on path)
+ StringWriter sw = new StringWriter();
+ SjavacClient.printFailedAttempt(forkCmd,
+ stdouterrfile,
+ new PrintWriter(sw));
+ Log.error(sw.toString());
+ }
+ }
+ }
+ return portFile.containsPortInfo();
+ }
+
+
+ public static void printFailedAttempt(String cmd, String f, PrintWriter err) {
+ err.println("---- Failed to start javac server with this command -----");
+ err.println(cmd);
+ try {
+ BufferedReader in = new BufferedReader(new FileReader(f));
+ err.println("---- stdout/stderr output from attempt to start javac server -----");
+ for (;;) {
+ String l = in.readLine();
+ if (l == null) {
+ break;
+ }
+ err.println(l);
+ }
+ err.println("------------------------------------------------------------------");
+ } catch (Exception e) {
+ err.println("The stdout/stderr output in file " + f + " does not exist and the server did not start.");
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ // Nothing to clean up
+ }
+}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/comp/AttrWithDeps.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/comp/AttrWithDeps.java Wed Aug 13 14:44:59 2014 +0200
@@ -30,10 +30,10 @@
/** Subclass to Attr that overrides reportDepedence.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class AttrWithDeps extends Attr {
--- a/langtools/src/share/classes/com/sun/tools/sjavac/comp/Dependencies.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/comp/Dependencies.java Wed Aug 13 14:44:59 2014 +0200
@@ -41,10 +41,10 @@
/** Utility class containing dependency information between packages
* and the pubapi for a package.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class Dependencies {
protected static final Context.Key<Dependencies> dependenciesKey = new Context.Key<>();
--- a/langtools/src/share/classes/com/sun/tools/sjavac/comp/JavaCompilerWithDeps.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/comp/JavaCompilerWithDeps.java Wed Aug 13 14:44:59 2014 +0200
@@ -32,29 +32,29 @@
/** Subclass to Resolve that overrides collect.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class JavaCompilerWithDeps extends JavaCompiler {
/** The dependency database
*/
protected Dependencies deps;
- protected JavacServiceImpl javacService;
+ protected SjavacErrorHandler errorHandler;
- public JavaCompilerWithDeps(Context context, JavacServiceImpl jsi) {
+ public JavaCompilerWithDeps(Context context, SjavacErrorHandler eh) {
super(context);
deps = Dependencies.instance(context);
- javacService = jsi;
+ errorHandler = eh;
needRootClasses = true;
}
- public static void preRegister(Context context, final JavacServiceImpl t) {
+ public static void preRegister(Context context, final SjavacErrorHandler eh) {
context.put(compilerKey, new Context.Factory<JavaCompiler>() {
public JavaCompiler make(Context c) {
- JavaCompiler instance = new JavaCompilerWithDeps(c, t);
+ JavaCompiler instance = new JavaCompilerWithDeps(c, eh);
c.put(JavaCompiler.class, instance);
return instance;
}
@@ -97,7 +97,7 @@
// Now check if the truncated uri ends with the path. (It does not == failure!)
if (path.length() > 0 && !path.equals("/unnamed package/") && !pp.endsWith(path)) {
- javacService.logError("Error: The source file "+sym.sourcefile.getName()+
+ errorHandler.logError("Error: The source file "+sym.sourcefile.getName()+
" is located in the wrong package directory, because it contains the class "+
sym.getQualifiedName());
}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/comp/JavacServiceImpl.java Tue Aug 12 17:48:30 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,152 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.tools.sjavac.comp;
-
-import java.io.File;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.net.URI;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-
-import javax.tools.JavaCompiler.CompilationTask;
-import javax.tools.JavaFileObject;
-import javax.tools.StandardJavaFileManager;
-
-import com.sun.tools.javac.api.JavacTaskImpl;
-import com.sun.tools.javac.api.JavacTool;
-import com.sun.tools.javac.util.Context;
-import com.sun.tools.javac.util.ListBuffer;
-import com.sun.tools.sjavac.Util;
-import com.sun.tools.sjavac.server.CompilationResult;
-import com.sun.tools.sjavac.server.JavacServer;
-import com.sun.tools.sjavac.server.JavacService;
-import com.sun.tools.sjavac.server.SysInfo;
-
-public class JavacServiceImpl implements JavacService {
-
- JavacServer javacServer;
- private ThreadLocal<Boolean> forcedExit;
-
- public JavacServiceImpl(JavacServer javacServer) {
- this.javacServer = javacServer;
-
- }
-
- public void logError(String msg) {
-// stderr.println(msg);
- forcedExit.set(true);
- }
-
- @Override
- public SysInfo getSysInfo() {
- return new SysInfo(Runtime.getRuntime().availableProcessors(),
- Runtime.getRuntime().maxMemory());
- }
-
- @Override
- public CompilationResult compile(String protocolId,
- String invocationId,
- String[] args,
- List<File> explicitSources,
- Set<URI> sourcesToCompile,
- Set<URI> visibleSources) {
-
- JavacTool compiler = JavacTool.create();
- StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
- SmartFileManager smartFileManager = new SmartFileManager(fileManager);
- Context context = new Context();
- ResolveWithDeps.preRegister(context);
- AttrWithDeps.preRegister(context);
- JavaCompilerWithDeps.preRegister(context, this);
-
- // Now setup the actual compilation....
- CompilationResult compilationResult = new CompilationResult(0);
-
- // First deal with explicit source files on cmdline and in at file.
- ListBuffer<JavaFileObject> compilationUnits = new ListBuffer<>();
- for (JavaFileObject i : fileManager.getJavaFileObjectsFromFiles(explicitSources)) {
- compilationUnits.append(i);
- }
- // Now deal with sources supplied as source_to_compile.
- ListBuffer<File> sourcesToCompileFiles = new ListBuffer<>();
- for (URI u : sourcesToCompile) {
- sourcesToCompileFiles.append(new File(u));
- }
- for (JavaFileObject i : fileManager.getJavaFileObjectsFromFiles(sourcesToCompileFiles)) {
- compilationUnits.append(i);
- }
- // Log the options to be used.
- StringBuilder options = new StringBuilder();
- for (String s : args) {
- options.append(">").append(s).append("< ");
- }
- javacServer.log(protocolId+" <"+invocationId+"> options "+options.toString());
-
- forcedExit.set(false);
- // Create a new logger.
- StringWriter stdoutLog = new StringWriter();
- StringWriter stderrLog = new StringWriter();
- PrintWriter stdout = new PrintWriter(stdoutLog);
- PrintWriter stderr = new PrintWriter(stderrLog);
- com.sun.tools.javac.main.Main.Result rc = com.sun.tools.javac.main.Main.Result.OK;
- try {
- if (compilationUnits.size() > 0) {
- smartFileManager.setVisibleSources(visibleSources);
- smartFileManager.cleanArtifacts();
- smartFileManager.setLog(stdout);
-
-
- // Do the compilation!
- CompilationTask task = compiler.getTask(stderr, smartFileManager, null, Arrays.asList(args), null, compilationUnits, context);
- rc = ((JavacTaskImpl) task).doCall();
- smartFileManager.flush();
- }
- } catch (Exception e) {
- stderr.println(e.getMessage());
- forcedExit.set(true);
- }
-
- compilationResult.packageArtifacts = smartFileManager.getPackageArtifacts();
-
- Dependencies deps = Dependencies.instance(context);
- compilationResult.packageDependencies = deps.getDependencies();
- compilationResult.packagePubapis = deps.getPubapis();
-
- compilationResult.stdout = stdoutLog.toString();
- compilationResult.stderr = stderrLog.toString();
- compilationResult.returnCode = rc.exitCode == 0 && forcedExit.get() ? -1 : rc.exitCode;
-
- return compilationResult;
- }
-
- @Override
- public String serverSettings() {
- return "";
- }
-
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/comp/PooledSjavac.java Wed Aug 13 14:44:59 2014 +0200
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.tools.sjavac.comp;
+
+import java.io.File;
+import java.net.URI;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.sun.tools.sjavac.Log;
+import com.sun.tools.sjavac.server.CompilationResult;
+import com.sun.tools.sjavac.server.Sjavac;
+import com.sun.tools.sjavac.server.SysInfo;
+
+/**
+ * An sjavac implementation that limits the number of concurrent calls by
+ * wrapping invocations in Callables and delegating them to a FixedThreadPool.
+ *
+ * <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 subject to change or
+ * deletion without notice.</b>
+ */
+public class PooledSjavac implements Sjavac {
+
+ final Sjavac delegate;
+ final ExecutorService pool;
+
+ public PooledSjavac(Sjavac delegate, int poolsize) {
+ Objects.requireNonNull(delegate);
+ this.delegate = delegate;
+ pool = Executors.newFixedThreadPool(poolsize, new ThreadFactory() {
+ AtomicInteger count = new AtomicInteger();
+ @Override
+ public Thread newThread(Runnable runnable) {
+ String cls = PooledSjavac.class.getSimpleName();
+ int num = count.incrementAndGet();
+ Thread t = new Thread(runnable, cls + "-" + num);
+ t.setDaemon(true);
+ return t;
+ }
+ });
+ }
+
+ @Override
+ public SysInfo getSysInfo() {
+ try {
+ return pool.submit(new Callable<SysInfo>() {
+ @Override
+ public SysInfo call() throws Exception {
+ return delegate.getSysInfo();
+ }
+ }).get();
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Error during getSysInfo", e);
+ }
+ }
+
+ @Override
+ public CompilationResult compile(final String protocolId,
+ final String invocationId,
+ final String[] args,
+ final List<File> explicitSources,
+ final Set<URI> sourcesToCompile,
+ final Set<URI> visibleSources) {
+ try {
+ return pool.submit(new Callable<CompilationResult>() {
+ @Override
+ public CompilationResult call() throws Exception {
+ return delegate.compile(protocolId,
+ invocationId,
+ args,
+ explicitSources,
+ sourcesToCompile,
+ visibleSources);
+ }
+ }).get();
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Error during compile", e);
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ pool.shutdown(); // Disable new tasks from being submitted
+ try {
+ // Wait a while for existing tasks to terminate
+ if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
+ pool.shutdownNow(); // Cancel currently executing tasks
+ // Wait a while for tasks to respond to being cancelled
+ if (!pool.awaitTermination(60, TimeUnit.SECONDS))
+ Log.error("ThreadPool did not terminate");
+ }
+ // Grace period for thread termination
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {
+ // (Re-)Cancel if current thread also interrupted
+ pool.shutdownNow();
+ // Preserve interrupt status
+ Thread.currentThread().interrupt();
+ }
+
+ delegate.shutdown();
+ }
+
+ @Override
+ public String serverSettings() {
+ return delegate.serverSettings();
+ }
+}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/comp/PubapiVisitor.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/comp/PubapiVisitor.java Wed Aug 13 14:44:59 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,10 +37,10 @@
/** Utility class that constructs a textual representation
* of the public api of a class.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class PubapiVisitor extends ElementScanner9<Void, Void> {
--- a/langtools/src/share/classes/com/sun/tools/sjavac/comp/ResolveWithDeps.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/comp/ResolveWithDeps.java Wed Aug 13 14:44:59 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,10 +30,10 @@
/** Subclass to Resolve that overrides collect.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class ResolveWithDeps extends Resolve {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/comp/SjavacErrorHandler.java Wed Aug 13 14:44:59 2014 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.sjavac.comp;
+
+/**
+ * <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 subject to change or
+ * deletion without notice.</b>
+ */
+public interface SjavacErrorHandler {
+ void logError(String msg);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java Wed Aug 13 14:44:59 2014 +0200
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.tools.sjavac.comp;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.tools.JavaCompiler.CompilationTask;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+
+import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Options;
+import com.sun.tools.sjavac.server.CompilationResult;
+import com.sun.tools.sjavac.server.Sjavac;
+import com.sun.tools.sjavac.server.SysInfo;
+
+/**
+ * The sjavac implementation that interacts with javac and performs the actual
+ * compilation.
+ *
+ * <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 subject to change or
+ * deletion without notice.</b>
+ */
+public class SjavacImpl implements Sjavac {
+
+ @Override
+ public SysInfo getSysInfo() {
+ return new SysInfo(Runtime.getRuntime().availableProcessors(),
+ Runtime.getRuntime().maxMemory());
+ }
+
+ @Override
+ public CompilationResult compile(String protocolId,
+ String invocationId,
+ String[] args,
+ List<File> explicitSources,
+ Set<URI> sourcesToCompile,
+ Set<URI> visibleSources) {
+ final AtomicBoolean forcedExit = new AtomicBoolean();
+
+ JavacTool compiler = JavacTool.create();
+ StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
+ SmartFileManager smartFileManager = new SmartFileManager(fileManager);
+ Context context = new Context();
+ ResolveWithDeps.preRegister(context);
+ AttrWithDeps.preRegister(context);
+ JavaCompilerWithDeps.preRegister(context, new SjavacErrorHandler() {
+ @Override
+ public void logError(String msg) {
+ forcedExit.set(true);
+ }
+ });
+
+ // Now setup the actual compilation....
+ CompilationResult compilationResult = new CompilationResult(0);
+
+ // First deal with explicit source files on cmdline and in at file.
+ ListBuffer<JavaFileObject> compilationUnits = new ListBuffer<>();
+ for (JavaFileObject i : fileManager.getJavaFileObjectsFromFiles(explicitSources)) {
+ compilationUnits.append(i);
+ }
+ // Now deal with sources supplied as source_to_compile.
+ ListBuffer<File> sourcesToCompileFiles = new ListBuffer<>();
+ for (URI u : sourcesToCompile) {
+ sourcesToCompileFiles.append(new File(u));
+ }
+ for (JavaFileObject i : fileManager.getJavaFileObjectsFromFiles(sourcesToCompileFiles)) {
+ compilationUnits.append(i);
+ }
+ forcedExit.set(false);
+ // Create a new logger.
+ StringWriter stdoutLog = new StringWriter();
+ StringWriter stderrLog = new StringWriter();
+ PrintWriter stdout = new PrintWriter(stdoutLog);
+ PrintWriter stderr = new PrintWriter(stderrLog);
+ com.sun.tools.javac.main.Main.Result rc = com.sun.tools.javac.main.Main.Result.OK;
+ try {
+ if (compilationUnits.size() > 0) {
+ smartFileManager.setVisibleSources(visibleSources);
+ smartFileManager.cleanArtifacts();
+ smartFileManager.setLog(stdout);
+
+ // Do the compilation!
+ CompilationTask task = compiler.getTask(stderr,
+ smartFileManager,
+ null,
+ Arrays.asList(args),
+ null,
+ compilationUnits,
+ context);
+ smartFileManager.setSymbolFileEnabled(!Options.instance(context).isSet("ignore.symbol.file"));
+ rc = ((JavacTaskImpl) task).doCall();
+ smartFileManager.flush();
+ }
+ } catch (Exception e) {
+ stderrLog.append(e.getMessage());
+ forcedExit.set(true);
+ }
+
+ compilationResult.packageArtifacts = smartFileManager.getPackageArtifacts();
+
+ Dependencies deps = Dependencies.instance(context);
+ compilationResult.packageDependencies = deps.getDependencies();
+ compilationResult.packagePubapis = deps.getPubapis();
+
+ compilationResult.stdout = stdoutLog.toString();
+ compilationResult.stderr = stderrLog.toString();
+
+ compilationResult.returnCode = rc.exitCode == 0 && forcedExit.get() ? -1 : rc.exitCode;
+
+ return compilationResult;
+ }
+
+ @Override
+ public void shutdown() {
+ // Nothing to clean up
+ // ... maybe we should wait for any current request to finish?
+ }
+
+
+ @Override
+ public String serverSettings() {
+ return "";
+ }
+
+}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/comp/SmartFileManager.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/comp/SmartFileManager.java Wed Aug 13 14:44:59 2014 +0200
@@ -37,7 +37,6 @@
import javax.tools.JavaFileObject.Kind;
import com.sun.tools.javac.file.JavacFileManager;
-import com.sun.tools.javac.util.BaseFileManager;
import com.sun.tools.javac.util.ListBuffer;
/**
@@ -50,10 +49,10 @@
* Can also blind out the filemanager from seeing certain files in the file system.
* Necessary to prevent javac from seeing some sources where the source path points.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class SmartFileManager extends ForwardingJavaFileManager<JavaFileManager> {
@@ -97,9 +96,7 @@
public Iterable<JavaFileObject> list(Location location,
String packageName,
Set<Kind> kinds,
- boolean recurse)
- throws IOException
- {
+ boolean recurse) throws IOException {
// Acquire the list of files.
Iterable<JavaFileObject> files = super.list(location, packageName, kinds, recurse);
if (visibleSources.isEmpty()) {
@@ -112,8 +109,7 @@
String t = uri.toString();
if (t.startsWith("jar:")
|| t.endsWith(".class")
- || visibleSources.contains(uri))
- {
+ || visibleSources.contains(uri)) {
filteredFiles.add(f);
}
}
@@ -128,9 +124,7 @@
@Override
public JavaFileObject getJavaFileForInput(Location location,
String className,
- Kind kind)
- throws IOException
- {
+ Kind kind) throws IOException {
JavaFileObject file = super.getJavaFileForInput(location, className, kind);
if (file == null || visibleSources.isEmpty()) {
return file;
@@ -146,9 +140,7 @@
public JavaFileObject getJavaFileForOutput(Location location,
String className,
Kind kind,
- FileObject sibling)
- throws IOException
- {
+ FileObject sibling) throws IOException {
JavaFileObject file = super.getJavaFileForOutput(location, className, kind, sibling);
if (file == null) return file;
int dp = className.lastIndexOf('.');
@@ -165,9 +157,7 @@
@Override
public FileObject getFileForInput(Location location,
String packageName,
- String relativeName)
- throws IOException
- {
+ String relativeName) throws IOException {
FileObject file = super.getFileForInput(location, packageName, relativeName);
if (file == null || visibleSources.isEmpty()) {
return file;
@@ -183,9 +173,7 @@
public FileObject getFileForOutput(Location location,
String packageName,
String relativeName,
- FileObject sibling)
- throws IOException
- {
+ FileObject sibling) throws IOException {
FileObject file = super.getFileForOutput(location, packageName, relativeName, sibling);
if (file == null) return file;
if (location.equals(StandardLocation.NATIVE_HEADER_OUTPUT) &&
--- a/langtools/src/share/classes/com/sun/tools/sjavac/comp/SmartFileObject.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/comp/SmartFileObject.java Wed Aug 13 14:44:59 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,10 +36,10 @@
* and compare the new content with the old content on disk. Only if they differ,
* will the file be updated.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class SmartFileObject implements JavaFileObject {
--- a/langtools/src/share/classes/com/sun/tools/sjavac/comp/SmartWriter.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/comp/SmartWriter.java Wed Aug 13 14:44:59 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,9 +34,9 @@
* If not, the file is not touched.
*
* <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 subject to change
- * or deletion without notice.</b></p>
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.</b>
*/
public class SmartWriter extends Writer {
--- a/langtools/src/share/classes/com/sun/tools/sjavac/options/ArgumentIterator.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/options/ArgumentIterator.java Wed Aug 13 14:44:59 2014 +0200
@@ -27,6 +27,12 @@
import java.util.Iterator;
+/**
+ * <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 subject to change or
+ * deletion without notice.</b>
+ */
public class ArgumentIterator implements Iterator<String> {
/** The underlying argument iterator */
--- a/langtools/src/share/classes/com/sun/tools/sjavac/options/Option.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/options/Option.java Wed Aug 13 14:44:59 2014 +0200
@@ -47,6 +47,11 @@
* This enum represents all options from (1) and (2). Note that instances of
* this enum only entail static information about the option. For storage of
* option values, refer to com.sun.tools.sjavac.options.Options.
+ *
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public enum Option {
--- a/langtools/src/share/classes/com/sun/tools/sjavac/options/OptionHelper.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/options/OptionHelper.java Wed Aug 13 14:44:59 2014 +0200
@@ -26,7 +26,6 @@
package com.sun.tools.sjavac.options;
import java.io.IOException;
-import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
@@ -38,6 +37,11 @@
/**
* This class is used to decode sjavac options.
* See com.sun.tools.sjavac.options.Options for example usage.
+ *
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public abstract class OptionHelper {
--- a/langtools/src/share/classes/com/sun/tools/sjavac/options/Options.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/options/Options.java Wed Aug 13 14:44:59 2014 +0200
@@ -39,6 +39,11 @@
/**
* Instances of this class represent values for sjavac command line options.
+ *
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class Options {
--- a/langtools/src/share/classes/com/sun/tools/sjavac/options/SourceLocation.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/options/SourceLocation.java Wed Aug 13 14:44:59 2014 +0200
@@ -37,6 +37,11 @@
/**
* Represents a directory to be used for input to sjavac. (For instance a
* sourcepath or classpath.)
+ *
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
public class SourceLocation {
--- a/langtools/src/share/classes/com/sun/tools/sjavac/server/CompilationResult.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/CompilationResult.java Wed Aug 13 14:44:59 2014 +0200
@@ -25,28 +25,35 @@
package com.sun.tools.sjavac.server;
+import java.io.Serializable;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
-public class CompilationResult {
+/**
+ *
+ * <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 subject to change or
+ * deletion without notice.</b>
+ */
+public class CompilationResult implements Serializable {
+
+ static final long serialVersionUID = 46739181113L;
// Return code constants
- public final static int ERROR_BUT_TRY_AGAIN = -4712;
public final static int ERROR_FATAL = -1;
public int returnCode;
public Map<String, Set<URI>> packageArtifacts = new HashMap<>();
public Map<String, Set<String>> packageDependencies = new HashMap<>();
public Map<String, String> packagePubapis = new HashMap<>();
- public SysInfo sysinfo;
- public String stdout;
- public String stderr;
+ public String stdout = "";
+ public String stderr = "";
public CompilationResult(int returnCode) {
this.returnCode = returnCode;
- this.sysinfo = new SysInfo(-1, -1);
}
public void setReturnCode(int returnCode) {
--- a/langtools/src/share/classes/com/sun/tools/sjavac/server/CompilerPool.java Tue Aug 12 17:48:30 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,165 +0,0 @@
-/*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.tools.sjavac.server;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Semaphore;
-import java.util.Stack;
-import java.util.concurrent.Future;
-
-import com.sun.tools.sjavac.comp.JavacServiceImpl;
-
-/** The compiler pool maintains compiler threads.
- *
- * <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 subject to change
- * or deletion without notice.</b></p>
- */
-public class CompilerPool {
- // The javac server that created this pool.
- private JavacServer javacServer;
- // A semaphore protecting the poolsize number of threads.
- private Semaphore available;
- // The stack of compiler threads.
- private Stack<CompilerThread> compilers = new Stack<>();
- // And the executor server to spawn threads.
- private final ExecutorService executorPool;
- // How many requests are active right now?
- private int concurrentRequests = 0;
- // When was the last request finished?
- private long lastRequestFinished = 0;
- // The total number of requests to this pool.
- private int numRequests = 0;
- // Protect access to the three above values.
- private static final Object conc = new Object();
-
- /**
- * Return the javac server that this pool belongs to.
- */
- public JavacServer getJavacServer() {
- return javacServer;
- }
-
- /**
- * Return how many threads are running at this very moment.
- */
- public int numActiveRequests()
- {
- synchronized (conc) {
- return concurrentRequests;
- }
- }
-
- /**
- * Return when the last request was finished.
- * I.e. the pool has been idle since.
- */
- public long lastRequestFinished()
- {
- synchronized (conc) {
- return lastRequestFinished;
- }
- }
-
- /**
- * Up the number of active requests.
- */
- public int startRequest() {
- int n;
- synchronized (conc) {
- concurrentRequests++;
- numRequests++;
- n = numRequests;
- }
- return n;
- }
-
- /**
- * Down the number of active requests. Return the current time.
- */
- public long stopRequest() {
- synchronized (conc) {
- concurrentRequests--;
- lastRequestFinished = System.currentTimeMillis();
- }
- return lastRequestFinished;
- }
-
- /**
- * Create a new compiler pool.
- */
- CompilerPool(int poolsize, JavacServer server) {
- available = new Semaphore(poolsize, true);
- javacServer = server;
- executorPool = Executors.newFixedThreadPool(poolsize);
- lastRequestFinished = System.currentTimeMillis();
- }
-
- /**
- * Execute a compiler thread.
- */
- public void execute(CompilerThread ct) {
- executorPool.execute(ct);
- }
-
- /**
- * Execute a minor task, for example generating bytecodes and writing them to disk,
- * that belong to a major compiler thread task.
- */
- public Future<?> executeSubtask(CompilerThread t, Runnable r) {
- return executorPool.submit(r);
- }
-
- /**
- * Shutdown the pool.
- */
- public void shutdown() {
- executorPool.shutdown();
- }
-
- /**
- * Acquire a compiler thread from the pool, or block until a thread is available.
- * If the pools is empty, create a new thread, but never more than is "available".
- */
- public CompilerThread grabCompilerThread() throws InterruptedException {
- available.acquire();
- if (compilers.empty()) {
- return new CompilerThread(this, new JavacServiceImpl(javacServer));
- }
- return compilers.pop();
- }
-
- /**
- * Return the specified compiler thread to the pool.
- */
- public void returnCompilerThread(CompilerThread h) {
- compilers.push(h);
- available.release();
- }
-}
-
--- a/langtools/src/share/classes/com/sun/tools/sjavac/server/CompilerThread.java Tue Aug 12 17:48:30 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,412 +0,0 @@
-/*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.tools.sjavac.server;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.net.Socket;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Future;
-
-import javax.tools.JavaCompiler.CompilationTask;
-import javax.tools.JavaFileObject;
-import javax.tools.StandardJavaFileManager;
-
-import com.sun.tools.javac.api.JavacTaskImpl;
-import com.sun.tools.javac.util.Context;
-import com.sun.tools.javac.util.ListBuffer;
-import com.sun.tools.javac.util.Options;
-import com.sun.tools.javac.util.StringUtils;
-import com.sun.tools.sjavac.comp.AttrWithDeps;
-import com.sun.tools.sjavac.comp.Dependencies;
-import com.sun.tools.sjavac.comp.JavaCompilerWithDeps;
-import com.sun.tools.sjavac.comp.JavacServiceImpl;
-import com.sun.tools.sjavac.comp.ResolveWithDeps;
-import com.sun.tools.sjavac.comp.SmartFileManager;
-
-/**
- * The compiler thread maintains a JavaCompiler instance and
- * can receive a request from the client, perform the compilation
- * requested and report back the results.
- *
- * * <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 subject to change
- * or deletion without notice.</b></p>
- */
-public class CompilerThread implements Runnable {
- private JavacServer javacServer;
- private CompilerPool compilerPool;
- private JavacServiceImpl javacServiceImpl;
- private List<Future<?>> subTasks;
-
- // Communicating over this socket.
- private Socket socket;
-
- // The necessary classes to do a compilation.
- private com.sun.tools.javac.api.JavacTool compiler;
- private StandardJavaFileManager fileManager;
- private SmartFileManager smartFileManager;
- private Context context;
-
- // If true, then this thread is serving a request.
- private boolean inUse = false;
-
- CompilerThread(CompilerPool cp, JavacServiceImpl javacServiceImpl) {
- compilerPool = cp;
- javacServer = cp.getJavacServer();
- this.javacServiceImpl = javacServiceImpl;
- }
-
- /**
- * Execute a minor task, for example generating bytecodes and writing them to disk,
- * that belong to a major compiler thread task.
- */
- public synchronized void executeSubtask(Runnable r) {
- subTasks.add(compilerPool.executeSubtask(this, r));
- }
-
- /**
- * Count the number of active sub tasks.
- */
- public synchronized int numActiveSubTasks() {
- int c = 0;
- for (Future<?> f : subTasks) {
- if (!f.isDone() && !f.isCancelled()) {
- c++;
- }
- }
- return c;
- }
-
- /**
- * Use this socket for the upcoming request.
- */
- public void setSocket(Socket s) {
- socket = s;
- }
-
- /**
- * Prepare the compiler thread for use. It is not yet started.
- * It will be started by the executor service.
- */
- public synchronized void use() {
- assert(!inUse);
- inUse = true;
- compiler = com.sun.tools.javac.api.JavacTool.create();
- fileManager = compiler.getStandardFileManager(null, null, null);
- smartFileManager = new SmartFileManager(fileManager);
- context = new Context();
- ResolveWithDeps.preRegister(context);
- AttrWithDeps.preRegister(context);
- JavaCompilerWithDeps.preRegister(context, javacServiceImpl);
- subTasks = new ArrayList<>();
- }
-
- /**
- * Prepare the compiler thread for idleness.
- */
- public synchronized void unuse() {
- assert(inUse);
- inUse = false;
- compiler = null;
- fileManager = null;
- smartFileManager = null;
- context = null;
- subTasks = null;
- }
-
- /**
- * Expect this key on the next line read from the reader.
- */
- private static boolean expect(BufferedReader in, String key) throws IOException {
- String s = in.readLine();
- if (s != null && s.equals(key)) {
- return true;
- }
- return false;
- }
-
- // The request identifier, for example GENERATE_NEWBYTECODE
- String id = "";
-
- public String currentRequestId() {
- return id;
- }
-
- PrintWriter stdout;
- PrintWriter stderr;
- int forcedExitCode = 0;
-
- public void logError(String msg) {
- stderr.println(msg);
- forcedExitCode = -1;
- }
-
- /**
- * Invoked by the executor service.
- */
- public void run() {
- // Unique nr that identifies this request.
- int thisRequest = compilerPool.startRequest();
- long start = System.currentTimeMillis();
- int numClasses = 0;
- StringBuilder compiledPkgs = new StringBuilder();
- use();
-
- PrintWriter out = null;
- try {
- javacServer.log("<"+thisRequest+"> Connect from "+socket.getRemoteSocketAddress()+" activethreads="+compilerPool.numActiveRequests());
- BufferedReader in = new BufferedReader(new InputStreamReader(
- socket.getInputStream()));
- out = new PrintWriter(new OutputStreamWriter(
- socket.getOutputStream()));
- if (!expect(in, JavacServer.PROTOCOL_COOKIE_VERSION)) {
- javacServer.log("<"+thisRequest+"> Bad protocol from ip "+socket.getRemoteSocketAddress());
- return;
- }
-
- String cookie = in.readLine();
- if (cookie == null || !cookie.equals(""+javacServer.getCookie())) {
- javacServer.log("<"+thisRequest+"> Bad cookie from ip "+socket.getRemoteSocketAddress());
- return;
- }
- if (!expect(in, JavacServer.PROTOCOL_CWD)) {
- return;
- }
- String cwd = in.readLine();
- if (cwd == null)
- return;
- if (!expect(in, JavacServer.PROTOCOL_ID)) {
- return;
- }
- id = in.readLine();
- if (id == null)
- return;
- if (!expect(in, JavacServer.PROTOCOL_ARGS)) {
- return;
- }
- ArrayList<String> the_options = new ArrayList<>();
- ArrayList<File> the_classes = new ArrayList<>();
- Iterable<File> path = Arrays.<File> asList(new File(cwd));
-
- for (;;) {
- String l = in.readLine();
- if (l == null)
- return;
- if (l.equals(JavacServer.PROTOCOL_SOURCES_TO_COMPILE))
- break;
- if (l.startsWith("--server:"))
- continue;
- if (!l.startsWith("-") && l.endsWith(".java")) {
- the_classes.add(new File(l));
- numClasses++;
- } else {
- the_options.add(l);
- }
- continue;
- }
-
- // Load sources to compile
- Set<URI> sourcesToCompile = new HashSet<>();
- for (;;) {
- String l = in.readLine();
- if (l == null)
- return;
- if (l.equals(JavacServer.PROTOCOL_VISIBLE_SOURCES))
- break;
- try {
- sourcesToCompile.add(new URI(l));
- numClasses++;
- } catch (URISyntaxException e) {
- return;
- }
- }
- // Load visible sources
- Set<URI> visibleSources = new HashSet<>();
- boolean fix_drive_letter_case =
- StringUtils.toLowerCase(System.getProperty("os.name")).startsWith("windows");
- for (;;) {
- String l = in.readLine();
- if (l == null)
- return;
- if (l.equals(JavacServer.PROTOCOL_END))
- break;
- try {
- URI u = new URI(l);
- if (fix_drive_letter_case) {
- // Make sure the driver letter is lower case.
- String s = u.toString();
- if (s.startsWith("file:/") &&
- Character.isUpperCase(s.charAt(6))) {
- u = new URI("file:/"+Character.toLowerCase(s.charAt(6))+s.substring(7));
- }
- }
- visibleSources.add(u);
- } catch (URISyntaxException e) {
- return;
- }
- }
-
- // A completed request has been received.
-
- // Now setup the actual compilation....
- // First deal with explicit source files on cmdline and in at file.
- ListBuffer<JavaFileObject> compilationUnits = new ListBuffer<>();
- for (JavaFileObject i : fileManager.getJavaFileObjectsFromFiles(the_classes)) {
- compilationUnits.append(i);
- }
- // Now deal with sources supplied as source_to_compile.
- ListBuffer<File> sourcesToCompileFiles = new ListBuffer<>();
- for (URI u : sourcesToCompile) {
- sourcesToCompileFiles.append(new File(u));
- }
- for (JavaFileObject i : fileManager.getJavaFileObjectsFromFiles(sourcesToCompileFiles)) {
- compilationUnits.append(i);
- }
- // Log the options to be used.
- StringBuilder options = new StringBuilder();
- for (String s : the_options) {
- options.append(">").append(s).append("< ");
- }
- javacServer.log(id+" <"+thisRequest+"> options "+options.toString());
-
- forcedExitCode = 0;
- // Create a new logger.
- StringWriter stdoutLog = new StringWriter();
- StringWriter stderrLog = new StringWriter();
- stdout = new PrintWriter(stdoutLog);
- stderr = new PrintWriter(stderrLog);
- com.sun.tools.javac.main.Main.Result rc = com.sun.tools.javac.main.Main.Result.OK;
- try {
- if (compilationUnits.size() > 0) {
- smartFileManager.setVisibleSources(visibleSources);
- smartFileManager.cleanArtifacts();
- smartFileManager.setLog(stdout);
-
- // Do the compilation!
- CompilationTask task = compiler.getTask(stderr, smartFileManager, null, the_options, null, compilationUnits, context);
- smartFileManager.setSymbolFileEnabled(!Options.instance(context).isSet("ignore.symbol.file"));
- rc = ((JavacTaskImpl) task).doCall();
-
- while (numActiveSubTasks()>0) {
- try { Thread.sleep(1000); } catch (InterruptedException e) { }
- }
-
- smartFileManager.flush();
- }
- } catch (Exception e) {
- stderr.println(e.getMessage());
- forcedExitCode = -1;
- }
-
- // Send the response..
- out.println(JavacServer.PROTOCOL_STDOUT);
- out.print(stdoutLog);
- out.println(JavacServer.PROTOCOL_STDERR);
- out.print(stderrLog);
- // The compilation is complete! And errors will have already been printed on out!
- out.println(JavacServer.PROTOCOL_PACKAGE_ARTIFACTS);
- Map<String,Set<URI>> pa = smartFileManager.getPackageArtifacts();
- for (String aPkgName : pa.keySet()) {
- out.println("+"+aPkgName);
- Set<URI> as = pa.get(aPkgName);
- for (URI a : as) {
- out.println(" "+a.toString());
- }
- }
- Dependencies deps = Dependencies.instance(context);
- out.println(JavacServer.PROTOCOL_PACKAGE_DEPENDENCIES);
- Map<String,Set<String>> pd = deps.getDependencies();
- for (String aPkgName : pd.keySet()) {
- out.println("+"+aPkgName);
- Set<String> ds = pd.get(aPkgName);
- // Everything depends on java.lang
- if (!ds.contains(":java.lang")) ds.add(":java.lang");
- for (String d : ds) {
- out.println(" "+d);
- }
- }
- out.println(JavacServer.PROTOCOL_PACKAGE_PUBLIC_APIS);
- Map<String,String> pp = deps.getPubapis();
- for (String aPkgName : pp.keySet()) {
- out.println("+"+aPkgName);
- String ps = pp.get(aPkgName);
- // getPubapis added a space to each line!
- out.println(ps);
- compiledPkgs.append(aPkgName+" ");
- }
- out.println(JavacServer.PROTOCOL_SYSINFO);
- out.println("num_cores=" + Runtime.getRuntime().availableProcessors());
- out.println("max_memory=" + Runtime.getRuntime().maxMemory());
- out.println(JavacServer.PROTOCOL_RETURN_CODE);
-
- // Errors from sjavac that affect compilation status!
- int rcv = rc.exitCode;
- if (rcv == 0 && forcedExitCode != 0) {
- rcv = forcedExitCode;
- }
- out.println("" + rcv);
- out.println(JavacServer.PROTOCOL_END);
- out.flush();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- try {
- if (out != null) out.close();
- if (!socket.isClosed()) {
- socket.close();
- }
- socket = null;
- } catch (Exception e) {
- javacServer.log("ERROR "+e);
- e.printStackTrace();
- }
- compilerPool.stopRequest();
- long duration = System.currentTimeMillis()-start;
- javacServer.addBuildTime(duration);
- float classpersec = ((float)numClasses)*(((float)1000.0)/((float)duration));
- javacServer.log(id+" <"+thisRequest+"> "+compiledPkgs+" duration " + duration+ " ms num_classes="+numClasses+
- " classpersec="+classpersec+" subtasks="+subTasks.size());
- javacServer.flushLog();
- unuse();
- compilerPool.returnCompilerThread(this);
- }
- }
-}
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/IdleResetSjavac.java Wed Aug 13 14:44:59 2014 +0200
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.tools.sjavac.server;
+
+import java.io.File;
+import java.net.URI;
+import java.util.List;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * An sjavac implementation that keeps track of idleness and shuts down the
+ * given Terminable upon idleness timeout.
+ *
+ * An idleness timeout kicks in {@code idleTimeout} milliseconds after the last
+ * request is completed.
+ *
+ * <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 subject to change or
+ * deletion without notice.</b>
+ */
+public class IdleResetSjavac implements Sjavac {
+
+ private final Sjavac delegate;
+ private final AtomicInteger outstandingCalls = new AtomicInteger();
+ private final Terminable toShutdown;
+ private final Timer idlenessTimer = new Timer();
+ private final long idleTimeout;
+
+ // Class invariant: idlenessTimerTask != null <-> idlenessTimerTask is scheduled
+ private TimerTask idlenessTimerTask;
+
+ public IdleResetSjavac(Sjavac delegate,
+ Terminable toShutdown,
+ long idleTimeout) {
+ this.delegate = delegate;
+ this.toShutdown = toShutdown;
+ this.idleTimeout = idleTimeout;
+ scheduleTimeout();
+ }
+
+ @Override
+ public SysInfo getSysInfo() {
+ startCall();
+ try {
+ return delegate.getSysInfo();
+ } finally {
+ endCall();
+ }
+ }
+
+ @Override
+ public CompilationResult compile(String protocolId,
+ String invocationId,
+ String[] args,
+ List<File> explicitSources,
+ Set<URI> sourcesToCompile,
+ Set<URI> visibleSources) {
+ startCall();
+ try {
+ return delegate.compile(protocolId,
+ invocationId,
+ args,
+ explicitSources,
+ sourcesToCompile,
+ visibleSources);
+ } finally {
+ endCall();
+ }
+ }
+
+ private void startCall() {
+ // Was there no outstanding calls before this call?
+ if (outstandingCalls.incrementAndGet() == 1) {
+ // Then the timer task must have been scheduled
+ if (idlenessTimerTask == null)
+ throw new IllegalStateException("Idle timeout already cancelled");
+ // Cancel timeout task
+ idlenessTimerTask.cancel();
+ idlenessTimerTask = null;
+ }
+ }
+
+ private void endCall() {
+ if (outstandingCalls.decrementAndGet() == 0) {
+ // No more outstanding calls. Schedule timeout.
+ scheduleTimeout();
+ }
+ }
+
+ private void scheduleTimeout() {
+ if (idlenessTimerTask != null)
+ throw new IllegalStateException("Idle timeout already scheduled");
+ idlenessTimerTask = new TimerTask() {
+ public void run() {
+ toShutdown.shutdown("Server has been idle for " + (idleTimeout / 1000) + " seconds.");
+ }
+ };
+ idlenessTimer.schedule(idlenessTimerTask, idleTimeout);
+ }
+
+ @Override
+ public void shutdown() {
+ idlenessTimer.cancel();
+ delegate.shutdown();
+ }
+
+ @Override
+ public String serverSettings() {
+ return delegate.serverSettings();
+ }
+}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/server/JavacServer.java Tue Aug 12 17:48:30 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,382 +0,0 @@
-/*
- * Copyright (c) 2011-2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.sun.tools.sjavac.server;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.FileNotFoundException;
-import java.util.HashMap;
-import java.util.Map;
-
-import java.net.InetAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.util.ArrayList;
-import java.util.Random;
-
-import com.sun.tools.sjavac.Util;
-import com.sun.tools.sjavac.ProblemException;
-import java.io.*;
-
-/**
- * The JavacServer class contains methods both to setup a server that responds to requests and methods to connect to this server.
- *
- * <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
- * subject to change or deletion without notice.</b></p>
- */
-public class JavacServer {
- // Responding to this tcp/ip port on localhost.
-
- private final ServerSocket serverSocket;
- // The secret cookie shared between server and client through the port file.
- private final long myCookie;
- // When the server was started.
- private long serverStart;
- // Accumulated build time for all requests, not counting idle time.
- private long totalBuildTime;
- // The javac server specific log file.
- PrintWriter theLog;
- // The compiler pool that maintains the compiler threads.
- CompilerPool compilerPool;
- // For the client, all port files fetched, one per started javac server.
- // Though usually only one javac server is started by a client.
- private static Map<String, PortFile> allPortFiles;
- private static Map<String, Long> maxServerMemory;
- final static String PROTOCOL_COOKIE_VERSION = "----THE-COOKIE-V2----";
- final static String PROTOCOL_CWD = "----THE-CWD----";
- final static String PROTOCOL_ID = "----THE-ID----";
- final static String PROTOCOL_ARGS = "----THE-ARGS----";
- final static String PROTOCOL_SOURCES_TO_COMPILE = "----THE-SOURCES-TO-COMPILE----";
- final static String PROTOCOL_VISIBLE_SOURCES = "----THE-VISIBLE-SOURCES----";
- final static String PROTOCOL_END = "----THE-END----";
- final static String PROTOCOL_STDOUT = "----THE-STDOUT----";
- final static String PROTOCOL_STDERR = "----THE-STDERR----";
- final static String PROTOCOL_PACKAGE_ARTIFACTS = "----THE-PACKAGE_ARTIFACTS----";
- final static String PROTOCOL_PACKAGE_DEPENDENCIES = "----THE-PACKAGE_DEPENDENCIES----";
- final static String PROTOCOL_PACKAGE_PUBLIC_APIS = "----THE-PACKAGE-PUBLIC-APIS----";
- final static String PROTOCOL_SYSINFO = "----THE-SYSINFO----";
- final static String PROTOCOL_RETURN_CODE = "----THE-RETURN-CODE----";
- // Check if the portfile is gone, every 5 seconds.
- static int CHECK_PORTFILE_INTERVAL = 5;
- // Wait 2 seconds for response, before giving up on javac server.
- static int CONNECTION_TIMEOUT = 2;
- static int WAIT_BETWEEN_CONNECT_ATTEMPTS = 1;
- static int MAX_NUM_CONNECT_ATTEMPTS = 3;
-
- /**
- * Acquire the port file. Synchronized since several threads inside an smart javac wrapper client acquires the same port file at the same time.
- */
- public static synchronized PortFile getPortFile(String filename) throws FileNotFoundException {
- if (allPortFiles == null) {
- allPortFiles = new HashMap<>();
- }
- PortFile pf = allPortFiles.get(filename);
-
- // Port file known. Does it still exist?
- if (pf != null) {
- try {
- if (!pf.exists())
- pf = null;
- } catch (IOException ioex) {
- ioex.printStackTrace();
- }
- }
-
- if (pf == null) {
- pf = new PortFile(filename);
- allPortFiles.put(filename, pf);
- }
- return pf;
- }
-
- /**
- * Get the cookie used for this server.
- */
- long getCookie() {
- return myCookie;
- }
-
- /**
- * Get the port used for this server.
- */
- int getPort() {
- return serverSocket.getLocalPort();
- }
-
- /**
- * Sum up the total build time for this javac server.
- */
- public void addBuildTime(long inc) {
- totalBuildTime += inc;
- }
-
- /**
- * Log this message.
- */
- public void log(String msg) {
- if (theLog != null) {
- theLog.println(msg);
- } else {
- System.err.println(msg);
- }
- }
-
- /**
- * Make sure the log is flushed.
- */
- public void flushLog() {
- if (theLog != null) {
- theLog.flush();
- }
- }
-
- /**
- * Start a server using a settings string. Typically: "--startserver:portfile=/tmp/myserver,poolsize=3" and the string "portfile=/tmp/myserver,poolsize=3"
- * is sent as the settings parameter. Returns 0 on success, -1 on failure.
- */
- public static int startServer(String settings, PrintStream err) {
- try {
- String portfile = Util.extractStringOption("portfile", settings);
- // The log file collects more javac server specific log information.
- String logfile = Util.extractStringOption("logfile", settings);
- // The stdouterr file collects all the System.out and System.err writes to disk.
- String stdouterrfile = Util.extractStringOption("stdouterrfile", settings);
- // We could perhaps use System.setOut and setErr here.
- // But for the moment we rely on the client to spawn a shell where stdout
- // and stderr are redirected already.
- // The pool size is a limit the number of concurrent compiler threads used.
- // The server might use less than these to avoid memory problems.
- int defaultPoolSize = Runtime.getRuntime().availableProcessors();
- int poolsize = Util.extractIntOption("poolsize", settings, defaultPoolSize);
-
- // How many seconds of inactivity will the server accept before quitting?
- int keepalive = Util.extractIntOption("keepalive", settings, 120);
-
- // The port file is locked and the server port and cookie is written into it.
- PortFile portFile = getPortFile(portfile);
- JavacServer s;
-
- synchronized (portFile) {
- portFile.lock();
- portFile.getValues();
- if (portFile.containsPortInfo()) {
- err.println("Javac server not started because portfile exists!");
- portFile.unlock();
- return -1;
- }
- s = new JavacServer(poolsize, logfile);
- portFile.setValues(s.getPort(), s.getCookie());
- portFile.unlock();
- }
-
- // Run the server. Will delete the port file when shutting down.
- // It will shut down automatically when no new requests have come in
- // during the last 125 seconds.
- s.run(portFile, err, keepalive);
- // The run loop for the server has exited.
- return 0;
- } catch (Exception e) {
- e.printStackTrace(err);
- return -1;
- }
- }
-
- /**
- * Spawn the server instance.
- */
-
- private JavacServer(int poolSize, String logfile) throws IOException {
- serverStart = System.currentTimeMillis();
- // Create a server socket on a random port that is bound to the localhost/127.0.0.1 interface.
- // I.e only local processes can connect to this port.
- serverSocket = new ServerSocket(0, 128, InetAddress.getByName(null));
- compilerPool = new CompilerPool(poolSize, this);
- Random rnd = new Random();
- myCookie = rnd.nextLong();
- theLog = new PrintWriter(logfile);
- log("Javac server started. port=" + getPort() + " date=" + (new java.util.Date()) + " with poolsize=" + poolSize);
- flushLog();
- }
-
- /**
- * Fork a background process. Returns the command line used that can be printed if something failed.
- */
- public static String fork(String sjavac, String portfile, String logfile, int poolsize, int keepalive,
- final PrintStream err, String stdouterrfile, boolean background)
- throws IOException, ProblemException {
- if (stdouterrfile != null && stdouterrfile.trim().equals("")) {
- stdouterrfile = null;
- }
- final String startserver = "--startserver:portfile=" + portfile + ",logfile=" + logfile + ",stdouterrfile=" + stdouterrfile + ",poolsize=" + poolsize + ",keepalive="+ keepalive;
-
- if (background) {
- sjavac += "%20" + startserver;
- sjavac = sjavac.replaceAll("%20", " ");
- sjavac = sjavac.replaceAll("%2C", ",");
- // If the java/sh/cmd launcher fails the failure will be captured by stdouterr because of the redirection here.
- String[] cmd = {"/bin/sh", "-c", sjavac + " >> " + stdouterrfile + " 2>&1"};
- if (!(new File("/bin/sh")).canExecute()) {
- ArrayList<String> wincmd = new ArrayList<>();
- wincmd.add("cmd");
- wincmd.add("/c");
- wincmd.add("start");
- wincmd.add("cmd");
- wincmd.add("/c");
- wincmd.add(sjavac + " >> " + stdouterrfile + " 2>&1");
- cmd = wincmd.toArray(new String[wincmd.size()]);
- }
- Process pp = null;
- try {
- pp = Runtime.getRuntime().exec(cmd);
- } catch (Exception e) {
- e.printStackTrace(err);
- e.printStackTrace(new PrintWriter(stdouterrfile));
- }
- StringBuilder rs = new StringBuilder();
- for (String s : cmd) {
- rs.append(s + " ");
- }
- return rs.toString();
- }
-
- // Do not spawn a background server, instead run it within the same JVM.
- Thread t = new Thread() {
- @Override
- public void run() {
- try {
- JavacServer.startServer(startserver, err);
- } catch (Throwable t) {
- t.printStackTrace(err);
- }
- }
- };
- t.start();
- return "";
- }
-
- /**
- * 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
- * javac server.
- */
- private void run(PortFile portFile, PrintStream err, int keepalive) {
- boolean fileDeleted = false;
- long timeSinceLastCompile;
- try {
- // Every 5 second (check_portfile_interval) we test if the portfile has disappeared => quit
- // Or if the last request was finished more than 125 seconds ago => quit
- // 125 = seconds_of_inactivity_before_shutdown+check_portfile_interval
- serverSocket.setSoTimeout(CHECK_PORTFILE_INTERVAL*1000);
- for (;;) {
- try {
- Socket s = serverSocket.accept();
- CompilerThread ct = compilerPool.grabCompilerThread();
- ct.setSocket(s);
- compilerPool.execute(ct);
- flushLog();
- } catch (java.net.SocketTimeoutException e) {
- if (compilerPool.numActiveRequests() > 0) {
- // Never quit while there are active requests!
- continue;
- }
- // If this is the timeout after the portfile
- // has been deleted by us. Then we truly stop.
- if (fileDeleted) {
- log("Quitting because of "+(keepalive+CHECK_PORTFILE_INTERVAL)+" seconds of inactivity!");
- break;
- }
- // Check if the portfile is still there.
- if (!portFile.exists()) {
- // Time to quit because the portfile was deleted by another
- // process, probably by the makefile that is done building.
- log("Quitting because portfile was deleted!");
- flushLog();
- break;
- }
- // Check if portfile.stop is still there.
- if (portFile.markedForStop()) {
- // Time to quit because another process touched the file
- // server.port.stop to signal that the server should stop.
- // This is necessary on some operating systems that lock
- // the port file hard!
- log("Quitting because a portfile.stop file was found!");
- portFile.delete();
- flushLog();
- break;
- }
- // Does the portfile still point to me?
- if (!portFile.stillMyValues()) {
- // Time to quit because another build has started.
- log("Quitting because portfile is now owned by another javac server!");
- flushLog();
- break;
- }
-
- // Check how long since the last request finished.
- long diff = System.currentTimeMillis() - compilerPool.lastRequestFinished();
- if (diff < keepalive * 1000) {
- // Do not quit if we have waited less than 120 seconds.
- continue;
- }
- // Ok, time to quit because of inactivity. Perhaps the build
- // was killed and the portfile not cleaned up properly.
- portFile.delete();
- fileDeleted = true;
- log("" + keepalive + " seconds of inactivity quitting in "
- + CHECK_PORTFILE_INTERVAL + " seconds!");
- flushLog();
- // Now we have a second 5 second grace
- // period where javac remote requests
- // that have loaded the data from the
- // recently deleted portfile can connect
- // and complete their requests.
- }
- }
- } catch (Exception e) {
- e.printStackTrace(err);
- e.printStackTrace(theLog);
- flushLog();
- } finally {
- compilerPool.shutdown();
- }
- long realTime = System.currentTimeMillis() - serverStart;
- log("Shutting down.");
- log("Total wall clock time " + realTime + "ms build time " + totalBuildTime + "ms");
- flushLog();
- }
-
- public static void cleanup(String... args) {
- String settings = Util.findServerSettings(args);
- if (settings == null) return;
- String portfile = Util.extractStringOption("portfile", settings);
- String background = Util.extractStringOption("background", settings);
- if (background != null && background.equals("false")) {
- // If the server runs within this jvm, then delete the portfile,
- // since this jvm is about to exit soon.
- File f = new File(portfile);
- f.delete();
- }
- }
-}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/server/JavacService.java Tue Aug 12 17:48:30 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.tools.sjavac.server;
-
-import java.io.File;
-import java.net.URI;
-import java.util.List;
-import java.util.Set;
-
-public interface JavacService {
-
- SysInfo getSysInfo();
-
- CompilationResult compile(String protocolId,
- String invocationId,
- String[] args,
- List<File> explicitSources,
- Set<URI> sourcesToCompile,
- Set<URI> visibleSources);
- String serverSettings();
-}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/server/JavacServiceClient.java Tue Aug 12 17:48:30 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,449 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.tools.sjavac.server;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.URI;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import com.sun.tools.sjavac.Util;
-import com.sun.tools.sjavac.options.Options;
-
-import static com.sun.tools.sjavac.server.CompilationResult.ERROR_BUT_TRY_AGAIN;
-import static com.sun.tools.sjavac.server.CompilationResult.ERROR_FATAL;
-
-public class JavacServiceClient implements JavacService {
-
-
- // The id can perhaps be used in the future by the javac server to reuse the
- // JavaCompiler instance for several compiles using the same id.
- private final String id;
- private final String portfile;
- private final String logfile;
- private final String stdouterrfile;
- private final boolean background;
-
- // Default keepalive for server is 120 seconds.
- // I.e. it will accept 120 seconds of inactivity before quitting.
- private final int keepalive;
- private final int poolsize;
-
- // The sjavac option specifies how the server part of sjavac is spawned.
- // If you have the experimental sjavac in your path, you are done. If not, you have
- // to point to a com.sun.tools.sjavac.Main that supports --startserver
- // for example by setting: sjavac=java%20-jar%20...javac.jar%com.sun.tools.sjavac.Main
- private final String sjavac;
-
- // Store the server conf settings here.
- private final String settings;
-
- public JavacServiceClient(Options options) {
- String tmpServerConf = options.getServerConf();
- String serverConf = (tmpServerConf!=null)? tmpServerConf : "";
- String tmpId = Util.extractStringOption("id", serverConf);
- id = (tmpId!=null) ? tmpId : "id"+(((new java.util.Random()).nextLong())&Long.MAX_VALUE);
- String p = Util.extractStringOption("portfile", serverConf);
- portfile = (p!=null) ? p : options.getStateDir().toFile().getAbsolutePath()+File.separatorChar+"javac_server";
- logfile = Util.extractStringOption("logfile", serverConf, portfile + ".javaclog");
- stdouterrfile = Util.extractStringOption("stdouterrfile", serverConf, portfile + ".stdouterr");
- background = Util.extractBooleanOption("background", serverConf, true);
- sjavac = Util.extractStringOption("sjavac", serverConf, "sjavac");
- int poolsize = Util.extractIntOption("poolsize", serverConf);
- keepalive = Util.extractIntOption("keepalive", serverConf, 120);
-
- this.poolsize = poolsize > 0 ? poolsize : Runtime.getRuntime().availableProcessors();
- settings = (serverConf.equals("")) ? "id="+id+",portfile="+portfile : serverConf;
- }
-
- /**
- * Hand out the server settings.
- * @return The server settings, possibly a default value.
- */
- public String serverSettings() {
- return settings;
- }
-
- /**
- * Make a request to the server only to get the maximum possible heap size to use for compilations.
- *
- * @param port_file The port file used to synchronize creation of this server.
- * @param id The identify of the compilation.
- * @param out Standard out information.
- * @param err Standard err information.
- * @return The maximum heap size in bytes.
- */
- @Override
- public SysInfo getSysInfo() {
- try {
- CompilationResult cr = useServer(new String[0],
- Collections.<URI>emptySet(),
- Collections.<URI>emptySet(),
- Collections.<URI, Set<String>>emptyMap());
- return cr.sysinfo;
- } catch (Exception e) {
- return new SysInfo(-1, -1);
- }
- }
-
- @Override
- public CompilationResult compile(String protocolId,
- String invocationId,
- String[] args,
- List<File> explicitSources,
- Set<URI> sourcesToCompile,
- Set<URI> visibleSources) {
- // Delegate to useServer, which delegates to compileHelper
- return useServer(args, sourcesToCompile, visibleSources, null);
- }
-
- /**
- * Connect and compile using the javac server settings and the args. When using more advanced features, the sources_to_compile and visible_sources are
- * supplied to the server and meta data is returned in package_artifacts, package_dependencies and package_pubapis.
- */
- public CompilationResult compileHelper(String id,
- String[] args,
- Set<URI> sourcesToCompile,
- Set<URI> visibleSources) {
-
- CompilationResult rc = new CompilationResult(-3);
-
- try {
- PortFile portFile = JavacServer.getPortFile(this.portfile);
-
- int port = portFile.containsPortInfo() ? portFile.getPort() : 0;
- if (port == 0) {
- return new CompilationResult(ERROR_BUT_TRY_AGAIN);
- }
- long cookie = portFile.getCookie();
- // Acquire the localhost/127.0.0.1 address.
- InetAddress addr = InetAddress.getByName(null);
- SocketAddress sockaddr = new InetSocketAddress(addr, port);
- Socket sock = new Socket();
- int timeoutMs = JavacServer.CONNECTION_TIMEOUT * 1000;
- try {
- sock.connect(sockaddr, timeoutMs);
- } catch (java.net.ConnectException e) {
- rc.setReturnCode(ERROR_BUT_TRY_AGAIN);
- rc.stderr = "Could not connect to javac server found in portfile: " + portFile.getFilename() + " " + e;
- return rc;
- }
- if (!sock.isConnected()) {
- rc.setReturnCode(ERROR_BUT_TRY_AGAIN);
- rc.stderr = "Could not connect to javac server found in portfile: " + portFile.getFilename();
- return rc;
- }
-
- //
- // Send arguments
- //
- BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
- PrintWriter sockout = new PrintWriter(sock.getOutputStream());
-
- sockout.println(JavacServer.PROTOCOL_COOKIE_VERSION);
- sockout.println("" + cookie);
- sockout.println(JavacServer.PROTOCOL_CWD);
- sockout.println(System.getProperty("user.dir"));
- sockout.println(JavacServer.PROTOCOL_ID);
- sockout.println(id);
- sockout.println(JavacServer.PROTOCOL_ARGS);
- for (String s : args) {
- StringBuffer buf = new StringBuffer();
- String[] paths = s.split(File.pathSeparator);
- int c = 0;
- for (String path : paths) {
- File f = new File(path);
- if (f.isFile() || f.isDirectory()) {
- buf.append(f.getAbsolutePath());
- c++;
- if (c < paths.length) {
- buf.append(File.pathSeparator);
- }
- } else {
- buf = new StringBuffer(s);
- break;
- }
- }
- sockout.println(buf.toString());
- }
- sockout.println(JavacServer.PROTOCOL_SOURCES_TO_COMPILE);
- for (URI uri : sourcesToCompile) {
- sockout.println(uri.toString());
- }
- sockout.println(JavacServer.PROTOCOL_VISIBLE_SOURCES);
- for (URI uri : visibleSources) {
- sockout.println(uri.toString());
- }
- sockout.println(JavacServer.PROTOCOL_END);
- sockout.flush();
-
- //
- // Receive result
- //
- StringBuffer stdout = new StringBuffer();
- StringBuffer stderr = new StringBuffer();
-
- if (!JavacServiceClient.expect(in, JavacServer.PROTOCOL_STDOUT)) {
- return new CompilationResult(ERROR_FATAL);
- }
- // Load stdout
- for (;;) {
- String l = in.readLine();
- if (l == null) {
- return new CompilationResult(ERROR_FATAL);
- }
- if (l.equals(JavacServer.PROTOCOL_STDERR)) {
- break;
- }
- stdout.append(l);
- stdout.append('\n');
- }
- // Load stderr
- for (;;) {
- String l = in.readLine();
- if (l == null) {
- return new CompilationResult(ERROR_FATAL);
- }
- if (l.equals(JavacServer.PROTOCOL_PACKAGE_ARTIFACTS)) {
- break;
- }
- stderr.append(l);
- stderr.append('\n');
- }
- // Load the package artifacts
- Set<URI> lastUriSet = null;
- for (;;) {
- String l = in.readLine();
- if (l == null) {
- return new CompilationResult(ERROR_FATAL);
- }
- if (l.equals(JavacServer.PROTOCOL_PACKAGE_DEPENDENCIES)) {
- break;
- }
- if (l.length() > 1 && l.charAt(0) == '+') {
- String pkg = l.substring(1);
- lastUriSet = new HashSet<>();
- rc.packageArtifacts.put(pkg, lastUriSet);
- } else if (l.length() > 1 && lastUriSet != null) {
- lastUriSet.add(new URI(l.substring(1)));
- }
- }
- // Load package dependencies
- Set<String> lastPackageSet = null;
- for (;;) {
- String l = in.readLine();
- if (l == null) {
- return new CompilationResult(ERROR_FATAL);
- }
- if (l.equals(JavacServer.PROTOCOL_PACKAGE_PUBLIC_APIS)) {
- break;
- }
- if (l.length() > 1 && l.charAt(0) == '+') {
- String pkg = l.substring(1);
- lastPackageSet = new HashSet<>();
- rc.packageDependencies.put(pkg, lastPackageSet);
- } else if (l.length() > 1 && lastPackageSet != null) {
- lastPackageSet.add(l.substring(1));
- }
- }
- // Load package pubapis
- Map<String, StringBuffer> tmp = new HashMap<>();
- StringBuffer lastPublicApi = null;
- for (;;) {
- String l = in.readLine();
- if (l == null) {
- return new CompilationResult(ERROR_FATAL);
- }
- if (l.equals(JavacServer.PROTOCOL_SYSINFO)) {
- break;
- }
- if (l.length() > 1 && l.charAt(0) == '+') {
- String pkg = l.substring(1);
- lastPublicApi = new StringBuffer();
- tmp.put(pkg, lastPublicApi);
- } else if (l.length() > 1 && lastPublicApi != null) {
- lastPublicApi.append(l.substring(1));
- lastPublicApi.append("\n");
- }
- }
- for (String p : tmp.keySet()) {
- //assert (packagePublicApis.get(p) == null);
- String api = tmp.get(p).toString();
- rc.packagePubapis.put(p, api);
- }
- // Now reading the max memory possible.
- for (;;) {
- String l = in.readLine();
- if (l == null) {
- return new CompilationResult(ERROR_FATAL);
- }
- if (l.equals(JavacServer.PROTOCOL_RETURN_CODE)) {
- break;
- }
- if (l.startsWith("num_cores=")) {
- rc.sysinfo.numCores = Integer.parseInt(l.substring(10));
- }
- if (l.startsWith("max_memory=")) {
- rc.sysinfo.maxMemory = Long.parseLong(l.substring(11));
- }
- }
- String l = in.readLine();
- if (l == null) {
- rc.setReturnCode(ERROR_FATAL);
- rc.stderr = "No return value from the server!";
- return rc;
- }
- rc.setReturnCode(Integer.parseInt(l));
- rc.stdout = stdout.toString();
- rc.stderr = stderr.toString();
- } catch (Exception e) {
- StringWriter sw = new StringWriter();
- e.printStackTrace(new PrintWriter(sw));
- rc.stderr = sw.toString();
- }
- return rc;
- }
-
- /**
- * Dispatch a compilation request to a javac server.
- *
- * @param args are the command line args to javac and is allowed to contain source files, @file and other command line options to javac.
- *
- * The generated classes, h files and other artifacts from the javac invocation are stored by the javac server to disk.
- *
- * @param sources_to_compile The sources to compile.
- *
- * @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!
- * (Sources to compile are always visible.) The visible sources are those supplied by the (filtered) -sourcepath
- *
- * @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
- * 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.
- *
- * The server return meta data about the build in the following parameters.
- * @param package_artifacts, map from package name to set of created artifacts for that package.
- * @param package_dependencies, map from package name to set of packages that it depends upon.
- * @param package_pubapis, map from package name to unique string identifying its pub api.
- */
- public CompilationResult useServer(String[] args,
- Set<URI> sourcesToCompile,
- Set<URI> visibleSources,
- Map<URI, Set<String>> visibleClasses) {
- try {
- if (portfile == null) {
- CompilationResult cr = new CompilationResult(CompilationResult.ERROR_FATAL);
- cr.stderr = "No portfile was specified!";
- return cr;
- }
-
- int attempts = 0;
- CompilationResult rc;
- do {
- PortFile port_file = JavacServer.getPortFile(portfile);
- synchronized (port_file) {
- port_file.lock();
- port_file.getValues();
- port_file.unlock();
- }
- if (!port_file.containsPortInfo()) {
- String cmd = JavacServer.fork(sjavac, port_file.getFilename(), logfile, poolsize, keepalive, System.err, stdouterrfile, background);
-
- if (background && !port_file.waitForValidValues()) {
- // Ouch the server did not start! Lets print its stdouterrfile and the command used.
- StringWriter sw = new StringWriter();
- JavacServiceClient.printFailedAttempt(cmd, stdouterrfile, new PrintWriter(sw));
- // And give up.
- CompilationResult cr = new CompilationResult(ERROR_FATAL);
- cr.stderr = sw.toString();
- return cr;
- }
- }
- rc = compileHelper(id, args, sourcesToCompile, visibleSources);
- // Try again until we manage to connect. Any error after that
- // will cause the compilation to fail.
- if (rc.returnCode == CompilationResult.ERROR_BUT_TRY_AGAIN) {
- // We could not connect to the server. Try again.
- attempts++;
- try {
- Thread.sleep(JavacServer.WAIT_BETWEEN_CONNECT_ATTEMPTS * 1000);
- } catch (InterruptedException e) {
- }
- }
- } while (rc.returnCode == ERROR_BUT_TRY_AGAIN && attempts < JavacServer.MAX_NUM_CONNECT_ATTEMPTS);
- return rc;
- } catch (Exception e) {
- StringWriter sw = new StringWriter();
- e.printStackTrace(new PrintWriter(sw));
- CompilationResult cr = new CompilationResult(ERROR_FATAL);
- cr.stderr = sw.toString();
- return cr;
- }
- }
-
- public static void printFailedAttempt(String cmd, String f, PrintWriter err) {
- err.println("---- Failed to start javac server with this command -----");
- err.println(cmd);
- try {
- BufferedReader in = new BufferedReader(new FileReader(f));
- err.println("---- stdout/stderr output from attempt to start javac server -----");
- for (;;) {
- String l = in.readLine();
- if (l == null) {
- break;
- }
- err.println(l);
- }
- err.println("------------------------------------------------------------------");
- } catch (Exception e) {
- err.println("The stdout/stderr output in file " + f + " does not exist and the server did not start.");
- }
- }
-
- /**
- * Expect this key on the next line read from the reader.
- */
- public static boolean expect(BufferedReader in, String key) throws IOException {
- String s = in.readLine();
- if (s != null && s.equals(key)) {
- return true;
- }
- return false;
- }
-}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/server/PortFile.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/PortFile.java Wed Aug 13 14:44:59 2014 +0200
@@ -41,12 +41,12 @@
* primitives to avoid race conditions when several javac clients are started at the same. Note that file
* system locking is not always supported on a all operating systems and/or file systems.
*
- * <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 subject to change
- * or deletion without notice.</b></p>
+ * <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 subject to change or
+ * deletion without notice.</b>
*/
-class PortFile {
+public class PortFile {
// Port file format:
// byte ordering: high byte first = big endian
@@ -72,8 +72,7 @@
* Create a new portfile.
* @param filename is the path to the file.
*/
- public PortFile(String fn) throws FileNotFoundException
- {
+ public PortFile(String fn) throws FileNotFoundException {
filename = fn;
file = new File(filename);
stopFile = new File(filename+".stop");
@@ -88,7 +87,7 @@
/**
* Lock the port file.
*/
- void lock() throws IOException {
+ public void lock() throws IOException {
lock = channel.lock();
}
@@ -115,7 +114,7 @@
containsPortInfo = false;
}
}
- } catch (Exception e) {
+ } catch (IOException e) {
containsPortInfo = false;
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/PortFileMonitor.java Wed Aug 13 14:44:59 2014 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.tools.sjavac.server;
+
+import java.io.IOException;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * Monitors the presence of a port file and shuts down the given SjavacServer
+ * whenever the port file is deleted or invalidated.
+ *
+ * TODO: JDK-8046882
+ *
+ * <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 subject to change or
+ * deletion without notice.</b>
+ */
+public class PortFileMonitor {
+
+ // Check if the portfile is gone, every 5 seconds.
+ private final static int CHECK_PORTFILE_INTERVAL = 5000;
+
+ final private Timer timer = new Timer();
+ final private PortFile portFile;
+ final private SjavacServer server;
+
+ public PortFileMonitor(PortFile portFile,
+ SjavacServer server) {
+ this.portFile = portFile;
+ this.server = server;
+ }
+
+ public void start() {
+ TimerTask shutdownCheck = new TimerTask() {
+ public void run() {
+ try {
+ if (!portFile.exists()) {
+ // Time to quit because the portfile was deleted by another
+ // process, probably by the makefile that is done building.
+ server.shutdown("Quitting because portfile was deleted!");
+ } else if (portFile.markedForStop()) {
+ // Time to quit because another process touched the file
+ // server.port.stop to signal that the server should stop.
+ // This is necessary on some operating systems that lock
+ // the port file hard!
+ server.shutdown("Quitting because a portfile.stop file was found!");
+ } else if (!portFile.stillMyValues()) {
+ // Time to quit because another build has started.
+ server.shutdown("Quitting because portfile is now owned by another javac server!");
+ }
+ } catch (IOException e) {
+ e.printStackTrace(server.theLog);
+ server.flushLog();
+ }
+ }
+ };
+
+ timer.schedule(shutdownCheck, 0, CHECK_PORTFILE_INTERVAL);
+ }
+
+ public void shutdown() {
+ timer.cancel();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/RequestHandler.java Wed Aug 13 14:44:59 2014 +0200
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.tools.sjavac.server;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.Socket;
+import java.net.URI;
+import java.util.List;
+import java.util.Set;
+
+import com.sun.tools.sjavac.Log;
+
+/**
+ * A RequestHandler handles requests performed over a socket. Specifically it
+ * - Reads the command string specifying which method is to be invoked
+ * - Reads the appropriate arguments
+ * - Delegates the actual invocation to the given sjavac implementation
+ * - Writes the result back to the socket output stream
+ *
+ * None of the work performed by this class is really bound by the CPU. It
+ * should be completely fine to have a large number of RequestHandlers active.
+ * To limit the number of concurrent compilations, use PooledSjavac.
+ *
+ * <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 subject to change or
+ * deletion without notice.</b>
+ */
+public class RequestHandler implements Runnable {
+
+ private final Socket socket;
+ private final Sjavac sjavac;
+
+ public RequestHandler(Socket socket, Sjavac sjavac) {
+ this.socket = socket;
+ this.sjavac = sjavac;
+ }
+
+ @Override
+ public void run() {
+ try (ObjectOutputStream oout = new ObjectOutputStream(socket.getOutputStream());
+ ObjectInputStream oin = new ObjectInputStream(socket.getInputStream())) {
+ String id = (String) oin.readObject();
+ String cmd = (String) oin.readObject();
+ Log.info("Handling request, id: " + id + " cmd: " + cmd);
+ switch (cmd) {
+ case SjavacServer.CMD_SYS_INFO: handleSysInfoRequest(oin, oout); break;
+ case SjavacServer.CMD_COMPILE: handleCompileRequest(oin, oout); break;
+ default: Log.error("Unknown command: " + cmd);
+ }
+ } catch (Exception ex) {
+ // Not much to be done at this point. The client side request
+ // code will most likely throw an IOException and the
+ // compilation will fail.
+ StringWriter sw = new StringWriter();
+ ex.printStackTrace(new PrintWriter(sw));
+ Log.error(sw.toString());
+ }
+ }
+
+ private void handleSysInfoRequest(ObjectInputStream oin,
+ ObjectOutputStream oout) throws IOException {
+ oout.writeObject(sjavac.getSysInfo());
+ oout.flush();
+ }
+
+ @SuppressWarnings("unchecked")
+ private void handleCompileRequest(ObjectInputStream oin,
+ ObjectOutputStream oout) throws IOException {
+ try {
+ // Read request arguments
+ String protocolId = (String) oin.readObject();
+ String invocationId = (String) oin.readObject();
+ String[] args = (String[]) oin.readObject();
+ List<File> explicitSources = (List<File>) oin.readObject();
+ Set<URI> sourcesToCompile = (Set<URI>) oin.readObject();
+ Set<URI> visibleSources = (Set<URI>) oin.readObject();
+
+ // Perform compilation
+ CompilationResult cr = sjavac.compile(protocolId,
+ invocationId,
+ args,
+ explicitSources,
+ sourcesToCompile,
+ visibleSources);
+ // Write request response
+ oout.writeObject(cr);
+ oout.flush();
+ } catch (ClassNotFoundException cnfe) {
+ throw new IOException(cnfe);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/Sjavac.java Wed Aug 13 14:44:59 2014 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.tools.sjavac.server;
+
+import java.io.File;
+import java.net.URI;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Interface of the SjavacImpl, the sjavac client and all wrappers such as
+ * PooledSjavac etc.
+ *
+ * <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 subject to change or
+ * deletion without notice.</b>
+ */
+public interface Sjavac {
+
+ SysInfo getSysInfo();
+
+ CompilationResult compile(String protocolId,
+ String invocationId,
+ String[] args,
+ List<File> explicitSources,
+ Set<URI> sourcesToCompile,
+ Set<URI> visibleSources);
+
+ void shutdown();
+ String serverSettings();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/SjavacServer.java Wed Aug 13 14:44:59 2014 +0200
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.tools.sjavac.server;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.sun.tools.sjavac.ProblemException;
+import com.sun.tools.sjavac.Util;
+import com.sun.tools.sjavac.comp.SjavacImpl;
+import com.sun.tools.sjavac.comp.PooledSjavac;
+
+/**
+ * The JavacServer class contains methods both to setup a server that responds to requests and methods to connect to this server.
+ *
+ * <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 subject to change or
+ * deletion without notice.</b>
+ */
+public class SjavacServer implements Terminable {
+
+ // Used in protocol to indicate which method to invoke
+ public final static String CMD_COMPILE = "compile";
+ public final static String CMD_SYS_INFO = "sys-info";
+
+ final private String portfilename;
+ final private String logfile;
+ final private String stdouterrfile;
+ final private int poolsize;
+ final private int keepalive;
+ final private PrintStream err;
+
+ // The secret cookie shared between server and client through the port file.
+ // Used to prevent clients from believing that they are communicating with
+ // an old server when a new server has started and reused the same port as
+ // an old server.
+ private final long myCookie;
+
+ // Accumulated build time, not counting idle time, used for logging purposes
+ private long totalBuildTime;
+
+ // The javac server specific log file.
+ PrintWriter theLog;
+
+ // The sjavac implementation to delegate requests to
+ Sjavac sjavac;
+
+ private ServerSocket serverSocket;
+
+ private PortFile portFile;
+ private PortFileMonitor portFileMonitor;
+
+ // Set to false break accept loop
+ final AtomicBoolean keepAcceptingRequests = new AtomicBoolean();
+
+ // For the client, all port files fetched, one per started javac server.
+ // Though usually only one javac server is started by a client.
+ private static Map<String, PortFile> allPortFiles;
+ private static Map<String, Long> maxServerMemory;
+
+ public SjavacServer(String settings, PrintStream err) throws FileNotFoundException {
+ // Extract options. TODO: Change to proper constructor args
+ portfilename = Util.extractStringOption("portfile", settings);
+ logfile = Util.extractStringOption("logfile", settings);
+ stdouterrfile = Util.extractStringOption("stdouterrfile", settings);
+ keepalive = Util.extractIntOption("keepalive", settings, 120);
+ poolsize = Util.extractIntOption("poolsize", settings,
+ Runtime.getRuntime().availableProcessors());
+ this.err = err;
+
+ myCookie = new Random().nextLong();
+ theLog = new PrintWriter(logfile);
+ }
+
+
+ /**
+ * Acquire the port file. Synchronized since several threads inside an smart javac wrapper client acquires the same port file at the same time.
+ */
+ public static synchronized PortFile getPortFile(String filename) throws FileNotFoundException {
+ if (allPortFiles == null) {
+ allPortFiles = new HashMap<>();
+ }
+ PortFile pf = allPortFiles.get(filename);
+
+ // Port file known. Does it still exist?
+ if (pf != null) {
+ try {
+ if (!pf.exists())
+ pf = null;
+ } catch (IOException ioex) {
+ ioex.printStackTrace();
+ }
+ }
+
+ if (pf == null) {
+ pf = new PortFile(filename);
+ allPortFiles.put(filename, pf);
+ }
+ return pf;
+ }
+
+ /**
+ * Get the cookie used for this server.
+ */
+ long getCookie() {
+ return myCookie;
+ }
+
+ /**
+ * Get the port used for this server.
+ */
+ int getPort() {
+ return serverSocket.getLocalPort();
+ }
+
+ /**
+ * Sum up the total build time for this javac server.
+ */
+ public void addBuildTime(long inc) {
+ totalBuildTime += inc;
+ }
+
+ /**
+ * Log this message.
+ */
+ public void log(String msg) {
+ if (theLog != null) {
+ theLog.println(msg);
+ } else {
+ System.err.println(msg);
+ }
+ }
+
+ /**
+ * Make sure the log is flushed.
+ */
+ public void flushLog() {
+ if (theLog != null) {
+ theLog.flush();
+ }
+ }
+
+ /**
+ * Start a server using a settings string. Typically: "--startserver:portfile=/tmp/myserver,poolsize=3" and the string "portfile=/tmp/myserver,poolsize=3"
+ * is sent as the settings parameter. Returns 0 on success, -1 on failure.
+ */
+ public int startServer() throws IOException {
+ long serverStart = System.currentTimeMillis();
+
+ // The port file is locked and the server port and cookie is written into it.
+ portFile = getPortFile(portfilename);
+
+ synchronized (portFile) {
+ portFile.lock();
+ portFile.getValues();
+ if (portFile.containsPortInfo()) {
+ err.println("Javac server not started because portfile exists!");
+ portFile.unlock();
+ return -1;
+ }
+
+ // .-----------. .--------. .------.
+ // socket -->| IdleReset |-->| Pooled |-->| Impl |--> javac
+ // '-----------' '--------' '------'
+ sjavac = new SjavacImpl();
+ sjavac = new PooledSjavac(sjavac, poolsize);
+ sjavac = new IdleResetSjavac(sjavac,
+ this,
+ keepalive * 1000);
+
+ serverSocket = new ServerSocket();
+ InetAddress localhost = InetAddress.getByName(null);
+ serverSocket.bind(new InetSocketAddress(localhost, 0));
+
+ // At this point the server accepts connections, so it is now safe
+ // to publish the port / cookie information
+ portFile.setValues(getPort(), getCookie());
+ portFile.unlock();
+ }
+
+ portFileMonitor = new PortFileMonitor(portFile, this);
+ portFileMonitor.start();
+
+ log("Sjavac server started. Accepting connections...");
+ log(" port: " + getPort());
+ log(" time: " + new java.util.Date());
+ log(" poolsize: " + poolsize);
+ flushLog();
+
+ keepAcceptingRequests.set(true);
+ do {
+ try {
+ Socket socket = serverSocket.accept();
+ new Thread(new RequestHandler(socket, sjavac)).start();
+ } catch (SocketException se) {
+ // Caused by serverSocket.close() and indicates shutdown
+ }
+ } while (keepAcceptingRequests.get());
+
+ log("Shutting down.");
+
+ // No more connections accepted. If any client managed to connect after
+ // the accept() was interrupted but before the server socket is closed
+ // here, any attempt to read or write to the socket will result in an
+ // IOException on the client side.
+
+ long realTime = System.currentTimeMillis() - serverStart;
+ log("Total wall clock time " + realTime + "ms build time " + totalBuildTime + "ms");
+ flushLog();
+
+ // Shut down
+ sjavac.shutdown();
+
+ return 0;
+ }
+
+ /**
+ * Fork a background process. Returns the command line used that can be printed if something failed.
+ */
+ public static String fork(String sjavac, String portfile, String logfile, int poolsize, int keepalive,
+ final PrintStream err, String stdouterrfile, boolean background)
+ throws IOException, ProblemException {
+ if (stdouterrfile != null && stdouterrfile.trim().equals("")) {
+ stdouterrfile = null;
+ }
+ final String startserver = "--startserver:portfile=" + portfile + ",logfile=" + logfile + ",stdouterrfile=" + stdouterrfile + ",poolsize=" + poolsize + ",keepalive="+ keepalive;
+
+ if (background) {
+ sjavac += "%20" + startserver;
+ sjavac = sjavac.replaceAll("%20", " ");
+ sjavac = sjavac.replaceAll("%2C", ",");
+ // If the java/sh/cmd launcher fails the failure will be captured by stdouterr because of the redirection here.
+ String[] cmd = {"/bin/sh", "-c", sjavac + " >> " + stdouterrfile + " 2>&1"};
+ if (!(new File("/bin/sh")).canExecute()) {
+ ArrayList<String> wincmd = new ArrayList<>();
+ wincmd.add("cmd");
+ wincmd.add("/c");
+ wincmd.add("start");
+ wincmd.add("cmd");
+ wincmd.add("/c");
+ wincmd.add(sjavac + " >> " + stdouterrfile + " 2>&1");
+ cmd = wincmd.toArray(new String[wincmd.size()]);
+ }
+ Process pp = null;
+ try {
+ pp = Runtime.getRuntime().exec(cmd);
+ } catch (Exception e) {
+ e.printStackTrace(err);
+ e.printStackTrace(new PrintWriter(stdouterrfile));
+ }
+ StringBuilder rs = new StringBuilder();
+ for (String s : cmd) {
+ rs.append(s + " ");
+ }
+ return rs.toString();
+ }
+
+ // Do not spawn a background server, instead run it within the same JVM.
+ Thread t = new Thread() {
+ @Override
+ public void run() {
+ try {
+ SjavacServer server = new SjavacServer(startserver, err);
+ server.startServer();
+ } catch (Throwable t) {
+ t.printStackTrace(err);
+ }
+ }
+ };
+ t.setDaemon(true);
+ t.start();
+ return "";
+ }
+
+ @Override
+ public void shutdown(String quitMsg) {
+ if (!keepAcceptingRequests.compareAndSet(false, true)) {
+ // Already stopped, no need to shut down again
+ return;
+ }
+
+ log("Quitting: " + quitMsg);
+ flushLog();
+
+ portFileMonitor.shutdown(); // No longer any need to monitor port file
+
+ // Unpublish port before shutting down socket to minimize the number of
+ // failed connection attempts
+ try {
+ portFile.delete();
+ } catch (IOException e) {
+ e.printStackTrace(theLog);
+ }
+ try {
+ serverSocket.close();
+ } catch (IOException e) {
+ e.printStackTrace(theLog);
+ }
+ }
+
+ public static void cleanup(String... args) {
+ String settings = Util.findServerSettings(args);
+ if (settings == null) return;
+ String portfile = Util.extractStringOption("portfile", settings);
+ String background = Util.extractStringOption("background", settings);
+ if (background != null && background.equals("false")) {
+ // If the server runs within this jvm, then delete the portfile,
+ // since this jvm is about to exit soon.
+ File f = new File(portfile);
+ f.delete();
+ }
+ }
+}
--- a/langtools/src/share/classes/com/sun/tools/sjavac/server/SysInfo.java Tue Aug 12 17:48:30 2014 -0700
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/SysInfo.java Wed Aug 13 14:44:59 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,18 @@
*/
package com.sun.tools.sjavac.server;
-public class SysInfo {
+import java.io.Serializable;
+
+/**
+ * <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 subject to change or
+ * deletion without notice.</b>
+ */
+public class SysInfo implements Serializable {
+
+ static final long serialVersionUID = -3096346807579L;
+
public int numCores;
public long maxMemory;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/sjavac/server/Terminable.java Wed Aug 13 14:44:59 2014 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.tools.sjavac.server;
+
+/**
+ * <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 subject to change or
+ * deletion without notice.</b>
+ */
+public interface Terminable {
+ void shutdown(String quitMsg);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/sjavac/IdleShutdown.java Wed Aug 13 14:44:59 2014 +0200
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8044131
+ * @summary Tests the hooks used for detecting idleness of the sjavac server.
+ * @build Wrapper
+ * @run main Wrapper IdleShutdown
+ */
+import java.io.File;
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+
+import com.sun.tools.sjavac.server.CompilationResult;
+import com.sun.tools.sjavac.server.IdleResetSjavac;
+import com.sun.tools.sjavac.server.Sjavac;
+import com.sun.tools.sjavac.server.SysInfo;
+import com.sun.tools.sjavac.server.Terminable;
+
+
+public class IdleShutdown {
+
+ final static long TEST_START = System.currentTimeMillis();
+ final static long TIMEOUT_MS = 3000;
+
+ public static void main(String[] args) throws InterruptedException {
+
+ final AtomicLong timeoutTimestamp = new AtomicLong(-1);
+
+ log("Starting IdleCallbackJavacService with timeout: " + TIMEOUT_MS);
+ Sjavac service = new IdleResetSjavac(
+ new NoopJavacService(),
+ new Terminable() {
+ public void shutdown(String msg) {
+ // Record the idle timeout time
+ log("Timeout detected");
+ timeoutTimestamp.set(System.currentTimeMillis());
+ }
+ },
+ TIMEOUT_MS);
+
+ // Make sure it didn't timeout immediately
+ if (timeoutTimestamp.get() != -1)
+ throw new AssertionError("Premature timeout detected.");
+
+ // Call various methods and wait less than TIMEOUT_MS in between
+ Thread.sleep(TIMEOUT_MS - 1000);
+ log("Getting sys info");
+ service.getSysInfo();
+
+ Thread.sleep(TIMEOUT_MS - 1000);
+ log("Getting sys info");
+ service.getSysInfo();
+
+ if (timeoutTimestamp.get() != -1)
+ throw new AssertionError("Premature timeout detected.");
+
+ Thread.sleep(TIMEOUT_MS - 1000);
+ log("Compiling");
+ service.compile("",
+ "",
+ new String[0],
+ Collections.<File>emptyList(),
+ Collections.<URI>emptySet(),
+ Collections.<URI>emptySet());
+
+ Thread.sleep(TIMEOUT_MS - 1000);
+ log("Compiling");
+ service.compile("",
+ "",
+ new String[0],
+ Collections.<File>emptyList(),
+ Collections.<URI>emptySet(),
+ Collections.<URI>emptySet());
+
+ if (timeoutTimestamp.get() != -1)
+ throw new AssertionError("Premature timeout detected.");
+
+ long expectedTimeout = System.currentTimeMillis() + TIMEOUT_MS;
+
+ // Wait for actual timeout
+ log("Awaiting idle timeout");
+ Thread.sleep(TIMEOUT_MS + 1000);
+
+ // Check result
+ if (timeoutTimestamp.get() == -1)
+ throw new AssertionError("Timeout never occurred");
+
+ long error = Math.abs(expectedTimeout - timeoutTimestamp.get());
+ log("Timeout error: " + error + " ms");
+ if (error > TIMEOUT_MS * .1)
+ throw new AssertionError("Error too big");
+
+ log("Shutting down");
+ service.shutdown();
+ }
+
+ private static void log(String msg) {
+ long logTime = System.currentTimeMillis() - TEST_START;
+ System.out.printf("After %5d ms: %s%n", logTime, msg);
+ }
+
+ private static class NoopJavacService implements Sjavac {
+ @Override
+ public SysInfo getSysInfo() {
+ // Attempt to trigger idle timeout during a call by sleeping
+ try {
+ Thread.sleep(TIMEOUT_MS + 1000);
+ } catch (InterruptedException e) {
+ }
+ return null;
+ }
+ @Override
+ public void shutdown() {
+ }
+ @Override
+ public CompilationResult compile(String protocolId,
+ String invocationId,
+ String[] args,
+ List<File> explicitSources,
+ Set<URI> sourcesToCompile,
+ Set<URI> visibleSources) {
+ return null;
+ }
+ @Override
+ public String serverSettings() {
+ return "";
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/sjavac/PooledExecution.java Wed Aug 13 14:44:59 2014 +0200
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8044131
+ * @summary Makes sure sjavac poolsize option is honored.
+ * @build Wrapper
+ * @run main Wrapper PooledExecution
+ */
+import java.io.File;
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.sun.tools.sjavac.comp.PooledSjavac;
+import com.sun.tools.sjavac.server.CompilationResult;
+import com.sun.tools.sjavac.server.Sjavac;
+import com.sun.tools.sjavac.server.SysInfo;
+
+
+public class PooledExecution {
+
+ public static void main(String[] args) throws InterruptedException {
+ new PooledExecutionTest().runTest();
+ }
+
+ static class PooledExecutionTest {
+
+ final int POOL_SIZE = 15;
+ final int NUM_REQUESTS = 100;
+
+ // Number of tasks that has not yet started
+ CountDownLatch leftToStart = new CountDownLatch(NUM_REQUESTS);
+
+ // Highest number of concurrently active request seen
+ int highWaterMark = 0;
+
+ public void runTest() throws InterruptedException {
+ ConcurrencyLoggingService loggingService = new ConcurrencyLoggingService();
+ final Sjavac service = new PooledSjavac(loggingService, POOL_SIZE);
+
+ // Keep track of the number of finished tasks so we can make sure all
+ // tasks finishes gracefully upon shutdown.
+ Thread[] tasks = new Thread[NUM_REQUESTS];
+ final AtomicInteger tasksFinished = new AtomicInteger(0);
+
+ for (int i = 0; i < NUM_REQUESTS; i++) {
+ tasks[i] = new Thread() {
+ public void run() {
+ service.compile("",
+ "",
+ new String[0],
+ Collections.<File>emptyList(),
+ Collections.<URI>emptySet(),
+ Collections.<URI>emptySet());
+ tasksFinished.incrementAndGet();
+ }
+ };
+ tasks[i].start();
+ }
+
+ // Wait for all tasks to start (but not necessarily run to completion)
+ leftToStart.await();
+
+ // Shutdown before all tasks are completed
+ System.out.println("Shutting down!");
+ service.shutdown();
+
+ // Wait for all tasks to complete
+ for (Thread t : tasks)
+ t.join();
+
+ if (tasksFinished.get() != NUM_REQUESTS) {
+ throw new AssertionError(tasksFinished.get() + " out of " +
+ NUM_REQUESTS + " finished. Broken shutdown?");
+ }
+
+ if (highWaterMark > POOL_SIZE) {
+ throw new AssertionError("Pool size overused: " + highWaterMark +
+ " used out of " + POOL_SIZE + " allowed.");
+ }
+
+ // Assuming more than POOL_SIZE requests can be processed within 1 sek:
+ if (highWaterMark < POOL_SIZE) {
+ throw new AssertionError("Pool size underused: " + highWaterMark +
+ " used out of " + POOL_SIZE + " allowed.");
+ }
+ }
+
+
+ private class ConcurrencyLoggingService implements Sjavac {
+
+ // Keeps track of currently active requests
+ AtomicInteger activeRequests = new AtomicInteger(0);
+
+ @Override
+ public CompilationResult compile(String protocolId,
+ String invocationId,
+ String[] args,
+ List<File> explicitSources,
+ Set<URI> sourcesToCompile,
+ Set<URI> visibleSources) {
+ leftToStart.countDown();
+ int numActiveRequests = activeRequests.incrementAndGet();
+ System.out.printf("Left to start: %2d / Currently active: %2d%n",
+ leftToStart.getCount(),
+ numActiveRequests);
+ highWaterMark = Math.max(highWaterMark, numActiveRequests);
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {
+ throw new RuntimeException("Interrupted", ie);
+ }
+ activeRequests.decrementAndGet();
+ System.out.println("Task completed");
+ return null;
+ }
+
+ @Override
+ public SysInfo getSysInfo() {
+ return null;
+ }
+
+ @Override
+ public void shutdown() {
+ }
+
+ @Override
+ public String serverSettings() {
+ return "";
+ }
+ }
+ }
+}