16b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson/* 26b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * Copyright (C) 2010 The Android Open Source Project 36b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * 46b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 56b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * you may not use this file except in compliance with the License. 66b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * You may obtain a copy of the License at 76b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * 86b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 96b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * 106b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * Unless required by applicable law or agreed to in writing, software 116b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 126b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * See the License for the specific language governing permissions and 146b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson * limitations under the License. 156b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson */ 164557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonpackage libcore.java.nio.channels; 176b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson 18173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamathimport android.system.Os; 196b739231f8985f33f20672fe727fde0d0f023eadJesse Wilsonimport java.io.IOException; 20d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.net.InetSocketAddress; 21d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.net.ServerSocket; 22173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamathimport java.io.FileDescriptor; 2357656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughesimport java.nio.ByteBuffer; 24d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.nio.channels.NoConnectionPendingException; 25d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.nio.channels.SelectionKey; 264557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.nio.channels.Selector; 27d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.nio.channels.ServerSocketChannel; 28d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.nio.channels.SocketChannel; 29d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.util.concurrent.CountDownLatch; 30d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughesimport java.util.concurrent.TimeUnit; 316b739231f8985f33f20672fe727fde0d0f023eadJesse Wilsonimport junit.framework.TestCase; 326b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson 336b739231f8985f33f20672fe727fde0d0f023eadJesse Wilsonpublic class SelectorTest extends TestCase { 34d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes public void testNonBlockingConnect_immediate() throws Exception { 35d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes // Test the case where we [probably] connect immediately. 36d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes Selector selector = Selector.open(); 37d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes ServerSocketChannel ssc = ServerSocketChannel.open(); 38d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes try { 39d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes ssc.configureBlocking(false); 40d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes ssc.socket().bind(null); 41d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes 42d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes SocketChannel sc = SocketChannel.open(); 43d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes sc.configureBlocking(false); 44d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes sc.connect(ssc.socket().getLocalSocketAddress()); 45d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes SelectionKey key = sc.register(selector, SelectionKey.OP_CONNECT); 46d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes assertEquals(1, selector.select()); 47d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes assertEquals(SelectionKey.OP_CONNECT, key.readyOps()); 48d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes sc.finishConnect(); 49d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes } finally { 50d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes selector.close(); 51d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes ssc.close(); 52d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes } 53d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes } 54d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes 55d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes // http://code.google.com/p/android/issues/detail?id=15388 56d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes public void testInterrupted() throws IOException { 57d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes Selector selector = Selector.open(); 580bb999c4d83b41e9d65735c417cae212bfab7d61Neil Fuller Thread.currentThread().interrupt(); 59d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes try { 60d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes int count = selector.select(); 61d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes assertEquals(0, count); 62e37bfbcea35237c5c61f4d94788eafbc5f1f4ee8Neil Fuller assertTrue(Thread.currentThread().isInterrupted()); 63d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes } finally { 640bb999c4d83b41e9d65735c417cae212bfab7d61Neil Fuller // Clear the interrupted thread state so that it does not interfere with later tests. 650bb999c4d83b41e9d65735c417cae212bfab7d61Neil Fuller Thread.interrupted(); 660bb999c4d83b41e9d65735c417cae212bfab7d61Neil Fuller 67d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes selector.close(); 68d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes } 69d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes } 70d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes 71d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes public void testManyWakeupCallsTriggerOnlyOneWakeup() throws Exception { 72d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes final Selector selector = Selector.open(); 73d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes try { 74d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes selector.wakeup(); 75d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes selector.wakeup(); 76d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes selector.wakeup(); 77d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes selector.select(); 78d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes 79d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes // create a latch that will reach 0 when select returns 80d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes final CountDownLatch selectReturned = new CountDownLatch(1); 81d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes Thread thread = new Thread(new Runnable() { 82d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes @Override public void run() { 83d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes try { 84d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes selector.select(); 85d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes selectReturned.countDown(); 86d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes } catch (IOException ignored) { 87d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes } 88d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes } 89d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes }); 90d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes thread.start(); 91d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes 92d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes // select doesn't ever return, so await() times out and returns false 938b3d7dfa1b50eb611b20824242f35eba2cfba46eElliott Hughes assertFalse(selectReturned.await(2, TimeUnit.SECONDS)); 94d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes } finally { 95d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes selector.close(); 96d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes } 97d3992b82602c2eef8e83ae7150f987cc9e0864fdElliott Hughes } 986b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson 9957656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes // We previously leaked a file descriptor for each selector instance created. 10057656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes // 10157656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes // http://code.google.com/p/android/issues/detail?id=5993 10257656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes // http://code.google.com/p/android/issues/detail?id=4825 1036b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson public void testLeakingPipes() throws IOException { 1046b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson for (int i = 0; i < 2000; i++) { 1056b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson Selector selector = Selector.open(); 1066b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson selector.close(); 1076b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson } 1086b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson } 10957656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes 11057656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes public void test_57456() throws Exception { 11199a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller Selector selector = Selector.open(); 11299a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller ServerSocketChannel ssc = ServerSocketChannel.open(); 11399a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller 11499a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller try { 11599a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller // Connect. 11699a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller ssc.configureBlocking(false); 11799a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller ssc.socket().bind(null); 11899a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller SocketChannel sc = SocketChannel.open(); 11999a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller sc.connect(ssc.socket().getLocalSocketAddress()); 12099a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller sc.finishConnect(); 12199a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller 12299a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller // Switch to non-blocking so we can use a Selector. 12399a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller sc.configureBlocking(false); 12499a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller 12599a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller // Have the 'server' write something. 12699a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller ssc.accept().write(ByteBuffer.allocate(128)); 12799a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller 12899a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller // At this point, the client should be able to read or write immediately. 12999a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller // (It shouldn't be able to connect because it's already connected.) 13099a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller SelectionKey key = sc.register(selector, 13199a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE); 13299a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller assertEquals(1, selector.select()); 13399a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller assertEquals(SelectionKey.OP_READ | SelectionKey.OP_WRITE, key.readyOps()); 13499a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller assertEquals(0, selector.select()); 13599a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller } finally { 13699a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller selector.close(); 13799a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller ssc.close(); 13899a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller } 13999a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller } 14099a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller 14199a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller // http://code.google.com/p/android/issues/detail?id=80785 14299a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller public void test_80785() throws Exception { 14399a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller Selector selector = Selector.open(); 14457656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes selector.close(); 14599a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller 14699a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller // Historically on android this did not throw an exception. Due to the bug it would throw 14799a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller // an (undeclared) IOException. 14899a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller selector.wakeup(); 14957656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes } 150173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath 151173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath public void test28318596() throws Exception { 152173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath Selector selector = Selector.open(); 153173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath ServerSocketChannel ssc = ServerSocketChannel.open(); 154173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath SocketChannel server = null; 155173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath FileDescriptor dup = null; 156173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath try { 157173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath ssc.configureBlocking(false); 158173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath ssc.bind(null); 159173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath SocketChannel sc = SocketChannel.open(); 160173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath sc.connect(ssc.getLocalAddress()); 161173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath sc.finishConnect(); 162173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath 163173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // Switch to non-blocking so we can use a Selector. 164173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath sc.configureBlocking(false); 165173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath 166173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); 167173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath assertEquals(1, selector.select(100)); 168173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath assertEquals(0, selector.select(100)); 169173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath 170173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath server = ssc.accept(); 171173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath server.write(ByteBuffer.allocate(8192)); 172173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath 173173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // This triggered b/28318596. We'd call through to preClose() which would dup2 174173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // a known sink descriptor into the channel's descriptor. All subsequent calls 175173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // to epoll_ctl(EPOLL_CTL_DEL) would then fail because the kernel was unhappy about 176173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // the fact that the descriptor was associated with a different file. This meant that 177173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // we'd spuriously return from select because we've never managed to remove the file 178173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // associated with the selection key from the epoll fd's interest set. 179173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath server.shutdownInput(); 180173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath server.shutdownOutput(); 181173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // We dup the socket here to work around kernel cleanup mechanisms. The kernel will 182173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // automatically unregister a file reference from all associated epoll instances once 183173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // the last non-epoll instance has been closed. 184173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath dup = Os.dup(sc.socket().getFileDescriptor$()); 185173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath sc.close(); 186173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath 187173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // The following is a finicky loop to try and figure out whether we're going into 188173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // a tight loop where select returns immediately (we should've received a POLLHUP 189173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // and/or POLLIN on |sc|). 190173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath long start = System.currentTimeMillis(); 191173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath for (int i = 0; i < 10; ++i) { 192173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath assertEquals(0, selector.select(500)); 193173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath } 194173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath 195173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath server.close(); 196173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath long end = System.currentTimeMillis(); 197173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // There should have been no events during the loop above (the size of 198173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // the interest set is zero) so all of the selects should timeout and take 199173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath // ~5000ms. 200173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath assertTrue("Time taken: " + (end - start), (end - start) > 2000); 201173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath } finally { 202173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath selector.close(); 203173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath ssc.close(); 204173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath 205173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath if (server != null) { 206173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath server.close(); 207173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath } 208173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath 209173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath if (dup != null) { 210173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath Os.close(dup); 211173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath } 212173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath } 213173e4cf05284f4f96b0c21976186edfc949559cdNarayan Kamath } 2146b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson} 215