8198562: (ch) Separate blocking and non-blocking code paths (part 1)
8198754: (ch) Separate blocking and non-blocking code paths (part 2) Reviewed-by: bpb
This commit is contained in:
parent
3918ed17a5
commit
13dd8888d2
@ -2080,8 +2080,8 @@ public final class System {
|
||||
E[] getEnumConstantsShared(Class<E> klass) {
|
||||
return klass.getEnumConstantsShared();
|
||||
}
|
||||
public void blockedOn(Thread t, Interruptible b) {
|
||||
t.blockedOn(b);
|
||||
public void blockedOn(Interruptible b) {
|
||||
Thread.blockedOn(b);
|
||||
}
|
||||
public void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook) {
|
||||
Shutdown.add(slot, registerShutdownInProgress, hook);
|
||||
|
@ -231,9 +231,10 @@ class Thread implements Runnable {
|
||||
/* Set the blocker field; invoked via jdk.internal.misc.SharedSecrets
|
||||
* from java.nio code
|
||||
*/
|
||||
void blockedOn(Interruptible b) {
|
||||
synchronized (blockerLock) {
|
||||
blocker = b;
|
||||
static void blockedOn(Interruptible b) {
|
||||
Thread me = Thread.currentThread();
|
||||
synchronized (me.blockerLock) {
|
||||
me.blocker = b;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1006,18 +1007,22 @@ class Thread implements Runnable {
|
||||
* @spec JSR-51
|
||||
*/
|
||||
public void interrupt() {
|
||||
if (this != Thread.currentThread())
|
||||
Thread me = Thread.currentThread();
|
||||
if (this != me)
|
||||
checkAccess();
|
||||
|
||||
synchronized (blockerLock) {
|
||||
Interruptible b = blocker;
|
||||
if (b != null) {
|
||||
interrupt0(); // Just to set the interrupt flag
|
||||
b.interrupt(this);
|
||||
return;
|
||||
// set interrupt status
|
||||
interrupt0();
|
||||
|
||||
// thread may be blocked in an I/O operation
|
||||
if (this != me && blocker != null) {
|
||||
synchronized (blockerLock) {
|
||||
Interruptible b = blocker;
|
||||
if (b != null) {
|
||||
b.interrupt(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
interrupt0();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -205,6 +205,6 @@ public abstract class AbstractInterruptibleChannel
|
||||
|
||||
// -- jdk.internal.misc.SharedSecrets --
|
||||
static void blockedOn(Interruptible intr) { // package-private
|
||||
SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), intr);
|
||||
SharedSecrets.getJavaLangAccess().blockedOn(intr);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -100,9 +100,9 @@ public interface JavaLangAccess {
|
||||
<E extends Enum<E>> E[] getEnumConstantsShared(Class<E> klass);
|
||||
|
||||
/**
|
||||
* Set thread's blocker field.
|
||||
* Set current thread's blocker field.
|
||||
*/
|
||||
void blockedOn(Thread t, Interruptible b);
|
||||
void blockedOn(Interruptible b);
|
||||
|
||||
/**
|
||||
* Registers a shutdown hook.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -41,6 +41,7 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.nio.channels.IllegalBlockingModeException;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
// Make a datagram-socket channel look like a datagram socket.
|
||||
@ -53,7 +54,6 @@ import java.nio.channels.IllegalBlockingModeException;
|
||||
public class DatagramSocketAdaptor
|
||||
extends DatagramSocket
|
||||
{
|
||||
|
||||
// The channel being adapted
|
||||
private final DatagramChannelImpl dc;
|
||||
|
||||
@ -63,7 +63,7 @@ public class DatagramSocketAdaptor
|
||||
// ## super will create a useless impl
|
||||
private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException {
|
||||
// Invoke the DatagramSocketAdaptor(SocketAddress) constructor,
|
||||
// passing a dummy DatagramSocketImpl object to aovid any native
|
||||
// passing a dummy DatagramSocketImpl object to avoid any native
|
||||
// resource allocation in super class and invoking our bind method
|
||||
// before the dc field is initialized.
|
||||
super(dummyDatagramSocket);
|
||||
@ -87,10 +87,10 @@ public class DatagramSocketAdaptor
|
||||
throw new IllegalArgumentException("connect: " + port);
|
||||
if (remote == null)
|
||||
throw new IllegalArgumentException("connect: null address");
|
||||
if (isClosed())
|
||||
return;
|
||||
try {
|
||||
dc.connect(remote);
|
||||
} catch (ClosedChannelException e) {
|
||||
// ignore
|
||||
} catch (Exception x) {
|
||||
Net.translateToSocketException(x);
|
||||
}
|
||||
@ -115,8 +115,7 @@ public class DatagramSocketAdaptor
|
||||
}
|
||||
|
||||
public void connect(SocketAddress remote) throws SocketException {
|
||||
if (remote == null)
|
||||
throw new IllegalArgumentException("Address can't be null");
|
||||
Objects.requireNonNull(remote, "Address can't be null");
|
||||
connectInternal(remote);
|
||||
}
|
||||
|
||||
@ -137,15 +136,13 @@ public class DatagramSocketAdaptor
|
||||
}
|
||||
|
||||
public InetAddress getInetAddress() {
|
||||
return (isConnected()
|
||||
? Net.asInetSocketAddress(dc.remoteAddress()).getAddress()
|
||||
: null);
|
||||
InetSocketAddress remote = dc.remoteAddress();
|
||||
return (remote != null) ? remote.getAddress() : null;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return (isConnected()
|
||||
? Net.asInetSocketAddress(dc.remoteAddress()).getPort()
|
||||
: -1);
|
||||
InetSocketAddress remote = dc.remoteAddress();
|
||||
return (remote != null) ? remote.getPort() : -1;
|
||||
}
|
||||
|
||||
public void send(DatagramPacket p) throws IOException {
|
||||
@ -161,8 +158,7 @@ public class DatagramSocketAdaptor
|
||||
if (p.getAddress() == null) {
|
||||
// Legacy DatagramSocket will send in this case
|
||||
// and set address and port of the packet
|
||||
InetSocketAddress isa = (InetSocketAddress)
|
||||
dc.remoteAddress();
|
||||
InetSocketAddress isa = dc.remoteAddress();
|
||||
p.setPort(isa.getPort());
|
||||
p.setAddress(isa.getAddress());
|
||||
dc.write(bb);
|
||||
@ -181,36 +177,24 @@ public class DatagramSocketAdaptor
|
||||
}
|
||||
}
|
||||
|
||||
// Must hold dc.blockingLock()
|
||||
//
|
||||
private SocketAddress receive(ByteBuffer bb) throws IOException {
|
||||
if (timeout == 0) {
|
||||
return dc.receive(bb);
|
||||
}
|
||||
assert Thread.holdsLock(dc.blockingLock()) && dc.isBlocking();
|
||||
|
||||
dc.configureBlocking(false);
|
||||
try {
|
||||
SocketAddress sender;
|
||||
if ((sender = dc.receive(bb)) != null)
|
||||
return sender;
|
||||
long to = timeout;
|
||||
long to = this.timeout;
|
||||
if (to == 0) {
|
||||
return dc.receive(bb);
|
||||
} else {
|
||||
for (;;) {
|
||||
if (!dc.isOpen())
|
||||
throw new ClosedChannelException();
|
||||
throw new ClosedChannelException();
|
||||
long st = System.currentTimeMillis();
|
||||
int result = dc.poll(Net.POLLIN, to);
|
||||
if (result > 0 && ((result & Net.POLLIN) != 0)) {
|
||||
if ((sender = dc.receive(bb)) != null)
|
||||
return sender;
|
||||
if (dc.pollRead(to)) {
|
||||
return dc.receive(bb);
|
||||
}
|
||||
to -= System.currentTimeMillis() - st;
|
||||
if (to <= 0)
|
||||
throw new SocketTimeoutException();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
dc.configureBlocking(true);
|
||||
} catch (ClosedChannelException e) { }
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,10 +220,10 @@ public class DatagramSocketAdaptor
|
||||
public InetAddress getLocalAddress() {
|
||||
if (isClosed())
|
||||
return null;
|
||||
SocketAddress local = dc.localAddress();
|
||||
InetSocketAddress local = dc.localAddress();
|
||||
if (local == null)
|
||||
local = new InetSocketAddress(0);
|
||||
InetAddress result = ((InetSocketAddress)local).getAddress();
|
||||
InetAddress result = local.getAddress();
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
try {
|
||||
@ -255,9 +239,9 @@ public class DatagramSocketAdaptor
|
||||
if (isClosed())
|
||||
return -1;
|
||||
try {
|
||||
SocketAddress local = dc.getLocalAddress();
|
||||
InetSocketAddress local = dc.localAddress();
|
||||
if (local != null) {
|
||||
return ((InetSocketAddress)local).getPort();
|
||||
return local.getPort();
|
||||
}
|
||||
} catch (Exception x) {
|
||||
}
|
||||
|
@ -55,8 +55,7 @@ public class IOUtil {
|
||||
throws IOException
|
||||
{
|
||||
if (src instanceof DirectBuffer) {
|
||||
return writeFromNativeBuffer(fd, src, position,
|
||||
directIO, alignment, nd);
|
||||
return writeFromNativeBuffer(fd, src, position, directIO, alignment, nd);
|
||||
}
|
||||
|
||||
// Substitute a native buffer
|
||||
@ -77,8 +76,7 @@ public class IOUtil {
|
||||
// Do not update src until we see how many bytes were written
|
||||
src.position(pos);
|
||||
|
||||
int n = writeFromNativeBuffer(fd, bb, position,
|
||||
directIO, alignment, nd);
|
||||
int n = writeFromNativeBuffer(fd, bb, position, directIO, alignment, nd);
|
||||
if (n > 0) {
|
||||
// now update src
|
||||
src.position(pos + n);
|
||||
@ -232,8 +230,7 @@ public class IOUtil {
|
||||
if (dst.isReadOnly())
|
||||
throw new IllegalArgumentException("Read-only buffer");
|
||||
if (dst instanceof DirectBuffer)
|
||||
return readIntoNativeBuffer(fd, dst, position,
|
||||
directIO, alignment, nd);
|
||||
return readIntoNativeBuffer(fd, dst, position, directIO, alignment, nd);
|
||||
|
||||
// Substitute a native buffer
|
||||
ByteBuffer bb;
|
||||
@ -245,8 +242,7 @@ public class IOUtil {
|
||||
bb = Util.getTemporaryDirectBuffer(rem);
|
||||
}
|
||||
try {
|
||||
int n = readIntoNativeBuffer(fd, bb, position,
|
||||
directIO, alignment,nd);
|
||||
int n = readIntoNativeBuffer(fd, bb, position, directIO, alignment,nd);
|
||||
bb.flip();
|
||||
if (n > 0)
|
||||
dst.put(bb);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,10 +25,11 @@
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.nio.channels.*;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.MembershipKey;
|
||||
import java.nio.channels.MulticastChannel;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
@ -46,7 +47,7 @@ class MembershipKeyImpl
|
||||
private volatile boolean invalid;
|
||||
|
||||
// lock used when creating or accessing blockedSet
|
||||
private Object stateLock = new Object();
|
||||
private final Object stateLock = new Object();
|
||||
|
||||
// set of source addresses that are blocked
|
||||
private HashSet<InetAddress> blockedSet;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,12 +25,30 @@
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.ProtocolFamily;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketOption;
|
||||
import java.net.StandardProtocolFamily;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.channels.AlreadyBoundException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.NotYetBoundException;
|
||||
import java.nio.channels.NotYetConnectedException;
|
||||
import java.nio.channels.UnresolvedAddressException;
|
||||
import java.nio.channels.UnsupportedAddressTypeException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import sun.net.ext.ExtendedSocketOptions;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
@ -116,6 +134,16 @@ public class Net {
|
||||
return isa;
|
||||
}
|
||||
|
||||
static InetSocketAddress checkAddress(SocketAddress sa, ProtocolFamily family) {
|
||||
InetSocketAddress isa = checkAddress(sa);
|
||||
if (family == StandardProtocolFamily.INET) {
|
||||
InetAddress addr = isa.getAddress();
|
||||
if (!(addr instanceof Inet4Address))
|
||||
throw new UnsupportedAddressTypeException();
|
||||
}
|
||||
return isa;
|
||||
}
|
||||
|
||||
static InetSocketAddress asInetSocketAddress(SocketAddress sa) {
|
||||
if (!(sa instanceof InetSocketAddress))
|
||||
throw new UnsupportedAddressTypeException();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,7 +29,6 @@ import java.nio.channels.Channel;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* An interface that allows translation (and more!).
|
||||
*
|
||||
@ -50,7 +49,7 @@ public interface SelChImpl extends Channel {
|
||||
* contains at least one bit that the previous value did not
|
||||
* contain
|
||||
*/
|
||||
public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk);
|
||||
boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk);
|
||||
|
||||
/**
|
||||
* Sets the specified ops if present in interestOps. The specified
|
||||
@ -60,7 +59,7 @@ public interface SelChImpl extends Channel {
|
||||
* contains at least one bit that the previous value did not
|
||||
* contain
|
||||
*/
|
||||
public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk);
|
||||
boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk);
|
||||
|
||||
void translateAndSetInterestOps(int ops, SelectionKeyImpl sk);
|
||||
|
||||
|
@ -34,7 +34,6 @@ import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.IllegalBlockingModeException;
|
||||
import java.nio.channels.NotYetBoundException;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
@ -51,7 +50,6 @@ import java.nio.channels.SocketChannel;
|
||||
class ServerSocketAdaptor // package-private
|
||||
extends ServerSocket
|
||||
{
|
||||
|
||||
// The channel being adapted
|
||||
private final ServerSocketChannelImpl ssc;
|
||||
|
||||
@ -67,13 +65,10 @@ class ServerSocketAdaptor // package-private
|
||||
}
|
||||
|
||||
// ## super will create a useless impl
|
||||
private ServerSocketAdaptor(ServerSocketChannelImpl ssc)
|
||||
throws IOException
|
||||
{
|
||||
private ServerSocketAdaptor(ServerSocketChannelImpl ssc) throws IOException {
|
||||
this.ssc = ssc;
|
||||
}
|
||||
|
||||
|
||||
public void bind(SocketAddress local) throws IOException {
|
||||
bind(local, 50);
|
||||
}
|
||||
@ -89,26 +84,31 @@ class ServerSocketAdaptor // package-private
|
||||
}
|
||||
|
||||
public InetAddress getInetAddress() {
|
||||
if (!ssc.isBound())
|
||||
InetSocketAddress local = ssc.localAddress();
|
||||
if (local == null) {
|
||||
return null;
|
||||
return Net.getRevealedLocalAddress(ssc.localAddress()).getAddress();
|
||||
|
||||
} else {
|
||||
return Net.getRevealedLocalAddress(local).getAddress();
|
||||
}
|
||||
}
|
||||
|
||||
public int getLocalPort() {
|
||||
if (!ssc.isBound())
|
||||
InetSocketAddress local = ssc.localAddress();
|
||||
if (local == null) {
|
||||
return -1;
|
||||
return Net.asInetSocketAddress(ssc.localAddress()).getPort();
|
||||
} else {
|
||||
return local.getPort();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Socket accept() throws IOException {
|
||||
synchronized (ssc.blockingLock()) {
|
||||
try {
|
||||
if (!ssc.isBound())
|
||||
throw new NotYetBoundException();
|
||||
|
||||
if (timeout == 0) {
|
||||
long to = this.timeout;
|
||||
if (to == 0) {
|
||||
// for compatibility reasons: accept connection if available
|
||||
// when configured non-blocking
|
||||
SocketChannel sc = ssc.accept();
|
||||
@ -119,28 +119,15 @@ class ServerSocketAdaptor // package-private
|
||||
|
||||
if (!ssc.isBlocking())
|
||||
throw new IllegalBlockingModeException();
|
||||
ssc.configureBlocking(false);
|
||||
try {
|
||||
SocketChannel sc;
|
||||
if ((sc = ssc.accept()) != null)
|
||||
return sc.socket();
|
||||
long to = timeout;
|
||||
for (;;) {
|
||||
if (!ssc.isOpen())
|
||||
throw new ClosedChannelException();
|
||||
long st = System.currentTimeMillis();
|
||||
int result = ssc.poll(Net.POLLIN, to);
|
||||
if (result > 0 && ((sc = ssc.accept()) != null))
|
||||
return sc.socket();
|
||||
to -= System.currentTimeMillis() - st;
|
||||
if (to <= 0)
|
||||
throw new SocketTimeoutException();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
ssc.configureBlocking(true);
|
||||
} catch (ClosedChannelException e) { }
|
||||
for (;;) {
|
||||
long st = System.currentTimeMillis();
|
||||
if (ssc.pollAccept(to))
|
||||
return ssc.accept().socket();
|
||||
to -= System.currentTimeMillis() - st;
|
||||
if (to <= 0)
|
||||
throw new SocketTimeoutException();
|
||||
}
|
||||
|
||||
} catch (Exception x) {
|
||||
Net.translateException(x);
|
||||
assert false;
|
||||
@ -216,5 +203,4 @@ class ServerSocketAdaptor // package-private
|
||||
return -1; // Never happens
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import java.net.SocketOption;
|
||||
import java.net.StandardProtocolFamily;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.nio.channels.AlreadyBoundException;
|
||||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.NotYetBoundException;
|
||||
import java.nio.channels.SelectionKey;
|
||||
@ -43,6 +44,7 @@ import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@ -56,7 +58,6 @@ class ServerSocketChannelImpl
|
||||
extends ServerSocketChannel
|
||||
implements SelChImpl
|
||||
{
|
||||
|
||||
// Used to make native close and configure calls
|
||||
private static NativeDispatcher nd;
|
||||
|
||||
@ -64,10 +65,7 @@ class ServerSocketChannelImpl
|
||||
private final FileDescriptor fd;
|
||||
private final int fdVal;
|
||||
|
||||
// ID of native thread currently blocked in this channel, for signalling
|
||||
private volatile long thread;
|
||||
|
||||
// Lock held by thread currently blocked in this channel
|
||||
// Lock held by thread currently blocked on this channel
|
||||
private final ReentrantLock acceptLock = new ReentrantLock();
|
||||
|
||||
// Lock held by any thread that modifies the state fields declared below
|
||||
@ -77,10 +75,14 @@ class ServerSocketChannelImpl
|
||||
// -- The following fields are protected by stateLock
|
||||
|
||||
// Channel state, increases monotonically
|
||||
private static final int ST_UNINITIALIZED = -1;
|
||||
private static final int ST_INUSE = 0;
|
||||
private static final int ST_KILLED = 1;
|
||||
private int state = ST_UNINITIALIZED;
|
||||
private static final int ST_CLOSING = 1;
|
||||
private static final int ST_KILLPENDING = 2;
|
||||
private static final int ST_KILLED = 3;
|
||||
private int state;
|
||||
|
||||
// ID of native thread currently blocked in this channel, for signalling
|
||||
private long thread;
|
||||
|
||||
// Binding
|
||||
private InetSocketAddress localAddress; // null => unbound
|
||||
@ -98,22 +100,28 @@ class ServerSocketChannelImpl
|
||||
super(sp);
|
||||
this.fd = Net.serverSocket(true);
|
||||
this.fdVal = IOUtil.fdVal(fd);
|
||||
this.state = ST_INUSE;
|
||||
}
|
||||
|
||||
ServerSocketChannelImpl(SelectorProvider sp,
|
||||
FileDescriptor fd,
|
||||
boolean bound)
|
||||
ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
|
||||
throws IOException
|
||||
{
|
||||
super(sp);
|
||||
this.fd = fd;
|
||||
this.fdVal = IOUtil.fdVal(fd);
|
||||
this.state = ST_INUSE;
|
||||
if (bound)
|
||||
localAddress = Net.localAddress(fd);
|
||||
if (bound) {
|
||||
synchronized (stateLock) {
|
||||
localAddress = Net.localAddress(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @throws ClosedChannelException if channel is closed
|
||||
private void ensureOpen() throws ClosedChannelException {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerSocket socket() {
|
||||
synchronized (stateLock) {
|
||||
if (socket == null)
|
||||
@ -125,11 +133,10 @@ class ServerSocketChannelImpl
|
||||
@Override
|
||||
public SocketAddress getLocalAddress() throws IOException {
|
||||
synchronized (stateLock) {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
return localAddress == null ? localAddress
|
||||
: Net.getRevealedLocalAddress(
|
||||
Net.asInetSocketAddress(localAddress));
|
||||
ensureOpen();
|
||||
return (localAddress == null)
|
||||
? null
|
||||
: Net.getRevealedLocalAddress(localAddress);
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,13 +144,11 @@ class ServerSocketChannelImpl
|
||||
public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
|
||||
throws IOException
|
||||
{
|
||||
if (name == null)
|
||||
throw new NullPointerException();
|
||||
Objects.requireNonNull(name);
|
||||
if (!supportedOptions().contains(name))
|
||||
throw new UnsupportedOperationException("'" + name + "' not supported");
|
||||
synchronized (stateLock) {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
ensureOpen();
|
||||
|
||||
if (name == StandardSocketOptions.IP_TOS) {
|
||||
ProtocolFamily family = Net.isIPv6Available() ?
|
||||
@ -152,9 +157,7 @@ class ServerSocketChannelImpl
|
||||
return this;
|
||||
}
|
||||
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR &&
|
||||
Net.useExclusiveBind())
|
||||
{
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
|
||||
// SO_REUSEADDR emulated when using exclusive bind
|
||||
isReuseAddress = (Boolean)value;
|
||||
} else {
|
||||
@ -170,17 +173,13 @@ class ServerSocketChannelImpl
|
||||
public <T> T getOption(SocketOption<T> name)
|
||||
throws IOException
|
||||
{
|
||||
if (name == null)
|
||||
throw new NullPointerException();
|
||||
Objects.requireNonNull(name);
|
||||
if (!supportedOptions().contains(name))
|
||||
throw new UnsupportedOperationException("'" + name + "' not supported");
|
||||
|
||||
synchronized (stateLock) {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR &&
|
||||
Net.useExclusiveBind())
|
||||
{
|
||||
ensureOpen();
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
|
||||
// SO_REUSEADDR emulated when using exclusive bind
|
||||
return (T)Boolean.valueOf(isReuseAddress);
|
||||
}
|
||||
@ -193,7 +192,7 @@ class ServerSocketChannelImpl
|
||||
static final Set<SocketOption<?>> defaultOptions = defaultOptions();
|
||||
|
||||
private static Set<SocketOption<?>> defaultOptions() {
|
||||
HashSet<SocketOption<?>> set = new HashSet<>(2);
|
||||
HashSet<SocketOption<?>> set = new HashSet<>();
|
||||
set.add(StandardSocketOptions.SO_RCVBUF);
|
||||
set.add(StandardSocketOptions.SO_REUSEADDR);
|
||||
if (Net.isReusePortAvailable()) {
|
||||
@ -209,35 +208,23 @@ class ServerSocketChannelImpl
|
||||
return DefaultOptionsHolder.defaultOptions;
|
||||
}
|
||||
|
||||
public boolean isBound() {
|
||||
synchronized (stateLock) {
|
||||
return localAddress != null;
|
||||
}
|
||||
}
|
||||
|
||||
public InetSocketAddress localAddress() {
|
||||
synchronized (stateLock) {
|
||||
return localAddress;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
|
||||
acceptLock.lock();
|
||||
try {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
if (isBound())
|
||||
throw new AlreadyBoundException();
|
||||
InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) :
|
||||
Net.checkAddress(local);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkListen(isa.getPort());
|
||||
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.bind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.listen(fd, backlog < 1 ? 50 : backlog);
|
||||
synchronized (stateLock) {
|
||||
ensureOpen();
|
||||
if (localAddress != null)
|
||||
throw new AlreadyBoundException();
|
||||
InetSocketAddress isa = (local == null)
|
||||
? new InetSocketAddress(0)
|
||||
: Net.checkAddress(local);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkListen(isa.getPort());
|
||||
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.bind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.listen(fd, backlog < 1 ? 50 : backlog);
|
||||
localAddress = Net.localAddress(fd);
|
||||
}
|
||||
} finally {
|
||||
@ -246,47 +233,78 @@ class ServerSocketChannelImpl
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the beginning of an I/O operation that might block.
|
||||
*
|
||||
* @throws ClosedChannelException if the channel is closed
|
||||
* @throws NotYetBoundException if the channel's socket has not been bound yet
|
||||
*/
|
||||
private void begin(boolean blocking) throws ClosedChannelException {
|
||||
if (blocking)
|
||||
begin(); // set blocker to close channel if interrupted
|
||||
synchronized (stateLock) {
|
||||
ensureOpen();
|
||||
if (localAddress == null)
|
||||
throw new NotYetBoundException();
|
||||
if (blocking)
|
||||
thread = NativeThread.current();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the end of an I/O operation that may have blocked.
|
||||
*
|
||||
* @throws AsynchronousCloseException if the channel was closed due to this
|
||||
* thread being interrupted on a blocking I/O operation.
|
||||
*/
|
||||
private void end(boolean blocking, boolean completed)
|
||||
throws AsynchronousCloseException
|
||||
{
|
||||
if (blocking) {
|
||||
synchronized (stateLock) {
|
||||
thread = 0;
|
||||
// notify any thread waiting in implCloseSelectableChannel
|
||||
if (state == ST_CLOSING) {
|
||||
stateLock.notifyAll();
|
||||
}
|
||||
}
|
||||
end(completed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketChannel accept() throws IOException {
|
||||
acceptLock.lock();
|
||||
try {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
if (!isBound())
|
||||
throw new NotYetBoundException();
|
||||
SocketChannel sc = null;
|
||||
|
||||
int n = 0;
|
||||
FileDescriptor newfd = new FileDescriptor();
|
||||
InetSocketAddress[] isaa = new InetSocketAddress[1];
|
||||
|
||||
boolean blocking = isBlocking();
|
||||
try {
|
||||
begin();
|
||||
if (!isOpen())
|
||||
return null;
|
||||
thread = NativeThread.current();
|
||||
for (;;) {
|
||||
begin(blocking);
|
||||
do {
|
||||
n = accept(this.fd, newfd, isaa);
|
||||
if ((n == IOStatus.INTERRUPTED) && isOpen())
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
} while (n == IOStatus.INTERRUPTED && isOpen());
|
||||
} finally {
|
||||
thread = 0;
|
||||
end(n > 0);
|
||||
end(blocking, n > 0);
|
||||
assert IOStatus.check(n);
|
||||
}
|
||||
|
||||
if (n < 1)
|
||||
return null;
|
||||
|
||||
// newly accepted socket is initially in blocking mode
|
||||
IOUtil.configureBlocking(newfd, true);
|
||||
|
||||
InetSocketAddress isa = isaa[0];
|
||||
sc = new SocketChannelImpl(provider(), newfd, isa);
|
||||
SocketChannel sc = new SocketChannelImpl(provider(), newfd, isa);
|
||||
|
||||
// check permitted to accept connections from the remote address
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
try {
|
||||
sm.checkAccept(isa.getAddress().getHostAddress(),
|
||||
isa.getPort());
|
||||
sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
|
||||
} catch (SecurityException x) {
|
||||
sc.close();
|
||||
throw x;
|
||||
@ -299,33 +317,133 @@ class ServerSocketChannelImpl
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implConfigureBlocking(boolean block) throws IOException {
|
||||
IOUtil.configureBlocking(fd, block);
|
||||
}
|
||||
|
||||
protected void implCloseSelectableChannel() throws IOException {
|
||||
synchronized (stateLock) {
|
||||
if (state != ST_KILLED)
|
||||
nd.preClose(fd);
|
||||
long th = thread;
|
||||
if (th != 0)
|
||||
NativeThread.signal(th);
|
||||
if (!isRegistered())
|
||||
kill();
|
||||
acceptLock.lock();
|
||||
try {
|
||||
synchronized (stateLock) {
|
||||
ensureOpen();
|
||||
IOUtil.configureBlocking(fd, block);
|
||||
}
|
||||
} finally {
|
||||
acceptLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by implCloseChannel to close the channel.
|
||||
*
|
||||
* This method waits for outstanding I/O operations to complete. When in
|
||||
* blocking mode, the socket is pre-closed and the threads in blocking I/O
|
||||
* operations are signalled to ensure that the outstanding I/O operations
|
||||
* complete quickly.
|
||||
*
|
||||
* The socket is closed by this method when it is not registered with a
|
||||
* Selector. Note that a channel configured blocking may be registered with
|
||||
* a Selector. This arises when a key is canceled and the channel configured
|
||||
* to blocking mode before the key is flushed from the Selector.
|
||||
*/
|
||||
@Override
|
||||
protected void implCloseSelectableChannel() throws IOException {
|
||||
assert !isOpen();
|
||||
|
||||
boolean interrupted = false;
|
||||
boolean blocking;
|
||||
|
||||
// set state to ST_CLOSING
|
||||
synchronized (stateLock) {
|
||||
assert state < ST_CLOSING;
|
||||
state = ST_CLOSING;
|
||||
blocking = isBlocking();
|
||||
}
|
||||
|
||||
// wait for any outstanding accept to complete
|
||||
if (blocking) {
|
||||
synchronized (stateLock) {
|
||||
assert state == ST_CLOSING;
|
||||
long th = thread;
|
||||
if (th != 0) {
|
||||
nd.preClose(fd);
|
||||
NativeThread.signal(th);
|
||||
|
||||
// wait for accept operation to end
|
||||
while (thread != 0) {
|
||||
try {
|
||||
stateLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
interrupted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// non-blocking mode: wait for accept to complete
|
||||
acceptLock.lock();
|
||||
acceptLock.unlock();
|
||||
}
|
||||
|
||||
// set state to ST_KILLPENDING
|
||||
synchronized (stateLock) {
|
||||
assert state == ST_CLOSING;
|
||||
state = ST_KILLPENDING;
|
||||
}
|
||||
|
||||
// close socket if not registered with Selector
|
||||
if (!isRegistered())
|
||||
kill();
|
||||
|
||||
// restore interrupt status
|
||||
if (interrupted)
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void kill() throws IOException {
|
||||
synchronized (stateLock) {
|
||||
if (state == ST_KILLED)
|
||||
return;
|
||||
if (state == ST_UNINITIALIZED) {
|
||||
if (state == ST_KILLPENDING) {
|
||||
state = ST_KILLED;
|
||||
return;
|
||||
nd.close(fd);
|
||||
}
|
||||
assert !isOpen() && !isRegistered();
|
||||
nd.close(fd);
|
||||
state = ST_KILLED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if channel's socket is bound
|
||||
*/
|
||||
boolean isBound() {
|
||||
synchronized (stateLock) {
|
||||
return localAddress != null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the local address, or null if not bound
|
||||
*/
|
||||
InetSocketAddress localAddress() {
|
||||
synchronized (stateLock) {
|
||||
return localAddress;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll this channel's socket for a new connection up to the given timeout.
|
||||
* @return {@code true} if there is a connection to accept
|
||||
*/
|
||||
boolean pollAccept(long timeout) throws IOException {
|
||||
assert Thread.holdsLock(blockingLock()) && isBlocking();
|
||||
acceptLock.lock();
|
||||
try {
|
||||
boolean polled = false;
|
||||
try {
|
||||
begin(true);
|
||||
int n = Net.poll(fd, Net.POLLIN, timeout);
|
||||
polled = (n > 0);
|
||||
} finally {
|
||||
end(true, polled);
|
||||
}
|
||||
return polled;
|
||||
} finally {
|
||||
acceptLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,31 +485,6 @@ class ServerSocketChannelImpl
|
||||
return translateReadyOps(ops, 0, sk);
|
||||
}
|
||||
|
||||
// package-private
|
||||
int poll(int events, long timeout) throws IOException {
|
||||
assert Thread.holdsLock(blockingLock()) && !isBlocking();
|
||||
|
||||
acceptLock.lock();
|
||||
try {
|
||||
int n = 0;
|
||||
try {
|
||||
begin();
|
||||
synchronized (stateLock) {
|
||||
if (!isOpen())
|
||||
return 0;
|
||||
thread = NativeThread.current();
|
||||
}
|
||||
n = Net.poll(fd, events, timeout);
|
||||
} finally {
|
||||
thread = 0;
|
||||
end(n > 0);
|
||||
}
|
||||
return n;
|
||||
} finally {
|
||||
acceptLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates an interest operation set into a native poll event set
|
||||
*/
|
||||
@ -421,7 +514,7 @@ class ServerSocketChannelImpl
|
||||
sb.append("closed");
|
||||
} else {
|
||||
synchronized (stateLock) {
|
||||
InetSocketAddress addr = localAddress();
|
||||
InetSocketAddress addr = localAddress;
|
||||
if (addr == null) {
|
||||
sb.append("unbound");
|
||||
} else {
|
||||
@ -438,7 +531,8 @@ class ServerSocketChannelImpl
|
||||
*
|
||||
* @implNote Wrap native call to allow instrumentation.
|
||||
*/
|
||||
private int accept(FileDescriptor ssfd, FileDescriptor newfd,
|
||||
private int accept(FileDescriptor ssfd,
|
||||
FileDescriptor newfd,
|
||||
InetSocketAddress[] isaa)
|
||||
throws IOException
|
||||
{
|
||||
@ -452,7 +546,8 @@ class ServerSocketChannelImpl
|
||||
// Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no
|
||||
// connections are pending) or IOStatus.INTERRUPTED.
|
||||
//
|
||||
private native int accept0(FileDescriptor ssfd, FileDescriptor newfd,
|
||||
private native int accept0(FileDescriptor ssfd,
|
||||
FileDescriptor newfd,
|
||||
InetSocketAddress[] isaa)
|
||||
throws IOException;
|
||||
|
||||
|
@ -44,16 +44,10 @@ import java.nio.channels.IllegalBlockingModeException;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import static java.util.concurrent.TimeUnit.*;
|
||||
|
||||
// Make a socket channel look like a socket.
|
||||
//
|
||||
// The only aspects of java.net.Socket-hood that we don't attempt to emulate
|
||||
// here are the interrupted-I/O exceptions (which our Solaris implementations
|
||||
// attempt to support) and the sending of urgent data. Otherwise an adapted
|
||||
// socket should look enough like a real java.net.Socket to fool most of the
|
||||
// developers most of the time, right down to the exception message strings.
|
||||
//
|
||||
// The methods in this class are defined in exactly the same order as in
|
||||
// java.net.Socket so as to simplify tracking future changes to that class.
|
||||
//
|
||||
@ -61,7 +55,6 @@ import java.util.concurrent.TimeUnit;
|
||||
class SocketAdaptor
|
||||
extends Socket
|
||||
{
|
||||
|
||||
// The channel being adapted
|
||||
private final SocketChannelImpl sc;
|
||||
|
||||
@ -102,40 +95,42 @@ class SocketAdaptor
|
||||
throw new IllegalBlockingModeException();
|
||||
|
||||
try {
|
||||
// no timeout
|
||||
if (timeout == 0) {
|
||||
sc.connect(remote);
|
||||
return;
|
||||
}
|
||||
|
||||
// timed connect
|
||||
sc.configureBlocking(false);
|
||||
try {
|
||||
if (sc.connect(remote))
|
||||
return;
|
||||
long timeoutNanos =
|
||||
TimeUnit.NANOSECONDS.convert(timeout,
|
||||
TimeUnit.MILLISECONDS);
|
||||
for (;;) {
|
||||
if (!sc.isOpen())
|
||||
throw new ClosedChannelException();
|
||||
long startTime = System.nanoTime();
|
||||
|
||||
int result = sc.poll(Net.POLLCONN, timeout);
|
||||
if (result > 0 && sc.finishConnect())
|
||||
break;
|
||||
timeoutNanos -= System.nanoTime() - startTime;
|
||||
if (timeoutNanos <= 0) {
|
||||
try {
|
||||
sc.close();
|
||||
} catch (IOException x) { }
|
||||
throw new SocketTimeoutException();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
sc.configureBlocking(true);
|
||||
} catch (ClosedChannelException e) { }
|
||||
}
|
||||
|
||||
long timeoutNanos = NANOSECONDS.convert(timeout, MILLISECONDS);
|
||||
long to = timeout;
|
||||
for (;;) {
|
||||
long startTime = System.nanoTime();
|
||||
if (sc.pollConnected(to)) {
|
||||
boolean connected = sc.finishConnect();
|
||||
assert connected;
|
||||
break;
|
||||
}
|
||||
timeoutNanos -= System.nanoTime() - startTime;
|
||||
if (timeoutNanos <= 0) {
|
||||
try {
|
||||
sc.close();
|
||||
} catch (IOException x) { }
|
||||
throw new SocketTimeoutException();
|
||||
}
|
||||
to = MILLISECONDS.convert(timeoutNanos, NANOSECONDS);
|
||||
}
|
||||
|
||||
} catch (Exception x) {
|
||||
Net.translateException(x, true);
|
||||
}
|
||||
@ -152,11 +147,11 @@ class SocketAdaptor
|
||||
}
|
||||
|
||||
public InetAddress getInetAddress() {
|
||||
SocketAddress remote = sc.remoteAddress();
|
||||
InetSocketAddress remote = sc.remoteAddress();
|
||||
if (remote == null) {
|
||||
return null;
|
||||
} else {
|
||||
return ((InetSocketAddress)remote).getAddress();
|
||||
return remote.getAddress();
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,20 +166,20 @@ class SocketAdaptor
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
SocketAddress remote = sc.remoteAddress();
|
||||
InetSocketAddress remote = sc.remoteAddress();
|
||||
if (remote == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return ((InetSocketAddress)remote).getPort();
|
||||
return remote.getPort();
|
||||
}
|
||||
}
|
||||
|
||||
public int getLocalPort() {
|
||||
SocketAddress local = sc.localAddress();
|
||||
InetSocketAddress local = sc.localAddress();
|
||||
if (local == null) {
|
||||
return -1;
|
||||
} else {
|
||||
return ((InetSocketAddress)local).getPort();
|
||||
return local.getPort();
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,34 +197,22 @@ class SocketAdaptor
|
||||
if (!sc.isBlocking())
|
||||
throw new IllegalBlockingModeException();
|
||||
|
||||
if (timeout == 0)
|
||||
// no timeout
|
||||
long to = SocketAdaptor.this.timeout;
|
||||
if (to == 0)
|
||||
return sc.read(bb);
|
||||
|
||||
sc.configureBlocking(false);
|
||||
try {
|
||||
int n;
|
||||
if ((n = sc.read(bb)) != 0)
|
||||
return n;
|
||||
long timeoutNanos =
|
||||
TimeUnit.NANOSECONDS.convert(timeout,
|
||||
TimeUnit.MILLISECONDS);
|
||||
for (;;) {
|
||||
if (!sc.isOpen())
|
||||
throw new ClosedChannelException();
|
||||
long startTime = System.nanoTime();
|
||||
int result = sc.poll(Net.POLLIN, timeout);
|
||||
if (result > 0) {
|
||||
if ((n = sc.read(bb)) != 0)
|
||||
return n;
|
||||
}
|
||||
timeoutNanos -= System.nanoTime() - startTime;
|
||||
if (timeoutNanos <= 0)
|
||||
throw new SocketTimeoutException();
|
||||
// timed read
|
||||
long timeoutNanos = NANOSECONDS.convert(to, MILLISECONDS);
|
||||
for (;;) {
|
||||
long startTime = System.nanoTime();
|
||||
if (sc.pollRead(to)) {
|
||||
return sc.read(bb);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
sc.configureBlocking(true);
|
||||
} catch (ClosedChannelException e) { }
|
||||
timeoutNanos -= System.nanoTime() - startTime;
|
||||
if (timeoutNanos <= 0)
|
||||
throw new SocketTimeoutException();
|
||||
to = MILLISECONDS.convert(timeoutNanos, NANOSECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -453,5 +436,4 @@ class SocketAdaptor
|
||||
public boolean isOutputShutdown() {
|
||||
return !sc.isOutputOpen();
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -28,31 +28,26 @@ package sun.nio.ch;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.NotYetConnectedException;
|
||||
import java.nio.channels.Pipe;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
|
||||
class SinkChannelImpl
|
||||
extends Pipe.SinkChannel
|
||||
implements SelChImpl
|
||||
{
|
||||
|
||||
// Used to make native read and write calls
|
||||
private static final NativeDispatcher nd = new FileDispatcherImpl();
|
||||
|
||||
// The file descriptor associated with this channel
|
||||
private final FileDescriptor fd;
|
||||
|
||||
// fd value needed for dev/poll. This value will remain valid
|
||||
// even after the value in the file descriptor object has been set to -1
|
||||
private final int fdVal;
|
||||
|
||||
// ID of native thread doing write, for signalling
|
||||
private volatile long thread;
|
||||
|
||||
// Lock held by current writing thread
|
||||
private final ReentrantLock writeLock = new ReentrantLock();
|
||||
|
||||
@ -63,10 +58,14 @@ class SinkChannelImpl
|
||||
// -- The following fields are protected by stateLock
|
||||
|
||||
// Channel state
|
||||
private static final int ST_UNINITIALIZED = -1;
|
||||
private static final int ST_INUSE = 0;
|
||||
private static final int ST_KILLED = 1;
|
||||
private volatile int state = ST_UNINITIALIZED;
|
||||
private static final int ST_CLOSING = 1;
|
||||
private static final int ST_KILLPENDING = 2;
|
||||
private static final int ST_KILLED = 3;
|
||||
private int state;
|
||||
|
||||
// ID of native thread doing write, for signalling
|
||||
private long thread;
|
||||
|
||||
// -- End of fields protected by stateLock
|
||||
|
||||
@ -83,37 +82,86 @@ class SinkChannelImpl
|
||||
super(sp);
|
||||
this.fd = fd;
|
||||
this.fdVal = IOUtil.fdVal(fd);
|
||||
this.state = ST_INUSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by implCloseChannel to close the channel.
|
||||
*/
|
||||
@Override
|
||||
protected void implCloseSelectableChannel() throws IOException {
|
||||
assert !isOpen();
|
||||
|
||||
boolean interrupted = false;
|
||||
boolean blocking;
|
||||
|
||||
// set state to ST_CLOSING
|
||||
synchronized (stateLock) {
|
||||
if (state != ST_KILLED)
|
||||
nd.preClose(fd);
|
||||
long th = thread;
|
||||
if (th != 0)
|
||||
NativeThread.signal(th);
|
||||
if (!isRegistered())
|
||||
kill();
|
||||
assert state < ST_CLOSING;
|
||||
state = ST_CLOSING;
|
||||
blocking = isBlocking();
|
||||
}
|
||||
|
||||
// wait for any outstanding write to complete
|
||||
if (blocking) {
|
||||
synchronized (stateLock) {
|
||||
assert state == ST_CLOSING;
|
||||
long th = thread;
|
||||
if (th != 0) {
|
||||
nd.preClose(fd);
|
||||
NativeThread.signal(th);
|
||||
|
||||
// wait for write operation to end
|
||||
while (thread != 0) {
|
||||
try {
|
||||
stateLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
interrupted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// non-blocking mode: wait for write to complete
|
||||
writeLock.lock();
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
// set state to ST_KILLPENDING
|
||||
synchronized (stateLock) {
|
||||
assert state == ST_CLOSING;
|
||||
state = ST_KILLPENDING;
|
||||
}
|
||||
|
||||
// close socket if not registered with Selector
|
||||
if (!isRegistered())
|
||||
kill();
|
||||
|
||||
// restore interrupt status
|
||||
if (interrupted)
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void kill() throws IOException {
|
||||
synchronized (stateLock) {
|
||||
if (state == ST_KILLED)
|
||||
return;
|
||||
if (state == ST_UNINITIALIZED) {
|
||||
assert thread == 0;
|
||||
if (state == ST_KILLPENDING) {
|
||||
state = ST_KILLED;
|
||||
return;
|
||||
nd.close(fd);
|
||||
}
|
||||
assert !isOpen() && !isRegistered();
|
||||
nd.close(fd);
|
||||
state = ST_KILLED;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implConfigureBlocking(boolean block) throws IOException {
|
||||
IOUtil.configureBlocking(fd, block);
|
||||
writeLock.lock();
|
||||
try {
|
||||
synchronized (stateLock) {
|
||||
IOUtil.configureBlocking(fd, block);
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean translateReadyOps(int ops, int initialOps,
|
||||
@ -153,67 +201,95 @@ class SinkChannelImpl
|
||||
sk.selector.putEventOps(sk, ops);
|
||||
}
|
||||
|
||||
private void ensureOpen() throws IOException {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
/**
|
||||
* Marks the beginning of a write operation that might block.
|
||||
*
|
||||
* @throws ClosedChannelException if the channel is closed
|
||||
* @throws NotYetConnectedException if the channel is not yet connected
|
||||
*/
|
||||
private void beginWrite(boolean blocking) throws ClosedChannelException {
|
||||
if (blocking) {
|
||||
// set hook for Thread.interrupt
|
||||
begin();
|
||||
}
|
||||
synchronized (stateLock) {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
if (blocking)
|
||||
thread = NativeThread.current();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the end of a write operation that may have blocked.
|
||||
*
|
||||
* @throws AsynchronousCloseException if the channel was closed due to this
|
||||
* thread being interrupted on a blocking write operation.
|
||||
*/
|
||||
private void endWrite(boolean blocking, boolean completed)
|
||||
throws AsynchronousCloseException
|
||||
{
|
||||
if (blocking) {
|
||||
synchronized (stateLock) {
|
||||
thread = 0;
|
||||
// notify any thread waiting in implCloseSelectableChannel
|
||||
if (state == ST_CLOSING) {
|
||||
stateLock.notifyAll();
|
||||
}
|
||||
}
|
||||
// remove hook for Thread.interrupt
|
||||
end(completed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int write(ByteBuffer src) throws IOException {
|
||||
Objects.requireNonNull(src);
|
||||
|
||||
writeLock.lock();
|
||||
try {
|
||||
ensureOpen();
|
||||
boolean blocking = isBlocking();
|
||||
int n = 0;
|
||||
try {
|
||||
begin();
|
||||
if (!isOpen())
|
||||
return 0;
|
||||
thread = NativeThread.current();
|
||||
beginWrite(blocking);
|
||||
do {
|
||||
n = IOUtil.write(fd, src, -1, nd);
|
||||
} while ((n == IOStatus.INTERRUPTED) && isOpen());
|
||||
return IOStatus.normalize(n);
|
||||
} finally {
|
||||
thread = 0;
|
||||
end((n > 0) || (n == IOStatus.UNAVAILABLE));
|
||||
endWrite(blocking, n > 0);
|
||||
assert IOStatus.check(n);
|
||||
}
|
||||
return IOStatus.normalize(n);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public long write(ByteBuffer[] srcs) throws IOException {
|
||||
if (srcs == null)
|
||||
throw new NullPointerException();
|
||||
@Override
|
||||
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
|
||||
Objects.checkFromIndexSize(offset, length, srcs.length);
|
||||
|
||||
writeLock.lock();
|
||||
try {
|
||||
ensureOpen();
|
||||
boolean blocking = isBlocking();
|
||||
long n = 0;
|
||||
try {
|
||||
begin();
|
||||
if (!isOpen())
|
||||
return 0;
|
||||
thread = NativeThread.current();
|
||||
beginWrite(blocking);
|
||||
do {
|
||||
n = IOUtil.write(fd, srcs, nd);
|
||||
n = IOUtil.write(fd, srcs, offset, length, nd);
|
||||
} while ((n == IOStatus.INTERRUPTED) && isOpen());
|
||||
return IOStatus.normalize(n);
|
||||
} finally {
|
||||
thread = 0;
|
||||
end((n > 0) || (n == IOStatus.UNAVAILABLE));
|
||||
endWrite(blocking, n > 0);
|
||||
assert IOStatus.check(n);
|
||||
}
|
||||
return IOStatus.normalize(n);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public long write(ByteBuffer[] srcs, int offset, int length)
|
||||
throws IOException
|
||||
{
|
||||
if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
|
||||
throw new IndexOutOfBoundsException();
|
||||
return write(Util.subsequence(srcs, offset, length));
|
||||
@Override
|
||||
public long write(ByteBuffer[] srcs) throws IOException {
|
||||
return write(srcs, 0, srcs.length);
|
||||
}
|
||||
}
|
||||
|
@ -28,31 +28,26 @@ package sun.nio.ch;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.NotYetConnectedException;
|
||||
import java.nio.channels.Pipe;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
|
||||
class SourceChannelImpl
|
||||
extends Pipe.SourceChannel
|
||||
implements SelChImpl
|
||||
{
|
||||
|
||||
// Used to make native read and write calls
|
||||
private static final NativeDispatcher nd = new FileDispatcherImpl();
|
||||
|
||||
// The file descriptor associated with this channel
|
||||
private final FileDescriptor fd;
|
||||
|
||||
// fd value needed for dev/poll. This value will remain valid
|
||||
// even after the value in the file descriptor object has been set to -1
|
||||
private final int fdVal;
|
||||
|
||||
// ID of native thread doing read, for signalling
|
||||
private volatile long thread;
|
||||
|
||||
// Lock held by current reading thread
|
||||
private final ReentrantLock readLock = new ReentrantLock();
|
||||
|
||||
@ -63,10 +58,14 @@ class SourceChannelImpl
|
||||
// -- The following fields are protected by stateLock
|
||||
|
||||
// Channel state
|
||||
private static final int ST_UNINITIALIZED = -1;
|
||||
private static final int ST_INUSE = 0;
|
||||
private static final int ST_KILLED = 1;
|
||||
private volatile int state = ST_UNINITIALIZED;
|
||||
private static final int ST_CLOSING = 1;
|
||||
private static final int ST_KILLPENDING = 2;
|
||||
private static final int ST_KILLED = 3;
|
||||
private int state;
|
||||
|
||||
// ID of native thread doing read, for signalling
|
||||
private long thread;
|
||||
|
||||
// -- End of fields protected by stateLock
|
||||
|
||||
@ -83,37 +82,86 @@ class SourceChannelImpl
|
||||
super(sp);
|
||||
this.fd = fd;
|
||||
this.fdVal = IOUtil.fdVal(fd);
|
||||
this.state = ST_INUSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by implCloseChannel to close the channel.
|
||||
*/
|
||||
@Override
|
||||
protected void implCloseSelectableChannel() throws IOException {
|
||||
assert !isOpen();
|
||||
|
||||
boolean interrupted = false;
|
||||
boolean blocking;
|
||||
|
||||
// set state to ST_CLOSING
|
||||
synchronized (stateLock) {
|
||||
if (state != ST_KILLED)
|
||||
nd.preClose(fd);
|
||||
long th = thread;
|
||||
if (th != 0)
|
||||
NativeThread.signal(th);
|
||||
if (!isRegistered())
|
||||
kill();
|
||||
assert state < ST_CLOSING;
|
||||
state = ST_CLOSING;
|
||||
blocking = isBlocking();
|
||||
}
|
||||
|
||||
// wait for any outstanding read to complete
|
||||
if (blocking) {
|
||||
synchronized (stateLock) {
|
||||
assert state == ST_CLOSING;
|
||||
long th = thread;
|
||||
if (th != 0) {
|
||||
nd.preClose(fd);
|
||||
NativeThread.signal(th);
|
||||
|
||||
// wait for read operation to end
|
||||
while (thread != 0) {
|
||||
try {
|
||||
stateLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
interrupted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// non-blocking mode: wait for read to complete
|
||||
readLock.lock();
|
||||
readLock.unlock();
|
||||
}
|
||||
|
||||
// set state to ST_KILLPENDING
|
||||
synchronized (stateLock) {
|
||||
assert state == ST_CLOSING;
|
||||
state = ST_KILLPENDING;
|
||||
}
|
||||
|
||||
// close socket if not registered with Selector
|
||||
if (!isRegistered())
|
||||
kill();
|
||||
|
||||
// restore interrupt status
|
||||
if (interrupted)
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void kill() throws IOException {
|
||||
synchronized (stateLock) {
|
||||
if (state == ST_KILLED)
|
||||
return;
|
||||
if (state == ST_UNINITIALIZED) {
|
||||
assert thread == 0;
|
||||
if (state == ST_KILLPENDING) {
|
||||
state = ST_KILLED;
|
||||
return;
|
||||
nd.close(fd);
|
||||
}
|
||||
assert !isOpen() && !isRegistered();
|
||||
nd.close(fd);
|
||||
state = ST_KILLED;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implConfigureBlocking(boolean block) throws IOException {
|
||||
IOUtil.configureBlocking(fd, block);
|
||||
readLock.lock();
|
||||
try {
|
||||
synchronized (stateLock) {
|
||||
IOUtil.configureBlocking(fd, block);
|
||||
}
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean translateReadyOps(int ops, int initialOps,
|
||||
@ -153,68 +201,95 @@ class SourceChannelImpl
|
||||
sk.selector.putEventOps(sk, ops);
|
||||
}
|
||||
|
||||
private void ensureOpen() throws IOException {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
/**
|
||||
* Marks the beginning of a read operation that might block.
|
||||
*
|
||||
* @throws ClosedChannelException if the channel is closed
|
||||
* @throws NotYetConnectedException if the channel is not yet connected
|
||||
*/
|
||||
private void beginRead(boolean blocking) throws ClosedChannelException {
|
||||
if (blocking) {
|
||||
// set hook for Thread.interrupt
|
||||
begin();
|
||||
}
|
||||
synchronized (stateLock) {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
if (blocking)
|
||||
thread = NativeThread.current();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the end of a read operation that may have blocked.
|
||||
*
|
||||
* @throws AsynchronousCloseException if the channel was closed due to this
|
||||
* thread being interrupted on a blocking read operation.
|
||||
*/
|
||||
private void endRead(boolean blocking, boolean completed)
|
||||
throws AsynchronousCloseException
|
||||
{
|
||||
if (blocking) {
|
||||
synchronized (stateLock) {
|
||||
thread = 0;
|
||||
// notify any thread waiting in implCloseSelectableChannel
|
||||
if (state == ST_CLOSING) {
|
||||
stateLock.notifyAll();
|
||||
}
|
||||
}
|
||||
// remove hook for Thread.interrupt
|
||||
end(completed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(ByteBuffer dst) throws IOException {
|
||||
Objects.requireNonNull(dst);
|
||||
|
||||
readLock.lock();
|
||||
try {
|
||||
ensureOpen();
|
||||
boolean blocking = isBlocking();
|
||||
int n = 0;
|
||||
try {
|
||||
begin();
|
||||
if (!isOpen())
|
||||
return 0;
|
||||
thread = NativeThread.current();
|
||||
beginRead(blocking);
|
||||
do {
|
||||
n = IOUtil.read(fd, dst, -1, nd);
|
||||
} while ((n == IOStatus.INTERRUPTED) && isOpen());
|
||||
return IOStatus.normalize(n);
|
||||
} finally {
|
||||
thread = 0;
|
||||
end((n > 0) || (n == IOStatus.UNAVAILABLE));
|
||||
endRead(blocking, n > 0);
|
||||
assert IOStatus.check(n);
|
||||
}
|
||||
return IOStatus.normalize(n);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public long read(ByteBuffer[] dsts, int offset, int length)
|
||||
throws IOException
|
||||
{
|
||||
if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
|
||||
throw new IndexOutOfBoundsException();
|
||||
return read(Util.subsequence(dsts, offset, length));
|
||||
}
|
||||
|
||||
public long read(ByteBuffer[] dsts) throws IOException {
|
||||
if (dsts == null)
|
||||
throw new NullPointerException();
|
||||
@Override
|
||||
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
|
||||
Objects.checkFromIndexSize(offset, length, dsts.length);
|
||||
|
||||
readLock.lock();
|
||||
try {
|
||||
ensureOpen();
|
||||
boolean blocking = isBlocking();
|
||||
long n = 0;
|
||||
try {
|
||||
begin();
|
||||
if (!isOpen())
|
||||
return 0;
|
||||
thread = NativeThread.current();
|
||||
beginRead(blocking);
|
||||
do {
|
||||
n = IOUtil.read(fd, dsts, nd);
|
||||
n = IOUtil.read(fd, dsts, offset, length, nd);
|
||||
} while ((n == IOStatus.INTERRUPTED) && isOpen());
|
||||
return IOStatus.normalize(n);
|
||||
} finally {
|
||||
thread = 0;
|
||||
end((n > 0) || (n == IOStatus.UNAVAILABLE));
|
||||
endRead(blocking, n > 0);
|
||||
assert IOStatus.check(n);
|
||||
}
|
||||
return IOStatus.normalize(n);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long read(ByteBuffer[] dsts) throws IOException {
|
||||
return read(dsts, 0, dsts.length);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user