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