netbeans-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From eba...@apache.org
Subject [incubator-netbeans] branch master updated: [NETBEANS-1197] Avoid ClosedByInterruptException in NetBeans' classloader
Date Tue, 30 Oct 2018 21:22:46 GMT
This is an automated email from the ASF dual-hosted git repository.

ebakke pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new ef48003  [NETBEANS-1197] Avoid ClosedByInterruptException in NetBeans' classloader
ef48003 is described below

commit ef4800372ccb39c98f610dc9a69569251ab58744
Author: Eirik Bakke <ebakke@alumni.princeton.edu>
AuthorDate: Tue Oct 30 17:22:41 2018 -0400

    [NETBEANS-1197] Avoid ClosedByInterruptException in NetBeans' classloader
    
    Use NIO by default, but fall back to the old FileInputStream if ClosedByInterruptException
is detected.
---
 .../src/org/netbeans/JarClassLoader.java           | 74 ++++++++++++++++++----
 1 file changed, 62 insertions(+), 12 deletions(-)

diff --git a/platform/o.n.bootstrap/src/org/netbeans/JarClassLoader.java b/platform/o.n.bootstrap/src/org/netbeans/JarClassLoader.java
index b1cdcc8..77cc076 100644
--- a/platform/o.n.bootstrap/src/org/netbeans/JarClassLoader.java
+++ b/platform/o.n.bootstrap/src/org/netbeans/JarClassLoader.java
@@ -21,6 +21,7 @@ package org.netbeans;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -36,6 +37,7 @@ import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLConnection;
 import java.net.URLStreamHandler;
+import java.nio.channels.ClosedByInterruptException;
 import java.nio.file.Files;
 import java.nio.file.InvalidPathException;
 import java.security.CodeSource;
@@ -850,20 +852,41 @@ public class JarClassLoader extends ProxyClassLoader {
             super(BaseUtilities.toURI(file).toURL());
             dir = file;
         }
-        
+
+        private Manifest getManifestHelper(boolean useNIO) throws IOException {
+          File maniF = new File(new File(dir, "META-INF"), "MANIFEST.MF");
+          Manifest mf = new Manifest();
+          if (maniF.canRead()) {
+              try (InputStream istm = useNIO
+                      ? Files.newInputStream(maniF.toPath())
+                      : new FileInputStream(maniF))
+              {
+                  mf.read(istm);
+              }
+          }
+          return mf;
+        }
+
         public Manifest getManifest() {
             Manifest mf = manifest;
             if (mf != null) {
                 return mf;
             }
-            File maniF = new File(new File(dir, "META-INF"), "MANIFEST.MF");
-            mf = new Manifest();
-            if (maniF.canRead()) {
-                try (InputStream istm = Files.newInputStream(maniF.toPath())) {
-                    mf.read(istm);
-                } catch (IOException | InvalidPathException ex) {
-                    Exceptions.printStackTrace(ex);
+            try {
+                try {
+                    mf = getManifestHelper(true);
+                } catch (ClosedByInterruptException ex) {
+                    // See comments in readClass().
+                    LOGGER.log(Level.INFO,
+                        "getManifest was interrupted; redoing operation with a regular FileInputStream");
+                    try {
+                      mf = getManifestHelper(false);
+                    } finally {
+                      Thread.currentThread().interrupt();
+                    }
                 }
+            } catch (IOException | InvalidPathException ex) {
+                Exceptions.printStackTrace(ex);
             }
             return manifest = mf;
         }
@@ -876,14 +899,17 @@ public class JarClassLoader extends ProxyClassLoader {
             File resFile = new File(dir, name);
             return resFile.exists() ? BaseUtilities.toURI(resFile).toURL() : null;
         }
-        
-        protected byte[] readClass(String path) throws IOException {
+
+        private byte[] readClassHelper(String path, boolean usingNIO) throws IOException
{
             File clsFile = new File(dir, path.replace('/', File.separatorChar));
             if (!clsFile.exists()) return null;
-            
+
             int len = (int)clsFile.length();
             byte[] data = new byte[len];
-            try (InputStream is = Files.newInputStream(clsFile.toPath())) {
+            try (InputStream is = usingNIO
+                  ? Files.newInputStream(clsFile.toPath())
+                  : new FileInputStream(clsFile))
+            {
                 int count = 0;
                 while (count < len) {
                     count += is.read(data, count, len - count);
@@ -893,6 +919,30 @@ public class JarClassLoader extends ProxyClassLoader {
                 throw new IOException(ex);
             }
         }
+
+        protected byte[] readClass(String path) throws IOException {
+            /* "FileOutputStream and FileInputStream complicate GC because they both override
+            'finalize()'. Switching to NIO API creates Stream without finalizers and thus
relieving
+            GC." However, using NIO means IO operations can fail with a ClosedByInterruptException,
+            for instance if client code starts a new thread which needs to load some new
classes,
+            and then interrupts the thread before class loading has finished. See NETBEANS-1197.
+            Note that the old java.io.InterruptedIOException, which could in theory be called
even
+            from FileOutputStream/FileInputStream, was seldom seen in practice; see JDK-4385444.
*/
+            try {
+                return readClassHelper(path, true);
+            } catch (ClosedByInterruptException ex) {
+                LOGGER.log(Level.INFO,
+                    "readClass was interrupted; redoing operation with a regular FileInputStream");
+                try {
+                  return readClassHelper(path, false);
+                } finally {
+                  /* The wording in ClosedByInterruptException's Javadoc is a little ambiguous
as to
+                  whether the thread's interrupt status will remain set _after_ the
+                  ClosedByInterruptException exception is thrown, so set it here just to
be safe. */
+                  Thread.currentThread().interrupt();
+                }
+            }
+        }
         
         protected void listCoveredPackages(Set<String> known, StringBuffer save) {
             appendAllChildren(known, save, dir, "");


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists


Mime
View raw message