/* * Copyright (c) 2012, 2016, 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 + ")"; } static void write1(SocketChannel peer) throws IOException { peer.write(ByteBuffer.wrap(new byte[1])); // give time for other end to be readable try { Thread.sleep(50); } catch (InterruptedException ignore) { } } 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 write1(peer); 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"); write1(peer); } System.out.println(); } } } finally { sc.close(); peer.close(); ssc.close(); } } static void assertTrue(boolean v, String msg) { if (!v) throw new RuntimeException(msg); } }