Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.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.util.concurrent.*;29import java.io.IOException;30import java.io.FileDescriptor;31import java.net.InetSocketAddress;32import java.util.concurrent.atomic.AtomicBoolean;33import java.security.AccessControlContext;34import java.security.AccessController;35import java.security.PrivilegedAction;3637/**38* Unix implementation of AsynchronousServerSocketChannel39*/4041class UnixAsynchronousServerSocketChannelImpl42extends AsynchronousServerSocketChannelImpl43implements Port.PollableChannel44{45private final static NativeDispatcher nd = new SocketDispatcher();4647private final Port port;48private final int fdVal;4950// flag to indicate an accept is outstanding51private final AtomicBoolean accepting = new AtomicBoolean();52private void enableAccept() {53accepting.set(false);54}5556// used to ensure that the context for an asynchronous accept is visible57// the pooled thread that handles the I/O event58private final Object updateLock = new Object();5960// pending accept61private boolean acceptPending;62private CompletionHandler<AsynchronousSocketChannel,Object> acceptHandler;63private Object acceptAttachment;64private PendingFuture<AsynchronousSocketChannel,Object> acceptFuture;6566// context for permission check when security manager set67private AccessControlContext acceptAcc;686970UnixAsynchronousServerSocketChannelImpl(Port port)71throws IOException72{73super(port);7475try {76IOUtil.configureBlocking(fd, false);77} catch (IOException x) {78nd.close(fd); // prevent leak79throw x;80}81this.port = port;82this.fdVal = IOUtil.fdVal(fd);8384// add mapping from file descriptor to this channel85port.register(fdVal, this);86}8788@Override89void implClose() throws IOException {90// remove the mapping91port.unregister(fdVal);9293// close file descriptor94nd.close(fd);9596// if there is a pending accept then complete it97CompletionHandler<AsynchronousSocketChannel,Object> handler;98Object att;99PendingFuture<AsynchronousSocketChannel,Object> future;100synchronized (updateLock) {101if (!acceptPending)102return; // no pending accept103acceptPending = false;104handler = acceptHandler;105att = acceptAttachment;106future = acceptFuture;107}108109// discard the stack trace as otherwise it may appear that implClose110// has thrown the exception.111AsynchronousCloseException x = new AsynchronousCloseException();112x.setStackTrace(new StackTraceElement[0]);113if (handler == null) {114future.setFailure(x);115} else {116// invoke by submitting task rather than directly117Invoker.invokeIndirectly(this, handler, att, null, x);118}119}120121@Override122public AsynchronousChannelGroupImpl group() {123return port;124}125126/**127* Invoked by event handling thread when listener socket is polled128*/129@Override130public void onEvent(int events, boolean mayInvokeDirect) {131synchronized (updateLock) {132if (!acceptPending)133return; // may have been grabbed by asynchronous close134acceptPending = false;135}136137// attempt to accept connection138FileDescriptor newfd = new FileDescriptor();139InetSocketAddress[] isaa = new InetSocketAddress[1];140Throwable exc = null;141try {142begin();143int n = accept(this.fd, newfd, isaa);144145// spurious wakeup, is this possible?146if (n == IOStatus.UNAVAILABLE) {147synchronized (updateLock) {148acceptPending = true;149}150port.startPoll(fdVal, Net.POLLIN);151return;152}153154} catch (Throwable x) {155if (x instanceof ClosedChannelException)156x = new AsynchronousCloseException();157exc = x;158} finally {159end();160}161162// Connection accepted so finish it when not holding locks.163AsynchronousSocketChannel child = null;164if (exc == null) {165try {166child = finishAccept(newfd, isaa[0], acceptAcc);167} catch (Throwable x) {168if (!(x instanceof IOException) && !(x instanceof SecurityException))169x = new IOException(x);170exc = x;171}172}173174// copy field befores accept is re-renabled175CompletionHandler<AsynchronousSocketChannel,Object> handler = acceptHandler;176Object att = acceptAttachment;177PendingFuture<AsynchronousSocketChannel,Object> future = acceptFuture;178179// re-enable accepting and invoke handler180enableAccept();181182if (handler == null) {183future.setResult(child, exc);184// if an async cancel has already cancelled the operation then185// close the new channel so as to free resources186if (child != null && future.isCancelled()) {187try {188child.close();189} catch (IOException ignore) { }190}191} else {192Invoker.invoke(this, handler, att, child, exc);193}194}195196/**197* Completes the accept by creating the AsynchronousSocketChannel for198* the given file descriptor and remote address. If this method completes199* with an IOException or SecurityException then the channel/file descriptor200* will be closed.201*/202private AsynchronousSocketChannel finishAccept(FileDescriptor newfd,203final InetSocketAddress remote,204AccessControlContext acc)205throws IOException, SecurityException206{207AsynchronousSocketChannel ch = null;208try {209ch = new UnixAsynchronousSocketChannelImpl(port, newfd, remote);210} catch (IOException x) {211nd.close(newfd);212throw x;213}214215// permission check must always be in initiator's context216try {217if (acc != null) {218AccessController.doPrivileged(new PrivilegedAction<Void>() {219public Void run() {220SecurityManager sm = System.getSecurityManager();221if (sm != null) {222sm.checkAccept(remote.getAddress().getHostAddress(),223remote.getPort());224}225return null;226}227}, acc);228} else {229SecurityManager sm = System.getSecurityManager();230if (sm != null) {231sm.checkAccept(remote.getAddress().getHostAddress(),232remote.getPort());233}234}235} catch (SecurityException x) {236try {237ch.close();238} catch (Throwable suppressed) {239x.addSuppressed(suppressed);240}241throw x;242}243return ch;244}245246@Override247Future<AsynchronousSocketChannel> implAccept(Object att,248CompletionHandler<AsynchronousSocketChannel,Object> handler)249{250// complete immediately if channel is closed251if (!isOpen()) {252Throwable e = new ClosedChannelException();253if (handler == null) {254return CompletedFuture.withFailure(e);255} else {256Invoker.invoke(this, handler, att, null, e);257return null;258}259}260if (localAddress == null)261throw new NotYetBoundException();262263// cancel was invoked with pending accept so connection may have been264// dropped.265if (isAcceptKilled())266throw new RuntimeException("Accept not allowed due cancellation");267268// check and set flag to prevent concurrent accepting269if (!accepting.compareAndSet(false, true))270throw new AcceptPendingException();271272// attempt accept273FileDescriptor newfd = new FileDescriptor();274InetSocketAddress[] isaa = new InetSocketAddress[1];275Throwable exc = null;276try {277begin();278279int n = accept(this.fd, newfd, isaa);280if (n == IOStatus.UNAVAILABLE) {281282// need calling context when there is security manager as283// permission check may be done in a different thread without284// any application call frames on the stack285PendingFuture<AsynchronousSocketChannel,Object> result = null;286synchronized (updateLock) {287if (handler == null) {288this.acceptHandler = null;289result = new PendingFuture<AsynchronousSocketChannel,Object>(this);290this.acceptFuture = result;291} else {292this.acceptHandler = handler;293this.acceptAttachment = att;294}295this.acceptAcc = (System.getSecurityManager() == null) ?296null : AccessController.getContext();297this.acceptPending = true;298}299300// register for connections301port.startPoll(fdVal, Net.POLLIN);302return result;303}304} catch (Throwable x) {305// accept failed306if (x instanceof ClosedChannelException)307x = new AsynchronousCloseException();308exc = x;309} finally {310end();311}312313AsynchronousSocketChannel child = null;314if (exc == null) {315// connection accepted immediately316try {317child = finishAccept(newfd, isaa[0], null);318} catch (Throwable x) {319exc = x;320}321}322323// re-enable accepting before invoking handler324enableAccept();325326if (handler == null) {327return CompletedFuture.withResult(child, exc);328} else {329Invoker.invokeIndirectly(this, handler, att, child, exc);330return null;331}332}333334/**335* Accept a connection on a socket.336*337* @implNote Wrap native call to allow instrumentation.338*/339private int accept(FileDescriptor ssfd, FileDescriptor newfd,340InetSocketAddress[] isaa)341throws IOException342{343return accept0(ssfd, newfd, isaa);344}345346// -- Native methods --347348private static native void initIDs();349350// Accepts a new connection, setting the given file descriptor to refer to351// the new socket and setting isaa[0] to the socket's remote address.352// Returns 1 on success, or IOStatus.UNAVAILABLE.353//354private native int accept0(FileDescriptor ssfd, FileDescriptor newfd,355InetSocketAddress[] isaa)356throws IOException;357358static {359IOUtil.load();360initIDs();361}362}363364365