Home | History | Annotate | Download | only in channels
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package libcore.java.nio.channels;
     17 
     18 import android.system.Os;
     19 import java.io.IOException;
     20 import java.net.InetSocketAddress;
     21 import java.net.ServerSocket;
     22 import java.io.FileDescriptor;
     23 import java.nio.ByteBuffer;
     24 import java.nio.channels.NoConnectionPendingException;
     25 import java.nio.channels.SelectionKey;
     26 import java.nio.channels.Selector;
     27 import java.nio.channels.ServerSocketChannel;
     28 import java.nio.channels.SocketChannel;
     29 import java.util.concurrent.CountDownLatch;
     30 import java.util.concurrent.TimeUnit;
     31 import junit.framework.TestCase;
     32 
     33 public class SelectorTest extends TestCase {
     34     public void testNonBlockingConnect_immediate() throws Exception {
     35         // Test the case where we [probably] connect immediately.
     36         Selector selector = Selector.open();
     37         ServerSocketChannel ssc = ServerSocketChannel.open();
     38         try {
     39             ssc.configureBlocking(false);
     40             ssc.socket().bind(null);
     41 
     42             SocketChannel sc = SocketChannel.open();
     43             sc.configureBlocking(false);
     44             sc.connect(ssc.socket().getLocalSocketAddress());
     45             SelectionKey key = sc.register(selector, SelectionKey.OP_CONNECT);
     46             assertEquals(1, selector.select());
     47             assertEquals(SelectionKey.OP_CONNECT, key.readyOps());
     48             sc.finishConnect();
     49         } finally {
     50             selector.close();
     51             ssc.close();
     52         }
     53     }
     54 
     55     // http://code.google.com/p/android/issues/detail?id=15388
     56     public void testInterrupted() throws IOException {
     57         Selector selector = Selector.open();
     58         Thread.currentThread().interrupt();
     59         try {
     60             int count = selector.select();
     61             assertEquals(0, count);
     62             assertTrue(Thread.currentThread().isInterrupted());
     63         } finally {
     64             // Clear the interrupted thread state so that it does not interfere with later tests.
     65             Thread.interrupted();
     66 
     67             selector.close();
     68         }
     69     }
     70 
     71     public void testManyWakeupCallsTriggerOnlyOneWakeup() throws Exception {
     72         final Selector selector = Selector.open();
     73         try {
     74             selector.wakeup();
     75             selector.wakeup();
     76             selector.wakeup();
     77             selector.select();
     78 
     79             // create a latch that will reach 0 when select returns
     80             final CountDownLatch selectReturned = new CountDownLatch(1);
     81             Thread thread = new Thread(new Runnable() {
     82                 @Override public void run() {
     83                     try {
     84                         selector.select();
     85                         selectReturned.countDown();
     86                     } catch (IOException ignored) {
     87                     }
     88                 }
     89             });
     90             thread.start();
     91 
     92             // select doesn't ever return, so await() times out and returns false
     93             assertFalse(selectReturned.await(2, TimeUnit.SECONDS));
     94         } finally {
     95             selector.close();
     96         }
     97     }
     98 
     99     // We previously leaked a file descriptor for each selector instance created.
    100     //
    101     // http://code.google.com/p/android/issues/detail?id=5993
    102     // http://code.google.com/p/android/issues/detail?id=4825
    103     public void testLeakingPipes() throws IOException {
    104         for (int i = 0; i < 2000; i++) {
    105             Selector selector = Selector.open();
    106             selector.close();
    107         }
    108     }
    109 
    110     public void test_57456() throws Exception {
    111         Selector selector = Selector.open();
    112         ServerSocketChannel ssc = ServerSocketChannel.open();
    113 
    114         try {
    115             // Connect.
    116             ssc.configureBlocking(false);
    117             ssc.socket().bind(null);
    118             SocketChannel sc = SocketChannel.open();
    119             sc.connect(ssc.socket().getLocalSocketAddress());
    120             sc.finishConnect();
    121 
    122             // Switch to non-blocking so we can use a Selector.
    123             sc.configureBlocking(false);
    124 
    125             // Have the 'server' write something.
    126             ssc.accept().write(ByteBuffer.allocate(128));
    127 
    128             // At this point, the client should be able to read or write immediately.
    129             // (It shouldn't be able to connect because it's already connected.)
    130             SelectionKey key = sc.register(selector,
    131                     SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE);
    132             assertEquals(1, selector.select());
    133             assertEquals(SelectionKey.OP_READ | SelectionKey.OP_WRITE, key.readyOps());
    134             assertEquals(0, selector.select());
    135         } finally {
    136             selector.close();
    137             ssc.close();
    138         }
    139     }
    140 
    141     // http://code.google.com/p/android/issues/detail?id=80785
    142     public void test_80785() throws Exception {
    143         Selector selector = Selector.open();
    144         selector.close();
    145 
    146         // Historically on android this did not throw an exception. Due to the bug it would throw
    147         // an (undeclared) IOException.
    148         selector.wakeup();
    149     }
    150 
    151     public void test28318596() throws Exception {
    152         Selector selector = Selector.open();
    153         ServerSocketChannel ssc = ServerSocketChannel.open();
    154         SocketChannel server = null;
    155         FileDescriptor dup = null;
    156         try {
    157             ssc.configureBlocking(false);
    158             ssc.bind(null);
    159             SocketChannel sc = SocketChannel.open();
    160             sc.connect(ssc.getLocalAddress());
    161             sc.finishConnect();
    162 
    163             // Switch to non-blocking so we can use a Selector.
    164             sc.configureBlocking(false);
    165 
    166             sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
    167             assertEquals(1, selector.select(100));
    168             assertEquals(0, selector.select(100));
    169 
    170             server = ssc.accept();
    171             server.write(ByteBuffer.allocate(8192));
    172 
    173             // This triggered b/28318596. We'd call through to preClose() which would dup2
    174             // a known sink descriptor into the channel's descriptor. All subsequent calls
    175             // to epoll_ctl(EPOLL_CTL_DEL) would then fail because the kernel was unhappy about
    176             // the fact that the descriptor was associated with a different file. This meant that
    177             // we'd spuriously return from select because we've never managed to remove the file
    178             // associated with the selection key from the epoll fd's interest set.
    179             server.shutdownInput();
    180             server.shutdownOutput();
    181             // We dup the socket here to work around kernel cleanup mechanisms. The kernel will
    182             // automatically unregister a file reference from all associated epoll instances once
    183             // the last non-epoll instance has been closed.
    184             dup = Os.dup(sc.socket().getFileDescriptor$());
    185             sc.close();
    186 
    187             // The following is a finicky loop to try and figure out whether we're going into
    188             // a tight loop where select returns immediately (we should've received a POLLHUP
    189             // and/or POLLIN on |sc|).
    190             long start = System.currentTimeMillis();
    191             for (int i = 0; i < 10; ++i) {
    192                 assertEquals(0, selector.select(500));
    193             }
    194 
    195             server.close();
    196             long end = System.currentTimeMillis();
    197             // There should have been no events during the loop above (the size of
    198             // the interest set is zero) so all of the selects should timeout and take
    199             // ~5000ms.
    200             assertTrue("Time taken: " + (end - start), (end - start) > 2000);
    201         } finally {
    202             selector.close();
    203             ssc.close();
    204 
    205             if (server != null) {
    206                 server.close();
    207             }
    208 
    209             if (dup != null) {
    210                 Os.close(dup);
    211             }
    212         }
    213     }
    214 }
    215