google / j2objc

A Java to iOS Objective-C translation tool and runtime.
http://j2objc.org
Apache License 2.0
6k stars 970 forks source link

Selector.select() does not block after SelectionKey.cancel() or SocketChannel.close() #645

Open cffan opened 9 years ago

cffan commented 9 years ago

This can be reproduced using the following test code:

public class TestMain {

    public static void main(String[] args) throws Exception {
        final Selector selector = SelectorProvider.provider().openSelector();
        final SocketChannel channel = SocketChannel.open();
        channel.configureBlocking(false);
        channel.connect(new InetSocketAddress(InetAddress.getByName("www.google.com"), 80));
        new Thread() {
            @Override
            public void run() {
                try {
                    channel.register(selector, SelectionKey.OP_CONNECT);

                    while (true) {
                        System.out.println("select");
                        selector.select();
                        Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

                        while (iterator.hasNext()) {
                            SelectionKey key = iterator.next();
                            System.out.println("OPS: " + key.interestOps());
                            if (key.isConnectable()) {
                                System.out.println("isConnectable");

                                channel.finishConnect();
                                key.interestOps(SelectionKey.OP_READ | (~SelectionKey.OP_CONNECT & key.interestOps()));
                                iterator.remove();

                                key.cancel();
                                ((SocketChannel) key.channel()).close();
                            } else if (key.isReadable()) {
                                System.out.println("isReadable");
                                iterator.remove();
                            } else {
                                System.out.println("isWritable");
                                iterator.remove();
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();

        selector.wakeup();
        Thread.sleep(60000);
    }
}

When running this piece of code in Java, it outputs

select
select
OPS: 8
isConnectable
select

and then blocks.

If it is translated to objc, it loops forever. If you comment out these two lines, it will block as in Java.

//  key.cancel();
//  ((SocketChannel) key.channel()).close();

So I guess the SelectionKey.cancel or SocketChannel.close() is not translated properly so that the SelectionKey is not removed.

cffan commented 9 years ago

It might relate to this JVM bug: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6403933

I tried to call key.selectNow() but it does not fix the problem. However, close the current selector and create a new one solves this problem.

tomball commented 9 years ago

The JVM bug may very well be the same, as OS X/iOS networking is very similar to Linux, since they both are based on Berkeley networking.

On Sun, Oct 25, 2015 at 6:18 PM Steve notifications@github.com wrote:

It might relate to this JVM bug: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6403933

I tried to call key.selectNow() but it does not fix the problem. However, close the current selector and create a new one solves this problem.

— Reply to this email directly or view it on GitHub https://github.com/google/j2objc/issues/645#issuecomment-150997395.