Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java
32288 views
/*1* Copyright (c) 2008, 2018, 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.nio.ByteBuffer;29import java.net.*;30import java.util.concurrent.*;31import java.io.IOException;32import java.io.FileDescriptor;33import java.security.AccessController;34import sun.net.NetHooks;35import sun.security.action.GetPropertyAction;3637/**38* Unix implementation of AsynchronousSocketChannel39*/4041class UnixAsynchronousSocketChannelImpl42extends AsynchronousSocketChannelImpl implements Port.PollableChannel43{44private final static NativeDispatcher nd = new SocketDispatcher();45private static enum OpType { CONNECT, READ, WRITE };4647private static final boolean disableSynchronousRead;48static {49String propValue = AccessController.doPrivileged(50new GetPropertyAction("sun.nio.ch.disableSynchronousRead", "false"));51disableSynchronousRead = (propValue.length() == 0) ?52true : Boolean.valueOf(propValue);53}5455private final Port port;56private final int fdVal;5758// used to ensure that the context for I/O operations that complete59// ascynrhonously is visible to the pooled threads handling I/O events.60private final Object updateLock = new Object();6162// pending connect (updateLock)63private boolean connectPending;64private CompletionHandler<Void,Object> connectHandler;65private Object connectAttachment;66private PendingFuture<Void,Object> connectFuture;6768// pending remote address (stateLock)69private SocketAddress pendingRemote;7071// pending read (updateLock)72private boolean readPending;73private boolean isScatteringRead;74private ByteBuffer readBuffer;75private ByteBuffer[] readBuffers;76private CompletionHandler<Number,Object> readHandler;77private Object readAttachment;78private PendingFuture<Number,Object> readFuture;79private Future<?> readTimer;8081// pending write (updateLock)82private boolean writePending;83private boolean isGatheringWrite;84private ByteBuffer writeBuffer;85private ByteBuffer[] writeBuffers;86private CompletionHandler<Number,Object> writeHandler;87private Object writeAttachment;88private PendingFuture<Number,Object> writeFuture;89private Future<?> writeTimer;909192UnixAsynchronousSocketChannelImpl(Port port)93throws IOException94{95super(port);9697// set non-blocking98try {99IOUtil.configureBlocking(fd, false);100} catch (IOException x) {101nd.close(fd);102throw x;103}104105this.port = port;106this.fdVal = IOUtil.fdVal(fd);107108// add mapping from file descriptor to this channel109port.register(fdVal, this);110}111112// Constructor for sockets created by UnixAsynchronousServerSocketChannelImpl113UnixAsynchronousSocketChannelImpl(Port port,114FileDescriptor fd,115InetSocketAddress remote)116throws IOException117{118super(port, fd, remote);119120this.fdVal = IOUtil.fdVal(fd);121IOUtil.configureBlocking(fd, false);122123try {124port.register(fdVal, this);125} catch (ShutdownChannelGroupException x) {126// ShutdownChannelGroupException thrown if we attempt to register a127// new channel after the group is shutdown128throw new IOException(x);129}130131this.port = port;132}133134@Override135public AsynchronousChannelGroupImpl group() {136return port;137}138139// register events for outstanding I/O operations, caller already owns updateLock140private void updateEvents() {141assert Thread.holdsLock(updateLock);142int events = 0;143if (readPending)144events |= Net.POLLIN;145if (connectPending || writePending)146events |= Net.POLLOUT;147if (events != 0)148port.startPoll(fdVal, events);149}150151// register events for outstanding I/O operations152private void lockAndUpdateEvents() {153synchronized (updateLock) {154updateEvents();155}156}157158// invoke to finish read and/or write operations159private void finish(boolean mayInvokeDirect,160boolean readable,161boolean writable)162{163boolean finishRead = false;164boolean finishWrite = false;165boolean finishConnect = false;166167// map event to pending result168synchronized (updateLock) {169if (readable && this.readPending) {170this.readPending = false;171finishRead = true;172}173if (writable) {174if (this.writePending) {175this.writePending = false;176finishWrite = true;177} else if (this.connectPending) {178this.connectPending = false;179finishConnect = true;180}181}182}183184// complete the I/O operation. Special case for when channel is185// ready for both reading and writing. In that case, submit task to186// complete write if write operation has a completion handler.187if (finishRead) {188if (finishWrite)189finishWrite(false);190finishRead(mayInvokeDirect);191return;192}193if (finishWrite) {194finishWrite(mayInvokeDirect);195}196if (finishConnect) {197finishConnect(mayInvokeDirect);198}199}200201/**202* Invoked by event handler thread when file descriptor is polled203*/204@Override205public void onEvent(int events, boolean mayInvokeDirect) {206boolean readable = (events & Net.POLLIN) > 0;207boolean writable = (events & Net.POLLOUT) > 0;208if ((events & (Net.POLLERR | Net.POLLHUP)) > 0) {209readable = true;210writable = true;211}212finish(mayInvokeDirect, readable, writable);213}214215@Override216void implClose() throws IOException {217// remove the mapping218port.unregister(fdVal);219220// close file descriptor221nd.close(fd);222223// All outstanding I/O operations are required to fail224finish(false, true, true);225}226227@Override228public void onCancel(PendingFuture<?,?> task) {229if (task.getContext() == OpType.CONNECT)230killConnect();231if (task.getContext() == OpType.READ)232killReading();233if (task.getContext() == OpType.WRITE)234killWriting();235}236237// -- connect --238239private void setConnected() throws IOException {240synchronized (stateLock) {241state = ST_CONNECTED;242localAddress = Net.localAddress(fd);243remoteAddress = (InetSocketAddress)pendingRemote;244}245}246247private void finishConnect(boolean mayInvokeDirect) {248Throwable e = null;249try {250begin();251checkConnect(fdVal);252setConnected();253} catch (Throwable x) {254if (x instanceof ClosedChannelException)255x = new AsynchronousCloseException();256e = x;257} finally {258end();259}260if (e != null) {261// close channel if connection cannot be established262try {263close();264} catch (Throwable suppressed) {265e.addSuppressed(suppressed);266}267}268269// invoke handler and set result270CompletionHandler<Void,Object> handler = connectHandler;271connectHandler = null;272Object att = connectAttachment;273PendingFuture<Void,Object> future = connectFuture;274if (handler == null) {275future.setResult(null, e);276} else {277if (mayInvokeDirect) {278Invoker.invokeUnchecked(handler, att, null, e);279} else {280Invoker.invokeIndirectly(this, handler, att, null, e);281}282}283}284285@Override286@SuppressWarnings("unchecked")287<A> Future<Void> implConnect(SocketAddress remote,288A attachment,289CompletionHandler<Void,? super A> handler)290{291if (!isOpen()) {292Throwable e = new ClosedChannelException();293if (handler == null) {294return CompletedFuture.withFailure(e);295} else {296Invoker.invoke(this, handler, attachment, null, e);297return null;298}299}300301InetSocketAddress isa = Net.checkAddress(remote);302303// permission check304SecurityManager sm = System.getSecurityManager();305if (sm != null)306sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());307308// check and set state309boolean notifyBeforeTcpConnect;310synchronized (stateLock) {311if (state == ST_CONNECTED)312throw new AlreadyConnectedException();313if (state == ST_PENDING)314throw new ConnectionPendingException();315state = ST_PENDING;316pendingRemote = remote;317notifyBeforeTcpConnect = (localAddress == null);318}319320Throwable e = null;321try {322begin();323// notify hook if unbound324if (notifyBeforeTcpConnect)325NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort());326int n = Net.connect(fd, isa.getAddress(), isa.getPort());327if (n == IOStatus.UNAVAILABLE) {328// connection could not be established immediately329PendingFuture<Void,A> result = null;330synchronized (updateLock) {331if (handler == null) {332result = new PendingFuture<Void,A>(this, OpType.CONNECT);333this.connectFuture = (PendingFuture<Void,Object>)result;334} else {335this.connectHandler = (CompletionHandler<Void,Object>)handler;336this.connectAttachment = attachment;337}338this.connectPending = true;339updateEvents();340}341return result;342}343setConnected();344} catch (Throwable x) {345if (x instanceof ClosedChannelException)346x = new AsynchronousCloseException();347e = x;348} finally {349end();350}351352// close channel if connect fails353if (e != null) {354try {355close();356} catch (Throwable suppressed) {357e.addSuppressed(suppressed);358}359}360if (handler == null) {361return CompletedFuture.withResult(null, e);362} else {363Invoker.invoke(this, handler, attachment, null, e);364return null;365}366}367368// -- read --369370private void finishRead(boolean mayInvokeDirect) {371int n = -1;372Throwable exc = null;373374// copy fields as we can't access them after reading is re-enabled.375boolean scattering = isScatteringRead;376CompletionHandler<Number,Object> handler = readHandler;377Object att = readAttachment;378PendingFuture<Number,Object> future = readFuture;379Future<?> timeout = readTimer;380381try {382begin();383384if (scattering) {385n = (int)IOUtil.read(fd, readBuffers, nd);386} else {387n = IOUtil.read(fd, readBuffer, -1, nd);388}389if (n == IOStatus.UNAVAILABLE) {390// spurious wakeup, is this possible?391synchronized (updateLock) {392readPending = true;393}394return;395}396397// allow objects to be GC'ed.398this.readBuffer = null;399this.readBuffers = null;400this.readAttachment = null;401this.readHandler = null;402403// allow another read to be initiated404enableReading();405406} catch (Throwable x) {407enableReading();408if (x instanceof ClosedChannelException)409x = new AsynchronousCloseException();410exc = x;411} finally {412// restart poll in case of concurrent write413if (!(exc instanceof AsynchronousCloseException))414lockAndUpdateEvents();415end();416}417418// cancel the associated timer419if (timeout != null)420timeout.cancel(false);421422// create result423Number result = (exc != null) ? null : (scattering) ?424(Number)Long.valueOf(n) : (Number)Integer.valueOf(n);425426// invoke handler or set result427if (handler == null) {428future.setResult(result, exc);429} else {430if (mayInvokeDirect) {431Invoker.invokeUnchecked(handler, att, result, exc);432} else {433Invoker.invokeIndirectly(this, handler, att, result, exc);434}435}436}437438private Runnable readTimeoutTask = new Runnable() {439public void run() {440CompletionHandler<Number,Object> handler = null;441Object att = null;442PendingFuture<Number,Object> future = null;443444synchronized (updateLock) {445if (!readPending)446return;447readPending = false;448handler = readHandler;449att = readAttachment;450future = readFuture;451}452453// kill further reading before releasing waiters454enableReading(true);455456// invoke handler or set result457Exception exc = new InterruptedByTimeoutException();458if (handler == null) {459future.setFailure(exc);460} else {461AsynchronousChannel ch = UnixAsynchronousSocketChannelImpl.this;462Invoker.invokeIndirectly(ch, handler, att, null, exc);463}464}465};466467/**468* Initiates a read or scattering read operation469*/470@Override471@SuppressWarnings("unchecked")472<V extends Number,A> Future<V> implRead(boolean isScatteringRead,473ByteBuffer dst,474ByteBuffer[] dsts,475long timeout,476TimeUnit unit,477A attachment,478CompletionHandler<V,? super A> handler)479{480// A synchronous read is not attempted if disallowed by system property481// or, we are using a fixed thread pool and the completion handler may482// not be invoked directly (because the thread is not a pooled thread or483// there are too many handlers on the stack).484Invoker.GroupAndInvokeCount myGroupAndInvokeCount = null;485boolean invokeDirect = false;486boolean attemptRead = false;487if (!disableSynchronousRead) {488if (handler == null) {489attemptRead = true;490} else {491myGroupAndInvokeCount = Invoker.getGroupAndInvokeCount();492invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port);493// okay to attempt read with user thread pool494attemptRead = invokeDirect || !port.isFixedThreadPool();495}496}497498int n = IOStatus.UNAVAILABLE;499Throwable exc = null;500boolean pending = false;501502try {503begin();504505if (attemptRead) {506if (isScatteringRead) {507n = (int)IOUtil.read(fd, dsts, nd);508} else {509n = IOUtil.read(fd, dst, -1, nd);510}511}512513if (n == IOStatus.UNAVAILABLE) {514PendingFuture<V,A> result = null;515synchronized (updateLock) {516this.isScatteringRead = isScatteringRead;517this.readBuffer = dst;518this.readBuffers = dsts;519if (handler == null) {520this.readHandler = null;521result = new PendingFuture<V,A>(this, OpType.READ);522this.readFuture = (PendingFuture<Number,Object>)result;523this.readAttachment = null;524} else {525this.readHandler = (CompletionHandler<Number,Object>)handler;526this.readAttachment = attachment;527this.readFuture = null;528}529if (timeout > 0L) {530this.readTimer = port.schedule(readTimeoutTask, timeout, unit);531}532this.readPending = true;533updateEvents();534}535pending = true;536return result;537}538} catch (Throwable x) {539if (x instanceof ClosedChannelException)540x = new AsynchronousCloseException();541exc = x;542} finally {543if (!pending)544enableReading();545end();546}547548Number result = (exc != null) ? null : (isScatteringRead) ?549(Number)Long.valueOf(n) : (Number)Integer.valueOf(n);550551// read completed immediately552if (handler != null) {553if (invokeDirect) {554Invoker.invokeDirect(myGroupAndInvokeCount, handler, attachment, (V)result, exc);555} else {556Invoker.invokeIndirectly(this, handler, attachment, (V)result, exc);557}558return null;559} else {560return CompletedFuture.withResult((V)result, exc);561}562}563564// -- write --565566private void finishWrite(boolean mayInvokeDirect) {567int n = -1;568Throwable exc = null;569570// copy fields as we can't access them after reading is re-enabled.571boolean gathering = this.isGatheringWrite;572CompletionHandler<Number,Object> handler = this.writeHandler;573Object att = this.writeAttachment;574PendingFuture<Number,Object> future = this.writeFuture;575Future<?> timer = this.writeTimer;576577try {578begin();579580if (gathering) {581n = (int)IOUtil.write(fd, writeBuffers, nd);582} else {583n = IOUtil.write(fd, writeBuffer, -1, nd);584}585if (n == IOStatus.UNAVAILABLE) {586// spurious wakeup, is this possible?587synchronized (updateLock) {588writePending = true;589}590return;591}592593// allow objects to be GC'ed.594this.writeBuffer = null;595this.writeBuffers = null;596this.writeAttachment = null;597this.writeHandler = null;598599// allow another write to be initiated600enableWriting();601602} catch (Throwable x) {603enableWriting();604if (x instanceof ClosedChannelException)605x = new AsynchronousCloseException();606exc = x;607} finally {608// restart poll in case of concurrent write609if (!(exc instanceof AsynchronousCloseException))610lockAndUpdateEvents();611end();612}613614// cancel the associated timer615if (timer != null)616timer.cancel(false);617618// create result619Number result = (exc != null) ? null : (gathering) ?620(Number)Long.valueOf(n) : (Number)Integer.valueOf(n);621622// invoke handler or set result623if (handler == null) {624future.setResult(result, exc);625} else {626if (mayInvokeDirect) {627Invoker.invokeUnchecked(handler, att, result, exc);628} else {629Invoker.invokeIndirectly(this, handler, att, result, exc);630}631}632}633634private Runnable writeTimeoutTask = new Runnable() {635public void run() {636CompletionHandler<Number,Object> handler = null;637Object att = null;638PendingFuture<Number,Object> future = null;639640synchronized (updateLock) {641if (!writePending)642return;643writePending = false;644handler = writeHandler;645att = writeAttachment;646future = writeFuture;647}648649// kill further writing before releasing waiters650enableWriting(true);651652// invoke handler or set result653Exception exc = new InterruptedByTimeoutException();654if (handler != null) {655Invoker.invokeIndirectly(UnixAsynchronousSocketChannelImpl.this,656handler, att, null, exc);657} else {658future.setFailure(exc);659}660}661};662663/**664* Initiates a read or scattering read operation665*/666@Override667@SuppressWarnings("unchecked")668<V extends Number,A> Future<V> implWrite(boolean isGatheringWrite,669ByteBuffer src,670ByteBuffer[] srcs,671long timeout,672TimeUnit unit,673A attachment,674CompletionHandler<V,? super A> handler)675{676Invoker.GroupAndInvokeCount myGroupAndInvokeCount =677Invoker.getGroupAndInvokeCount();678boolean invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port);679boolean attemptWrite = (handler == null) || invokeDirect ||680!port.isFixedThreadPool(); // okay to attempt write with user thread pool681682int n = IOStatus.UNAVAILABLE;683Throwable exc = null;684boolean pending = false;685686try {687begin();688689if (attemptWrite) {690if (isGatheringWrite) {691n = (int)IOUtil.write(fd, srcs, nd);692} else {693n = IOUtil.write(fd, src, -1, nd);694}695}696697if (n == IOStatus.UNAVAILABLE) {698PendingFuture<V,A> result = null;699synchronized (updateLock) {700this.isGatheringWrite = isGatheringWrite;701this.writeBuffer = src;702this.writeBuffers = srcs;703if (handler == null) {704this.writeHandler = null;705result = new PendingFuture<V,A>(this, OpType.WRITE);706this.writeFuture = (PendingFuture<Number,Object>)result;707this.writeAttachment = null;708} else {709this.writeHandler = (CompletionHandler<Number,Object>)handler;710this.writeAttachment = attachment;711this.writeFuture = null;712}713if (timeout > 0L) {714this.writeTimer = port.schedule(writeTimeoutTask, timeout, unit);715}716this.writePending = true;717updateEvents();718}719pending = true;720return result;721}722} catch (Throwable x) {723if (x instanceof ClosedChannelException)724x = new AsynchronousCloseException();725exc = x;726} finally {727if (!pending)728enableWriting();729end();730}731732Number result = (exc != null) ? null : (isGatheringWrite) ?733(Number)Long.valueOf(n) : (Number)Integer.valueOf(n);734735// write completed immediately736if (handler != null) {737if (invokeDirect) {738Invoker.invokeDirect(myGroupAndInvokeCount, handler, attachment, (V)result, exc);739} else {740Invoker.invokeIndirectly(this, handler, attachment, (V)result, exc);741}742return null;743} else {744return CompletedFuture.withResult((V)result, exc);745}746}747748// -- Native methods --749750private static native void checkConnect(int fdVal) throws IOException;751752static {753IOUtil.load();754}755}756757758