You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by "lbruun (JIRA)" <ji...@apache.org> on 2017/10/30 08:44:00 UTC

[jira] [Comment Edited] (NETBEANS-106) NB classloaders should use fine grained locking

    [ https://issues.apache.org/jira/browse/NETBEANS-106?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16224510#comment-16224510 ] 

lbruun edited comment on NETBEANS-106 at 10/30/17 8:43 AM:
-----------------------------------------------------------

Below is a NetBeans centric example which shows off the problem. Success of the new enhanced NB classloader (my proposal) can be measured by the below code no longer causing NB to freeze.

{code:java}

/**
 * Example which shows how NetBeans freezes because of deadlock.
 * (NETBEANS-58 and JDK-8068184)
 * 
 * Instructions: Add the following to a module and you'll see all of NetBeans 
 * freezing shortly after the UI is shown.
 * 
 * In order to be as realistic as possible the case is shown via use of
 * a custom Authenticator. This is really unnecessary but makes it a
 * bit more like real-life.
 * 
 * @author lbruun
 */
@OnStart
public class NetworkTaskStarter implements Runnable {

    private static URL TEST_URL;
    private static InetAddress IP4;

    static {
        try {
            TEST_URL = new URL("https://protected.apache.org/foo/bar/foo2");
            IP4 = InetAddress.getByAddress(new byte[]{-44, 110, -89, -99});  // 212.110.167.157
        } catch (UnknownHostException | MalformedURLException ex) {
        }
    }

    private final RequestProcessor rp = new RequestProcessor("FreezeTesterRP", 2);

    @Override
    public void run() {

        rp.post(new Runnable() {
            @Override
            public void run() {
                try {
                    // Lots of cerimony to wait for UI to be ready
                    FutureTask<Void> uiInit = new FutureTask<>(new Callable<Void>() {
                        @Override
                        public Void call() throws Exception {
                            return null;
                        }
                    });
                    WindowManager.getDefault().invokeWhenUIReady(uiInit);
                    uiInit.get();

                    // Install our own Authenticator
                    Authenticator.setDefault(new CustomAuthenticator());

                    // Fire our simulated network task
                    rp.post(new NetworkTaskSimulator());

                } catch (InterruptedException | ExecutionException ex) {
                    Exceptions.printStackTrace(ex);
                }
            }
        });
    }

    private class NetworkTaskSimulator implements Runnable {

        @Override
        public void run() {

            // Call the Authenticator the same way as the JDK's
            // URLConnection classes do : with a lock on the CL !
            synchronized (Thread.currentThread().getContextClassLoader()) {
                Authenticator.requestPasswordAuthentication(
                        "squid.chicago.internal.net", // host
                        IP4, // addr
                        3128, // port
                        "https", // protocol
                        "", // prompt (aka realm)
                        "negotiate", // scheme
                        TEST_URL, // URL
                        Authenticator.RequestorType.PROXY
                );

                // We never get here. Application deadlocks above.
            }
        }
    }

    public class CustomAuthenticator extends Authenticator {

        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            // Do something which requires classloading and which executes
            // on a different thread and then waits for the result. It can be 
            // anything really, but Keyring.read() is the simplest way of showing 
            // the problem. So we use that.
            // (Another typical example is launching a dialog on the Swing EDT
            // and then waiting for the user's input to that dialog)

            Keyring.read("foobar");  // trigger the deadlock

            return null;
        }
    }
}
{code}







was (Author: lbruun):

Below is a NetBeans centric example which shows off the problem. Success of the new enhanced NB classloader (my proposal) can be measured by the below code no longer causing NB to freeze.

{code:java}

/**
 * Example which shows how NetBeans freezes because of deadlock.
 * (NETBEANS-58 and JDK-8068184)
 * 
 * Instructions: Add the following to a module and you'll see all of NetBeans 
 * freezing shortly after the UI is shown.
 * 
 * In order to be as realistic as possible the freeze is shown via
 * use of a custom Authenticator. This is really unnecessary but makes it
 * a bit more like real-life.
 * 
 * @author lbruun
 */
@OnStart
public class NetworkTaskStarter implements Runnable {

    private static URL TEST_URL;
    private static InetAddress IP4;

    static {
        try {
            TEST_URL = new URL("https://protected.apache.org/foo/bar/foo2");
            IP4 = InetAddress.getByAddress(new byte[]{-44, 110, -89, -99});  // 212.110.167.157
        } catch (UnknownHostException | MalformedURLException ex) {
        }
    }

    private final RequestProcessor rp = new RequestProcessor("FreezeTesterRP", 2);

    @Override
    public void run() {

        rp.post(new Runnable() {
            @Override
            public void run() {
                try {
                    // Lots of cerimony to wait for UI to be ready
                    FutureTask<Void> uiInit = new FutureTask<>(new Callable<Void>() {
                        @Override
                        public Void call() throws Exception {
                            return null;
                        }
                    });
                    WindowManager.getDefault().invokeWhenUIReady(uiInit);
                    uiInit.get();

                    // Install our own Authenticator
                    Authenticator.setDefault(new CustomAuthenticator());

                    // Fire our simulated network task
                    rp.post(new NetworkTaskSimulator());

                } catch (InterruptedException | ExecutionException ex) {
                    Exceptions.printStackTrace(ex);
                }
            }
        });
    }

    private class NetworkTaskSimulator implements Runnable {

        @Override
        public void run() {

            // Call the Authenticator the same way as the JDK's
            // URLConnection classes do : with a lock on the CL !
            synchronized (Thread.currentThread().getContextClassLoader()) {
                Authenticator.requestPasswordAuthentication(
                        "squid.chicago.internal.net", // host
                        IP4, // addr
                        3128, // port
                        "https", // protocol
                        "", // prompt (aka realm)
                        "negotiate", // scheme
                        TEST_URL, // URL
                        Authenticator.RequestorType.PROXY
                );

                // We never get here. Application deadlocks above.
            }
        }
    }

    public class CustomAuthenticator extends Authenticator {

        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            // Do something which requires classloading and which executes
            // on a different thread and then waits for the result. It can be 
            // anything really, but Keyring.read() is the simplest way of showing 
            // the problem. So we use that.
            // (Another typical example is launching a dialog on the Swing EDT
            // and then waiting for the user's input to that dialog)

            Keyring.read("foobar");  // trigger the deadlock

            return null;
        }
    }
}
{code}






> NB classloaders should use fine grained locking
> -----------------------------------------------
>
>                 Key: NETBEANS-106
>                 URL: https://issues.apache.org/jira/browse/NETBEANS-106
>             Project: NetBeans
>          Issue Type: Bug
>            Reporter: lbruun
>
> In order to avoid issues such as NETBEANS-58 the NB classloaders should use fine grained locking. (possibly only needed on System Classloader)
> Background:  At the time when the NB classloaders were created the general consensus at the time was that a proper classloader used locking at the level of the classloader itself. This was also how the classloaders in the JDK worked. However, in Java 7 this [changed|https://docs.oracle.com/javase/7/docs/technotes/guides/lang/cl-mt.html]. The JDK classloaders started using more fine grained locking. But the NB classloaders didn't follow suit. (it is not exactly an inheritable feature)
> This means we are now in a situation were deadlocks occur in NB code which cannot be reproduced with only the JDK. One such case is JDK-8068184 which causes a severe freeze in NetBeans. We cannot expect the JDK folks to fix problems that occur only in NB code.
> What I propose is that a more fine grained locking mechanism is used. Look to the JDK for inspiration. This will solve such deadlock issues. I don't think it is necessary to actually claim that it is now fully multi-thread safe by calling [registerAsParallelCapable()|https://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#registerAsParallelCapable()]. This can be left for a later exercise. First step is to remove the lock on the classloader as a whole.
> NETBEANS-58 contains a simple [minimal example|https://issues.apache.org/jira/browse/NETBEANS-58?focusedCommentId=16224149&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-16224149] which can be used as a measure of success. Once an NB application can use the pattern in the example without freezing then we have accomplished the goal.
>  
> (I'm personally not confident with fiddling with the NB classloaders. Scares the sh.. out of me because I know it is the heart of the platform. So won't come up with a PR. Sorry.)



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)