Harmony
  1. Harmony
  2. HARMONY-6375

[classlib][nio]ServerSocketChannel hang when the main thread is waiting for request to accept and another thread try to configure the block mode on one channel

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 6.0M2, 5.0M14
    • Component/s: Classlib
    • Labels:
      None
    • Environment:
      All platforms
    • Patch Info:
      Patch Available

      Description

      As the summary described:

      One thread is waiting for request to accept and another thread is trying to configure the block mode on the same channel.

      I will attach one test case file to describe the problem.

      1. Harmony6375TestCase.java
        2 kB
        Ray Chen
      2. Harmony6375TestCase_V2.java
        2 kB
        Ray Chen
      3. Harmony-6375.diff
        0.9 kB
        Ray Chen
      4. Harmony-6375_V2.diff
        2 kB
        Ray Chen

        Activity

        Hide
        Ray Chen added a comment -

        Patch verified! Thanks Mark!

        Show
        Ray Chen added a comment - Patch verified! Thanks Mark!
        Hide
        Hudson added a comment -

        Integrated in Harmony-1.5-head-linux-x86_64 #661 (See http://hudson.zones.apache.org/hudson/job/Harmony-1.5-head-linux-x86_64/661/)
        Applying patches from "[#] [classlib][nio]ServerSocketChannel
        hang when the main thread is waiting for request to accept and another
        thread try to configure the block mode on one channel".

        Show
        Hudson added a comment - Integrated in Harmony-1.5-head-linux-x86_64 #661 (See http://hudson.zones.apache.org/hudson/job/Harmony-1.5-head-linux-x86_64/661/ ) Applying patches from " [#] [classlib] [nio] ServerSocketChannel hang when the main thread is waiting for request to accept and another thread try to configure the block mode on one channel".
        Hide
        Mark Hindess added a comment -

        Applied patch in r921764. Please confirm (by closing this JIRA) that it has been applied as expected.

        Show
        Mark Hindess added a comment - Applied patch in r921764. Please confirm (by closing this JIRA) that it has been applied as expected.
        Hide
        Ray Chen added a comment -

        Hi Mark,

        How about this new version patch?

        Show
        Ray Chen added a comment - Hi Mark, How about this new version patch?
        Hide
        Mark Hindess added a comment -

        Patch looks good but it would be good to have a regression test if possible.

        Show
        Mark Hindess added a comment - Patch looks good but it would be good to have a regression test if possible.
        Hide
        Li Jing Qin added a comment -

        Hi Ray,

        I have misunderstood your test case. It should throw AsynchronousCloseException when another thread close the Channel. If you comment out the ssc.configureBlocking line, harmony and ri all works well.
        About configureBlocking mode: if you comment out the ssc.close line, you will find that ssc.accept still wait for a connection, even though it is set to NON_BLOCKING. It is kind of reasonable from the native view but unreason from the java view.

        Any way, I agree your patch.

        One more thing, ServerSocketChannelImpl use select to fake the NON_BLOCKING, but SocketChannel set flag on fd to support the NON_BLOCKING. Does anyone know where does this difference come from?

        Show
        Li Jing Qin added a comment - Hi Ray, I have misunderstood your test case. It should throw AsynchronousCloseException when another thread close the Channel. If you comment out the ssc.configureBlocking line, harmony and ri all works well. About configureBlocking mode: if you comment out the ssc.close line, you will find that ssc.accept still wait for a connection, even though it is set to NON_BLOCKING. It is kind of reasonable from the native view but unreason from the java view. Any way, I agree your patch. One more thing, ServerSocketChannelImpl use select to fake the NON_BLOCKING, but SocketChannel set flag on fd to support the NON_BLOCKING. Does anyone know where does this difference come from?
        Hide
        Ray Chen added a comment -

        Hi Charles,

        I modified my testcase by adding two statements and ran it on RI:
        ...
        System.out.println(channel1.isBlocking());
        channel1.configureBlocking(false);
        System.out.println(channel1.isBlocking());
        ...
        The output showed that the blocking mode has been changed from "true" to "false"

        And I also ran the test case on harmony which has applied my patch,
        the behavior is same as RI's.

        However, in our implementation I found following code in
        ServerSocketChannelImpl.java
        protected void implConfigureBlocking(boolean blockingMode)
        throws IOException

        { // Do nothing here. For real accept() operation in nonblocking mode, // it uses INetworkSystem.select. Whether a channel is blocking can be // decided by isBlocking() method. }

        See? Actually it just changes the flag in java code.

        For RI, is it also a flag? Or really change the mode in native code?
        We can not know.


        Regards,

        Ray Chen

        Show
        Ray Chen added a comment - Hi Charles, I modified my testcase by adding two statements and ran it on RI: ... System.out.println(channel1.isBlocking()); channel1.configureBlocking(false); System.out.println(channel1.isBlocking()); ... The output showed that the blocking mode has been changed from "true" to "false" And I also ran the test case on harmony which has applied my patch, the behavior is same as RI's. However, in our implementation I found following code in ServerSocketChannelImpl.java protected void implConfigureBlocking(boolean blockingMode) throws IOException { // Do nothing here. For real accept() operation in nonblocking mode, // it uses INetworkSystem.select. Whether a channel is blocking can be // decided by isBlocking() method. } See? Actually it just changes the flag in java code. For RI, is it also a flag? Or really change the mode in native code? We can not know. – Regards, Ray Chen
        Hide
        Li Jing Qin added a comment -

        Hi Ray,
        What does the RI behave if one is accepting and another is trying to change the block mode?

        From the native aspect, when accept is called for a blocking socket, it should be blocked. So if we have configure it as block and accept, the process should be put to sleep. During this sleep, if we change the blocking mode, it should not have any affect.

        Show
        Li Jing Qin added a comment - Hi Ray, What does the RI behave if one is accepting and another is trying to change the block mode? From the native aspect, when accept is called for a blocking socket, it should be blocked. So if we have configure it as block and accept, the process should be put to sleep. During this sleep, if we change the blocking mode, it should not have any affect.
        Hide
        Ray Chen added a comment -

        In the ServerSocketChannelImpl.java, it holds the blockingLock, and because it is in blocking mode, so the accept() keep waiting. But in another thread which want to change the blocking mode, it also want to hold the blockingLock in the configureBlocking(boolean) method, which result in a deadLock.

        In the patch, I simply remove the sychronized block to resolve the thread deadlock because the bolckingLock has been synchronized in blockingLock() method located in AbstractSelectableChannel.

        This patch can make the test pass and no new test failures found in luni and nio unit tests.

        I wonder, does this change hava any side effect?

        If the main thread got the blocking mode and release the blockingLock, then before the main thread do the real IO operations, another thread change the blocking mode, what behavior it should be?

        I found following description in the spec of the InterruptibleChannel interface says:
        "A channel that implements this interface is asynchronously closeable: If a thread is blocked in an I/O operation on an interruptible channel then another thread may invoke the channel's close method. This will cause the blocked thread to receive an AsynchronousCloseException."

        Any comments?

        Show
        Ray Chen added a comment - In the ServerSocketChannelImpl.java, it holds the blockingLock, and because it is in blocking mode, so the accept() keep waiting. But in another thread which want to change the blocking mode, it also want to hold the blockingLock in the configureBlocking(boolean) method, which result in a deadLock. In the patch, I simply remove the sychronized block to resolve the thread deadlock because the bolckingLock has been synchronized in blockingLock() method located in AbstractSelectableChannel. This patch can make the test pass and no new test failures found in luni and nio unit tests. I wonder, does this change hava any side effect? If the main thread got the blocking mode and release the blockingLock, then before the main thread do the real IO operations, another thread change the blocking mode, what behavior it should be? I found following description in the spec of the InterruptibleChannel interface says: "A channel that implements this interface is asynchronously closeable: If a thread is blocked in an I/O operation on an interruptible channel then another thread may invoke the channel's close method. This will cause the blocked thread to receive an AsynchronousCloseException." Any comments?
        Hide
        Ray Chen added a comment -

        It is a test case which can reproduce the problem

        Show
        Ray Chen added a comment - It is a test case which can reproduce the problem

          People

          • Assignee:
            Mark Hindess
            Reporter:
            Ray Chen
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development