--- /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);
+ }
+
+}