test/jdk/java/nio/channels/Selector/ChangingInterests.java
changeset 47216 71c04702a3d5
parent 44120 f569cf365ae3
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 /* @test
       
    25  * @bug 7200742
       
    26  * @key intermittent
       
    27  * @summary Test that Selector doesn't spin when changing interest ops
       
    28  */
       
    29 
       
    30 import java.net.*;
       
    31 import java.nio.ByteBuffer;
       
    32 import java.nio.channels.*;
       
    33 import static java.nio.channels.SelectionKey.*;
       
    34 import java.io.IOException;
       
    35 
       
    36 public class ChangingInterests {
       
    37 
       
    38     static int OPS[] = { 0, OP_WRITE, OP_READ, (OP_WRITE|OP_READ) };
       
    39 
       
    40     static String toOpsString(int ops) {
       
    41         String s = "";
       
    42         if ((ops & OP_READ) > 0)
       
    43             s += "POLLIN";
       
    44         if ((ops & OP_WRITE) > 0) {
       
    45             if (s.length() > 0)
       
    46                 s += "|";
       
    47             s += "POLLOUT";
       
    48         }
       
    49         if (s.length() == 0)
       
    50             s = "0";
       
    51         return "(" + s + ")";
       
    52     }
       
    53 
       
    54     /**
       
    55      * Writes two bytes to 'out' and reads one byte from 'in' so
       
    56      * as to make 'in' readable.
       
    57      */
       
    58     static void makeReadable(SocketChannel out, SocketChannel in) throws IOException {
       
    59         out.write(ByteBuffer.wrap(new byte[2]));
       
    60         ByteBuffer oneByte = ByteBuffer.wrap(new byte[1]);
       
    61         do {
       
    62             int n = in.read(oneByte);
       
    63             if (n == 1) {
       
    64                 break;
       
    65             } else if (n == 0) {
       
    66                 try {
       
    67                     Thread.sleep(50);
       
    68                 } catch (InterruptedException ignore) { }
       
    69             } else {
       
    70                 throw new RuntimeException
       
    71                     ("Expected to read 0 or 1 byte; actual number was " + n);
       
    72             }
       
    73         } while (true);
       
    74     }
       
    75 
       
    76     static void drain(SocketChannel sc) throws IOException {
       
    77         ByteBuffer buf = ByteBuffer.allocate(100);
       
    78         int n;
       
    79         while ((n = sc.read(buf)) > 0) {
       
    80             buf.rewind();
       
    81         }
       
    82     }
       
    83 
       
    84     /**
       
    85      * Changes the given key's interest set from one set to another and then
       
    86      * checks the selected key set and the key's channel.
       
    87      */
       
    88     static void testChange(SelectionKey key, int from, int to) throws IOException {
       
    89         Selector sel = key.selector();
       
    90         assertTrue(sel.keys().size() == 1, "Only one channel should be registered");
       
    91 
       
    92         // ensure that channel is registered with the "from" interest set
       
    93         key.interestOps(from);
       
    94         sel.selectNow();
       
    95         sel.selectedKeys().clear();
       
    96 
       
    97         // change to the "to" interest set
       
    98         key.interestOps(to);
       
    99         System.out.println("select...");
       
   100         int selected = sel.selectNow();
       
   101         System.out.println("" + selected + " channel(s) selected");
       
   102 
       
   103         int expected = (to == 0) ? 0 : 1;
       
   104         assertTrue(selected == expected, "Expected " + expected);
       
   105 
       
   106         // check selected keys
       
   107         for (SelectionKey k: sel.selectedKeys()) {
       
   108             assertTrue(k == key, "Unexpected key selected");
       
   109 
       
   110             boolean readable = k.isReadable();
       
   111             boolean writable = k.isWritable();
       
   112 
       
   113             System.out.println("key readable: " + readable);
       
   114             System.out.println("key writable: " + writable);
       
   115 
       
   116             if ((to & OP_READ) == 0) {
       
   117                 assertTrue(!readable, "Not expected to be readable");
       
   118             } else {
       
   119                 assertTrue(readable, "Expected to be readable");
       
   120             }
       
   121 
       
   122             if ((to & OP_WRITE) == 0) {
       
   123                 assertTrue(!writable, "Not expected to be writable");
       
   124             } else {
       
   125                 assertTrue(writable, "Expected to be writable");
       
   126             }
       
   127 
       
   128             sel.selectedKeys().clear();
       
   129         }
       
   130     }
       
   131 
       
   132     /**
       
   133      * Tests that given Selector's select method blocks.
       
   134      */
       
   135     static void testForSpin(Selector sel) throws IOException {
       
   136         System.out.println("Test for spin...");
       
   137         long start = System.currentTimeMillis();
       
   138         int count = 3;
       
   139         while (count-- > 0) {
       
   140             int selected = sel.select(1000);
       
   141             System.out.println("" + selected + " channel(s) selected");
       
   142             assertTrue(selected == 0, "Channel should not be selected");
       
   143         }
       
   144         long dur = System.currentTimeMillis() - start;
       
   145         assertTrue(dur > 1000, "select was too short");
       
   146     }
       
   147 
       
   148     public static void main(String[] args) throws IOException {
       
   149         InetAddress lh = InetAddress.getLocalHost();
       
   150 
       
   151         // create loopback connection
       
   152         ServerSocketChannel ssc =
       
   153             ServerSocketChannel.open().bind(new InetSocketAddress(0));
       
   154 
       
   155         final SocketChannel sc = SocketChannel.open();
       
   156         sc.setOption(StandardSocketOptions.TCP_NODELAY, true);
       
   157         sc.connect(new InetSocketAddress(lh, ssc.socket().getLocalPort()));
       
   158         SocketChannel peer = ssc.accept();
       
   159         peer.setOption(StandardSocketOptions.TCP_NODELAY, true);
       
   160 
       
   161         sc.configureBlocking(false);
       
   162 
       
   163         // ensure that channel "sc" is readable
       
   164         makeReadable(peer, sc);
       
   165 
       
   166         try (Selector sel = Selector.open()) {
       
   167             SelectionKey key = sc.register(sel, 0);
       
   168             sel.selectNow();
       
   169 
       
   170             // test all transitions
       
   171             for (int from: OPS) {
       
   172                 for (int to: OPS) {
       
   173 
       
   174                     System.out.println(toOpsString(from) + " -> " + toOpsString(to));
       
   175 
       
   176                     testChange(key, from, to);
       
   177 
       
   178                     // if the interst ops is now 0 then Selector should not spin
       
   179                     if (to == 0)
       
   180                         testForSpin(sel);
       
   181 
       
   182                     // if interest ops is now OP_READ then make non-readable
       
   183                     // and test that Selector does not spin.
       
   184                     if (to == OP_READ) {
       
   185                         System.out.println("Drain channel...");
       
   186                         drain(sc);
       
   187                         testForSpin(sel);
       
   188                         System.out.println("Make channel readable again");
       
   189                         makeReadable(peer, sc);
       
   190                     }
       
   191 
       
   192                     System.out.println();
       
   193                 }
       
   194             }
       
   195 
       
   196         } finally {
       
   197             sc.close();
       
   198             peer.close();
       
   199             ssc.close();
       
   200         }
       
   201     }
       
   202 
       
   203     static void assertTrue(boolean v, String msg) {
       
   204         if (!v) throw new RuntimeException(msg);
       
   205     }
       
   206 
       
   207 }