1 /* 2 * Copyright (c) 2018, 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 8202252 26 * @requires (os.family != "windows") 27 * @run testng CompletionHandlerRelease 28 * @summary Verify that reference to CompletionHandler is cleared after use 29 */ 30 31 import java.io.Closeable; 32 import java.io.IOException; 33 import java.lang.ref.WeakReference; 34 import java.net.InetAddress; 35 import java.net.InetSocketAddress; 36 import static java.net.StandardSocketOptions.*; 37 import java.nio.ByteBuffer; 38 import java.nio.channels.AsynchronousChannelGroup; 39 import java.nio.channels.AsynchronousServerSocketChannel; 40 import java.nio.channels.AsynchronousSocketChannel; 41 import java.nio.channels.CompletionHandler; 42 import java.util.concurrent.CountDownLatch; 43 import java.util.concurrent.Executors; 44 import java.util.concurrent.Future; 45 46 import org.testng.annotations.AfterTest; 47 import org.testng.annotations.BeforeTest; 48 import org.testng.annotations.Test; 49 import static org.testng.Assert.*; 50 51 public class CompletionHandlerRelease { 52 @Test 53 public void testConnect() throws Exception { 54 System.out.println("-- testConnect --"); // XXX 55 56 try (Server server = new Server(); 57 AsynchronousSocketChannel ch = 58 AsynchronousSocketChannel.open(GROUP)) { 59 Object obj = new Object(); 60 WeakReference<Object> ref = new WeakReference<Object>(obj); 61 CountDownLatch latch = new CountDownLatch(1); 62 Handler<Void,Object> handler = 63 new Handler<Void,Object>("connect", obj, latch); 64 65 ch.connect(server.address(), null, handler); 66 67 try { 68 latch.await(); 69 } catch (InterruptedException ignore) { 70 } 71 Thread.sleep(1000); 72 73 obj = null; 74 handler = null; 75 System.gc(); 76 77 assertNull(ref.get()); 78 } 79 } 80 81 @Test 82 public void testWrite() throws Exception { 83 System.out.println("-- testWrite --"); // XXX 84 85 try (Server server = new Server(); 86 AsynchronousSocketChannel ch = 87 AsynchronousSocketChannel.open(GROUP)) { 88 ch.connect(server.address()).get(); 89 90 try (AsynchronousSocketChannel sc = server.accept().get()) { 91 ByteBuffer src = ByteBuffer.wrap("hello".getBytes("UTF-8")); 92 sc.setOption(SO_SNDBUF, src.remaining()); 93 94 Object obj = new Object(); 95 WeakReference<Object> ref = new WeakReference<Object>(obj); 96 CountDownLatch latch = new CountDownLatch(1); 97 Handler<Integer,Object> handler = 98 new Handler<Integer,Object>("write", obj, latch); 99 100 sc.write(src, null, handler); 101 102 try { 103 latch.await(); 104 } catch (InterruptedException ignore) { 105 } 106 Thread.sleep(1000); 107 108 obj = null; 109 handler = null; 110 System.gc(); 111 112 assertNull(ref.get()); 113 } 114 } 115 } 116 117 @Test 118 public void testRead() throws Exception { 119 System.out.println("-- testRead --"); // XXX 120 121 try (Server server = new Server(); 122 AsynchronousSocketChannel ch = 123 AsynchronousSocketChannel.open(GROUP)) { 124 ch.connect(server.address()).get(); 125 126 try (AsynchronousSocketChannel sc = server.accept().get()) { 127 ByteBuffer src = ByteBuffer.wrap("hello".getBytes("UTF-8")); 128 sc.setOption(SO_SNDBUF, src.remaining()); 129 sc.write(src).get(); 130 131 Object obj = new Object(); 132 WeakReference<Object> ref = new WeakReference<Object>(obj); 133 CountDownLatch latch = new CountDownLatch(1); 134 Handler<Integer,Object> handler = 135 new Handler<Integer,Object>("read", obj, latch); 136 137 ByteBuffer dst = ByteBuffer.allocate(64); 138 ch.read(dst, null, handler); 139 140 obj = null; 141 handler = null; 142 143 try { 144 latch.await(); 145 } catch (InterruptedException ignore) { 146 } 147 Thread.sleep(1000); 148 149 System.gc(); 150 151 assertNull(ref.get()); 152 } 153 } 154 } 155 156 private AsynchronousChannelGroup GROUP; 157 158 @BeforeTest 159 void setup() throws IOException { 160 GROUP = AsynchronousChannelGroup.withFixedThreadPool(2, 161 Executors.defaultThreadFactory()); 162 } 163 164 @AfterTest 165 void cleanup() throws IOException { 166 GROUP.shutdownNow(); 167 } 168 169 class Server implements Closeable { 170 private final AsynchronousServerSocketChannel ssc; 171 private final InetSocketAddress address; 172 173 Server() throws IOException { 174 this(0); 175 } 176 177 Server(int recvBufSize) throws IOException { 178 ssc = AsynchronousServerSocketChannel.open(GROUP); 179 if (recvBufSize > 0) { 180 ssc.setOption(SO_RCVBUF, recvBufSize); 181 } 182 ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 183 0)); 184 address = (InetSocketAddress)ssc.getLocalAddress(); 185 } 186 187 InetSocketAddress address() { 188 return address; 189 } 190 191 Future<AsynchronousSocketChannel> accept() throws IOException { 192 return ssc.accept(); 193 } 194 195 public void close() throws IOException { 196 System.out.println("Server.close()"); 197 ssc.close(); 198 } 199 } 200 201 static class Handler<V,A> implements CompletionHandler<V,A> { 202 private final String name; 203 private final Object obj; 204 private final CountDownLatch latch; 205 206 Handler(String name, Object obj, CountDownLatch latch) { 207 this.name = name; 208 this.obj = obj; 209 this.latch = latch; 210 } 211 212 public void completed(V result, A attachment) { 213 System.out.format("%s completed(%s, %s)%n", 214 name, result, attachment); 215 latch.countDown(); 216 } 217 218 public void failed(Throwable exc, A attachment) { 219 System.out.format("%s failed(%s, %s)%n", 220 name, exc, attachment); 221 exc.printStackTrace(); 222 latch.countDown(); 223 } 224 } 225 }