1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/sjavac/server/PortFile.java Wed Apr 27 01:34:52 2016 +0800 1.3 @@ -0,0 +1,259 @@ 1.4 +/* 1.5 + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.tools.sjavac.server; 1.30 + 1.31 +import java.io.File; 1.32 +import java.io.FileNotFoundException; 1.33 +import java.io.IOException; 1.34 +import java.io.RandomAccessFile; 1.35 +import java.nio.channels.ClosedChannelException; 1.36 +import java.nio.channels.FileChannel; 1.37 +import java.nio.channels.FileLock; 1.38 +import java.nio.channels.FileLockInterruptionException; 1.39 +import com.sun.tools.sjavac.Log; 1.40 + 1.41 +/** 1.42 + * The PortFile class mediates access to a short binary file containing the tcp/ip port (for the localhost) 1.43 + * and a cookie necessary for the server answering on that port. The file can be locked using file system 1.44 + * primitives to avoid race conditions when several javac clients are started at the same. Note that file 1.45 + * system locking is not always supported on a all operating systems and/or file systems. 1.46 + * 1.47 + * <p><b>This is NOT part of any supported API. 1.48 + * If you write code that depends on this, you do so at your own 1.49 + * risk. This code and its internal interfaces are subject to change 1.50 + * or deletion without notice.</b></p> 1.51 + */ 1.52 +class PortFile { 1.53 + 1.54 + // Port file format: 1.55 + // byte ordering: high byte first = big endian 1.56 + // Magic nr, 4 byte int, first in file. 1.57 + private final static int magicNr = 0x1174; 1.58 + // Followed by a 4 byte int, with the port nr. 1.59 + // Followed by a 8 byte long, with cookie nr. 1.60 + 1.61 + private String filename; 1.62 + private File file; 1.63 + private File stopFile; 1.64 + private RandomAccessFile rwfile; 1.65 + private FileChannel channel; 1.66 + private FileLock lock; 1.67 + 1.68 + private boolean containsPortInfo; 1.69 + private int serverPort; 1.70 + private long serverCookie; 1.71 + private int myServerPort; 1.72 + private long myServerCookie; 1.73 + 1.74 + /** 1.75 + * Create a new portfile. 1.76 + * @param filename is the path to the file. 1.77 + */ 1.78 + public PortFile(String fn) throws FileNotFoundException 1.79 + { 1.80 + filename = fn; 1.81 + file = new File(filename); 1.82 + stopFile = new File(filename+".stop"); 1.83 + rwfile = new RandomAccessFile(file, "rw"); 1.84 + // The rwfile should only be readable by the owner of the process 1.85 + // and no other! How do we do that on a RandomAccessFile? 1.86 + channel = rwfile.getChannel(); 1.87 + containsPortInfo = false; 1.88 + lock = null; 1.89 + } 1.90 + 1.91 + /** 1.92 + * Lock the port file. 1.93 + */ 1.94 + void lock() throws IOException { 1.95 + lock = channel.lock(); 1.96 + } 1.97 + 1.98 + /** 1.99 + * Read the values from the port file in the file system. 1.100 + * Expects the port file to be locked. 1.101 + */ 1.102 + public void getValues() { 1.103 + containsPortInfo = false; 1.104 + if (lock == null) { 1.105 + // Not locked, remain ignorant about port file contents. 1.106 + return; 1.107 + } 1.108 + try { 1.109 + if (rwfile.length()>0) { 1.110 + rwfile.seek(0); 1.111 + int nr = rwfile.readInt(); 1.112 + serverPort = rwfile.readInt(); 1.113 + serverCookie = rwfile.readLong(); 1.114 + 1.115 + if (nr == magicNr) { 1.116 + containsPortInfo = true; 1.117 + } else { 1.118 + containsPortInfo = false; 1.119 + } 1.120 + } 1.121 + } catch (Exception e) { 1.122 + containsPortInfo = false; 1.123 + } 1.124 + } 1.125 + 1.126 + /** 1.127 + * Did the locking and getValues succeed? 1.128 + */ 1.129 + public boolean containsPortInfo() { 1.130 + return containsPortInfo; 1.131 + } 1.132 + 1.133 + /** 1.134 + * If so, then we can acquire the tcp/ip port on localhost. 1.135 + */ 1.136 + public int getPort() { 1.137 + assert(containsPortInfo); 1.138 + return serverPort; 1.139 + } 1.140 + 1.141 + /** 1.142 + * If so, then we can acquire the server cookie. 1.143 + */ 1.144 + public long getCookie() { 1.145 + assert(containsPortInfo); 1.146 + return serverCookie; 1.147 + } 1.148 + 1.149 + /** 1.150 + * Store the values into the locked port file. 1.151 + */ 1.152 + public void setValues(int port, long cookie) throws IOException { 1.153 + assert(lock != null); 1.154 + rwfile.seek(0); 1.155 + // Write the magic nr that identifes a port file. 1.156 + rwfile.writeInt(magicNr); 1.157 + rwfile.writeInt(port); 1.158 + rwfile.writeLong(cookie); 1.159 + myServerPort = port; 1.160 + myServerCookie = cookie; 1.161 + } 1.162 + 1.163 + /** 1.164 + * Delete the port file. 1.165 + */ 1.166 + public void delete() throws IOException { 1.167 + // Access to file must be closed before deleting. 1.168 + rwfile.close(); 1.169 + // Now delete. 1.170 + file.delete(); 1.171 + } 1.172 + 1.173 + /** 1.174 + * Is the port file still there? 1.175 + */ 1.176 + public boolean exists() throws IOException { 1.177 + return file.exists(); 1.178 + } 1.179 + 1.180 + /** 1.181 + * Is a stop file there? 1.182 + */ 1.183 + public boolean markedForStop() throws IOException { 1.184 + if (stopFile.exists()) { 1.185 + try { 1.186 + stopFile.delete(); 1.187 + } catch (Exception e) 1.188 + {} 1.189 + return true; 1.190 + } 1.191 + return false; 1.192 + } 1.193 + 1.194 + /** 1.195 + * Unlock the port file. 1.196 + */ 1.197 + public void unlock() throws IOException { 1.198 + assert(lock != null); 1.199 + lock.release(); 1.200 + lock = null; 1.201 + } 1.202 + 1.203 + /** 1.204 + * Wait for the port file to contain values that look valid. 1.205 + * Return true, if a-ok, false if the valid values did not materialize within 5 seconds. 1.206 + */ 1.207 + public synchronized boolean waitForValidValues() throws IOException, FileNotFoundException { 1.208 + for (int tries = 0; tries < 50; tries++) { 1.209 + lock(); 1.210 + getValues(); 1.211 + unlock(); 1.212 + if (containsPortInfo) { 1.213 + Log.debug("Found valid values in port file after waiting "+(tries*100)+"ms"); 1.214 + return true; 1.215 + } 1.216 + try { 1.217 + Thread.sleep(100); 1.218 + } catch (InterruptedException e) 1.219 + {} 1.220 + } 1.221 + Log.debug("Gave up waiting for valid values in port file"); 1.222 + return false; 1.223 + } 1.224 + 1.225 + /** 1.226 + * Check if the portfile still contains my values, assuming that I am the server. 1.227 + */ 1.228 + public synchronized boolean stillMyValues() throws IOException, FileNotFoundException { 1.229 + for (;;) { 1.230 + try { 1.231 + lock(); 1.232 + getValues(); 1.233 + unlock(); 1.234 + if (containsPortInfo) { 1.235 + if (serverPort == myServerPort && 1.236 + serverCookie == myServerCookie) { 1.237 + // Everything is ok. 1.238 + return true; 1.239 + } 1.240 + // Someone has overwritten the port file. 1.241 + // Probably another javac server, lets quit. 1.242 + return false; 1.243 + } 1.244 + // Something else is wrong with the portfile. Lets quit. 1.245 + return false; 1.246 + } catch (FileLockInterruptionException e) { 1.247 + continue; 1.248 + } 1.249 + catch (ClosedChannelException e) { 1.250 + // The channel has been closed since sjavac is exiting. 1.251 + return false; 1.252 + } 1.253 + } 1.254 + } 1.255 + 1.256 + /** 1.257 + * Return the name of the port file. 1.258 + */ 1.259 + public String getFilename() { 1.260 + return filename; 1.261 + } 1.262 +}