Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java
32288 views
/*1* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.ch;2627import java.nio.channels.*;28import java.net.InetSocketAddress;29import java.util.concurrent.Future;30import java.util.concurrent.atomic.AtomicBoolean;31import java.io.IOException;32import java.security.AccessControlContext;33import java.security.AccessController;34import java.security.PrivilegedAction;35import sun.misc.Unsafe;3637/**38* Windows implementation of AsynchronousServerSocketChannel using overlapped I/O.39*/4041class WindowsAsynchronousServerSocketChannelImpl42extends AsynchronousServerSocketChannelImpl implements Iocp.OverlappedChannel43{44private static final Unsafe unsafe = Unsafe.getUnsafe();4546// 2 * (sizeof(SOCKET_ADDRESS) + 16)47private static final int DATA_BUFFER_SIZE = 88;4849private final long handle;50private final int completionKey;51private final Iocp iocp;5253// typically there will be zero, or one I/O operations pending. In rare54// cases there may be more. These rare cases arise when a sequence of accept55// operations complete immediately and handled by the initiating thread.56// The corresponding OVERLAPPED cannot be reused/released until the completion57// event has been posted.58private final PendingIoCache ioCache;5960// the data buffer to receive the local/remote socket address61private final long dataBuffer;6263// flag to indicate that an accept operation is outstanding64private AtomicBoolean accepting = new AtomicBoolean();656667WindowsAsynchronousServerSocketChannelImpl(Iocp iocp) throws IOException {68super(iocp);6970// associate socket with given completion port71long h = IOUtil.fdVal(fd);72int key;73try {74key = iocp.associate(this, h);75} catch (IOException x) {76closesocket0(h); // prevent leak77throw x;78}7980this.handle = h;81this.completionKey = key;82this.iocp = iocp;83this.ioCache = new PendingIoCache();84this.dataBuffer = unsafe.allocateMemory(DATA_BUFFER_SIZE);85}8687@Override88public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {89return ioCache.remove(overlapped);90}9192@Override93void implClose() throws IOException {94// close socket (which may cause outstanding accept to be aborted).95closesocket0(handle);9697// waits until the accept operations have completed98ioCache.close();99100// finally disassociate from the completion port101iocp.disassociate(completionKey);102103// release other resources104unsafe.freeMemory(dataBuffer);105}106107@Override108public AsynchronousChannelGroupImpl group() {109return iocp;110}111112/**113* Task to initiate accept operation and to handle result.114*/115private class AcceptTask implements Runnable, Iocp.ResultHandler {116private final WindowsAsynchronousSocketChannelImpl channel;117private final AccessControlContext acc;118private final PendingFuture<AsynchronousSocketChannel,Object> result;119120AcceptTask(WindowsAsynchronousSocketChannelImpl channel,121AccessControlContext acc,122PendingFuture<AsynchronousSocketChannel,Object> result)123{124this.channel = channel;125this.acc = acc;126this.result = result;127}128129void enableAccept() {130accepting.set(false);131}132133void closeChildChannel() {134try {135channel.close();136} catch (IOException ignore) { }137}138139// caller must have acquired read lock for the listener and child channel.140void finishAccept() throws IOException {141/**142* Set local/remote addresses. This is currently very inefficient143* in that it requires 2 calls to getsockname and 2 calls to getpeername.144* (should change this to use GetAcceptExSockaddrs)145*/146updateAcceptContext(handle, channel.handle());147148InetSocketAddress local = Net.localAddress(channel.fd);149final InetSocketAddress remote = Net.remoteAddress(channel.fd);150channel.setConnected(local, remote);151152// permission check (in context of initiating thread)153if (acc != null) {154AccessController.doPrivileged(new PrivilegedAction<Void>() {155public Void run() {156SecurityManager sm = System.getSecurityManager();157sm.checkAccept(remote.getAddress().getHostAddress(),158remote.getPort());159return null;160}161}, acc);162}163}164165/**166* Initiates the accept operation.167*/168@Override169public void run() {170long overlapped = 0L;171172try {173// begin usage of listener socket174begin();175try {176// begin usage of child socket (as it is registered with177// completion port and so may be closed in the event that178// the group is forcefully closed).179channel.begin();180181synchronized (result) {182overlapped = ioCache.add(result);183184int n = accept0(handle, channel.handle(), overlapped, dataBuffer);185if (n == IOStatus.UNAVAILABLE) {186return;187}188189// connection accepted immediately190finishAccept();191192// allow another accept before the result is set193enableAccept();194result.setResult(channel);195}196} finally {197// end usage on child socket198channel.end();199}200} catch (Throwable x) {201// failed to initiate accept so release resources202if (overlapped != 0L)203ioCache.remove(overlapped);204closeChildChannel();205if (x instanceof ClosedChannelException)206x = new AsynchronousCloseException();207if (!(x instanceof IOException) && !(x instanceof SecurityException))208x = new IOException(x);209enableAccept();210result.setFailure(x);211} finally {212// end of usage of listener socket213end();214}215216// accept completed immediately but may not have executed on217// initiating thread in which case the operation may have been218// cancelled.219if (result.isCancelled()) {220closeChildChannel();221}222223// invoke completion handler224Invoker.invokeIndirectly(result);225}226227/**228* Executed when the I/O has completed229*/230@Override231public void completed(int bytesTransferred, boolean canInvokeDirect) {232try {233// connection accept after group has shutdown234if (iocp.isShutdown()) {235throw new IOException(new ShutdownChannelGroupException());236}237238// finish the accept239try {240begin();241try {242channel.begin();243finishAccept();244} finally {245channel.end();246}247} finally {248end();249}250251// allow another accept before the result is set252enableAccept();253result.setResult(channel);254} catch (Throwable x) {255enableAccept();256closeChildChannel();257if (x instanceof ClosedChannelException)258x = new AsynchronousCloseException();259if (!(x instanceof IOException) && !(x instanceof SecurityException))260x = new IOException(x);261result.setFailure(x);262}263264// if an async cancel has already cancelled the operation then265// close the new channel so as to free resources266if (result.isCancelled()) {267closeChildChannel();268}269270// invoke handler (but not directly)271Invoker.invokeIndirectly(result);272}273274@Override275public void failed(int error, IOException x) {276enableAccept();277closeChildChannel();278279// release waiters280if (isOpen()) {281result.setFailure(x);282} else {283result.setFailure(new AsynchronousCloseException());284}285Invoker.invokeIndirectly(result);286}287}288289@Override290Future<AsynchronousSocketChannel> implAccept(Object attachment,291final CompletionHandler<AsynchronousSocketChannel,Object> handler)292{293if (!isOpen()) {294Throwable exc = new ClosedChannelException();295if (handler == null)296return CompletedFuture.withFailure(exc);297Invoker.invokeIndirectly(this, handler, attachment, null, exc);298return null;299}300if (isAcceptKilled())301throw new RuntimeException("Accept not allowed due to cancellation");302303// ensure channel is bound to local address304if (localAddress == null)305throw new NotYetBoundException();306307// create the socket that will be accepted. The creation of the socket308// is enclosed by a begin/end for the listener socket to ensure that309// we check that the listener is open and also to prevent the I/O310// port from being closed as the new socket is registered.311WindowsAsynchronousSocketChannelImpl ch = null;312IOException ioe = null;313try {314begin();315ch = new WindowsAsynchronousSocketChannelImpl(iocp, false);316} catch (IOException x) {317ioe = x;318} finally {319end();320}321if (ioe != null) {322if (handler == null)323return CompletedFuture.withFailure(ioe);324Invoker.invokeIndirectly(this, handler, attachment, null, ioe);325return null;326}327328// need calling context when there is security manager as329// permission check may be done in a different thread without330// any application call frames on the stack331AccessControlContext acc = (System.getSecurityManager() == null) ?332null : AccessController.getContext();333334PendingFuture<AsynchronousSocketChannel,Object> result =335new PendingFuture<AsynchronousSocketChannel,Object>(this, handler, attachment);336AcceptTask task = new AcceptTask(ch, acc, result);337result.setContext(task);338339// check and set flag to prevent concurrent accepting340if (!accepting.compareAndSet(false, true))341throw new AcceptPendingException();342343// initiate I/O344if (Iocp.supportsThreadAgnosticIo()) {345task.run();346} else {347Invoker.invokeOnThreadInThreadPool(this, task);348}349return result;350}351352// -- Native methods --353354private static native void initIDs();355356private static native int accept0(long listenSocket, long acceptSocket,357long overlapped, long dataBuffer) throws IOException;358359private static native void updateAcceptContext(long listenSocket,360long acceptSocket) throws IOException;361362private static native void closesocket0(long socket) throws IOException;363364static {365IOUtil.load();366initIDs();367}368}369370371