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