Skip to content

Can't interrupt blocking accept #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
gregw opened this issue Oct 23, 2015 · 8 comments
Closed

Can't interrupt blocking accept #21

gregw opened this issue Oct 23, 2015 · 8 comments

Comments

@gregw
Copy link
Contributor

gregw commented Oct 23, 2015

A blocking call to accept cannot be interrupted, not even if the channel is closed. This is demonstrated by the following code:

import java.io.File;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import jnr.unixsocket.UnixServerSocketChannel;
import jnr.unixsocket.UnixSocketAddress;

public class UnixSocketAcceptInterrupt
{
    public static void main(String... args) throws Exception
    {
        File file = new File("/tmp/test.sock");
        if (file.exists())
            file.delete();

        final UnixServerSocketChannel channel = UnixServerSocketChannel.open();
        channel.socket().bind(new UnixSocketAddress(file));

        final AtomicBoolean run = new AtomicBoolean(true);
        final CountDownLatch start = new CountDownLatch(1);
        final CountDownLatch complete = new CountDownLatch(1);
        Thread accept = new Thread()
        {
            @Override public void run()
            {
                start.countDown();
                try
                {
                    while(run.get())
                    {
                        try
                        {
                            channel.accept();
                            System.err.println("accepted");
                        }
                        catch (IOException e)
                        {
                            e.printStackTrace();
                        }
                    }
                }
                finally
                {
                    complete.countDown();
                }
            }
        };
        accept.setDaemon(true);
        accept.start();
        if (!start.await(5,TimeUnit.SECONDS))
            System.err.println("Timeout waiting for start");

        Thread.sleep(1000);

        run.set(false);
        accept.interrupt();
        if (!complete.await(5,TimeUnit.SECONDS))
            System.err.println("Timeout waiting for complete");

        channel.close();
        accept.interrupt();
        if (!complete.await(5,TimeUnit.SECONDS))
            System.err.println("Timeout waiting for complete after close");
    }
}
@felfert
Copy link
Contributor

felfert commented Feb 3, 2016

AFAIK, This is the documented behaviour of java.nio.channels.spi.AbstractInterruptibleChannel.
You need to use begin()/end() pairs, if you want to interrupt the thread.
See https://docs.oracle.com/javase/7/docs/api/java/nio/channels/spi/AbstractInterruptibleChannel.html#be

@gregw
Copy link
Contributor Author

gregw commented Feb 29, 2016

@felfert but begin/end are protected methods, so I can't call them directly. Surely it is the JNR implementation of UnixServerSocketChannel#accept that should be calling them?

@gregw
Copy link
Contributor Author

gregw commented Feb 29, 2016

Specifically, shouldn't this line be wrapped in begin/end pairs?

@headius
Copy link
Member

headius commented Mar 8, 2016

@gregw I think you're right. Can you help us patch this?

gregw added a commit to gregw/jnr-unixsocket that referenced this issue Mar 9, 2016
@gregw
Copy link
Contributor Author

gregw commented Mar 9, 2016

@headius #25 is a PR that adds begin/end calls. It makes it a little bit better, but doesn't generally fix the problem? At least not on Linux Tile440 4.2.0-30-generic #36-Ubuntu SMP Fri Feb 26 00:58:07 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

@headius
Copy link
Member

headius commented Sep 28, 2016

Fix this for 0.14.

@headius headius added this to the 0.14 milestone Sep 28, 2016
@headius headius removed this from the 0.14 milestone Mar 10, 2017
@leifwalsh
Copy link

I think the way to do accept() with an interrupt or timeout is to call select() first, check if the socket is ready, and then call accept() knowing there's a connection to accept. You could set things up so that one of the sockets passed to select() is something that a thread wanting to interrupt it could close or otherwise signal, separate from the socket you're actually trying to accept on, and you could implement a version of the api with a timeout.

@swankjesse
Copy link

Fixed in #65

@gregw gregw closed this as completed Nov 21, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants