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