diff -r 4ebc2e2fb97c -r 71c04702a3d5 test/jdk/java/nio/channels/Selector/ChangingInterests.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/nio/channels/Selector/ChangingInterests.java Tue Sep 12 19:03:39 2017 +0200 @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 7200742 + * @key intermittent + * @summary Test that Selector doesn't spin when changing interest ops + */ + +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import static java.nio.channels.SelectionKey.*; +import java.io.IOException; + +public class ChangingInterests { + + static int OPS[] = { 0, OP_WRITE, OP_READ, (OP_WRITE|OP_READ) }; + + static String toOpsString(int ops) { + String s = ""; + if ((ops & OP_READ) > 0) + s += "POLLIN"; + if ((ops & OP_WRITE) > 0) { + if (s.length() > 0) + s += "|"; + s += "POLLOUT"; + } + if (s.length() == 0) + s = "0"; + return "(" + s + ")"; + } + + /** + * Writes two bytes to 'out' and reads one byte from 'in' so + * as to make 'in' readable. + */ + static void makeReadable(SocketChannel out, SocketChannel in) throws IOException { + out.write(ByteBuffer.wrap(new byte[2])); + ByteBuffer oneByte = ByteBuffer.wrap(new byte[1]); + do { + int n = in.read(oneByte); + if (n == 1) { + break; + } else if (n == 0) { + try { + Thread.sleep(50); + } catch (InterruptedException ignore) { } + } else { + throw new RuntimeException + ("Expected to read 0 or 1 byte; actual number was " + n); + } + } while (true); + } + + static void drain(SocketChannel sc) throws IOException { + ByteBuffer buf = ByteBuffer.allocate(100); + int n; + while ((n = sc.read(buf)) > 0) { + buf.rewind(); + } + } + + /** + * Changes the given key's interest set from one set to another and then + * checks the selected key set and the key's channel. + */ + static void testChange(SelectionKey key, int from, int to) throws IOException { + Selector sel = key.selector(); + assertTrue(sel.keys().size() == 1, "Only one channel should be registered"); + + // ensure that channel is registered with the "from" interest set + key.interestOps(from); + sel.selectNow(); + sel.selectedKeys().clear(); + + // change to the "to" interest set + key.interestOps(to); + System.out.println("select..."); + int selected = sel.selectNow(); + System.out.println("" + selected + " channel(s) selected"); + + int expected = (to == 0) ? 0 : 1; + assertTrue(selected == expected, "Expected " + expected); + + // check selected keys + for (SelectionKey k: sel.selectedKeys()) { + assertTrue(k == key, "Unexpected key selected"); + + boolean readable = k.isReadable(); + boolean writable = k.isWritable(); + + System.out.println("key readable: " + readable); + System.out.println("key writable: " + writable); + + if ((to & OP_READ) == 0) { + assertTrue(!readable, "Not expected to be readable"); + } else { + assertTrue(readable, "Expected to be readable"); + } + + if ((to & OP_WRITE) == 0) { + assertTrue(!writable, "Not expected to be writable"); + } else { + assertTrue(writable, "Expected to be writable"); + } + + sel.selectedKeys().clear(); + } + } + + /** + * Tests that given Selector's select method blocks. + */ + static void testForSpin(Selector sel) throws IOException { + System.out.println("Test for spin..."); + long start = System.currentTimeMillis(); + int count = 3; + while (count-- > 0) { + int selected = sel.select(1000); + System.out.println("" + selected + " channel(s) selected"); + assertTrue(selected == 0, "Channel should not be selected"); + } + long dur = System.currentTimeMillis() - start; + assertTrue(dur > 1000, "select was too short"); + } + + public static void main(String[] args) throws IOException { + InetAddress lh = InetAddress.getLocalHost(); + + // create loopback connection + ServerSocketChannel ssc = + ServerSocketChannel.open().bind(new InetSocketAddress(0)); + + final SocketChannel sc = SocketChannel.open(); + sc.setOption(StandardSocketOptions.TCP_NODELAY, true); + sc.connect(new InetSocketAddress(lh, ssc.socket().getLocalPort())); + SocketChannel peer = ssc.accept(); + peer.setOption(StandardSocketOptions.TCP_NODELAY, true); + + sc.configureBlocking(false); + + // ensure that channel "sc" is readable + makeReadable(peer, sc); + + try (Selector sel = Selector.open()) { + SelectionKey key = sc.register(sel, 0); + sel.selectNow(); + + // test all transitions + for (int from: OPS) { + for (int to: OPS) { + + System.out.println(toOpsString(from) + " -> " + toOpsString(to)); + + testChange(key, from, to); + + // if the interst ops is now 0 then Selector should not spin + if (to == 0) + testForSpin(sel); + + // if interest ops is now OP_READ then make non-readable + // and test that Selector does not spin. + if (to == OP_READ) { + System.out.println("Drain channel..."); + drain(sc); + testForSpin(sel); + System.out.println("Make channel readable again"); + makeReadable(peer, sc); + } + + System.out.println(); + } + } + + } finally { + sc.close(); + peer.close(); + ssc.close(); + } + } + + static void assertTrue(boolean v, String msg) { + if (!v) throw new RuntimeException(msg); + } + +}