Ensure closing a Socket / FileDescriptor multiple times will not throw exception
Motivation: If an user will close a Socket / FileDescriptor multiple times we should handle the extra close operations as NOOP. Modifications: Only do the actual closing one time Result: No exception if close is called multiple times.
This commit is contained in:
parent
ac1060003a
commit
617773817f
@ -15,9 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.channel.unix;
|
package io.netty.channel.unix;
|
||||||
|
|
||||||
|
import io.netty.util.internal.PlatformDependent;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
||||||
|
|
||||||
import static io.netty.channel.unix.Errors.CONNECTION_RESET_EXCEPTION_READ;
|
import static io.netty.channel.unix.Errors.CONNECTION_RESET_EXCEPTION_READ;
|
||||||
import static io.netty.channel.unix.Errors.CONNECTION_RESET_EXCEPTION_WRITE;
|
import static io.netty.channel.unix.Errors.CONNECTION_RESET_EXCEPTION_WRITE;
|
||||||
@ -31,8 +34,18 @@ import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
|||||||
* {@link FileDescriptor} for it.
|
* {@link FileDescriptor} for it.
|
||||||
*/
|
*/
|
||||||
public class FileDescriptor {
|
public class FileDescriptor {
|
||||||
|
private static final AtomicIntegerFieldUpdater<FileDescriptor> openUpdater;
|
||||||
|
static {
|
||||||
|
AtomicIntegerFieldUpdater<FileDescriptor> updater
|
||||||
|
= PlatformDependent.newAtomicIntegerFieldUpdater(FileDescriptor.class, "open");
|
||||||
|
if (updater == null) {
|
||||||
|
updater = AtomicIntegerFieldUpdater.newUpdater(FileDescriptor.class, "open");
|
||||||
|
}
|
||||||
|
openUpdater = updater;
|
||||||
|
}
|
||||||
|
|
||||||
private final int fd;
|
private final int fd;
|
||||||
private volatile boolean open = true;
|
private volatile int open = 1;
|
||||||
|
|
||||||
public FileDescriptor(int fd) {
|
public FileDescriptor(int fd) {
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
@ -52,18 +65,19 @@ public class FileDescriptor {
|
|||||||
* Close the file descriptor.
|
* Close the file descriptor.
|
||||||
*/
|
*/
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
open = false;
|
if (openUpdater.compareAndSet(this, 1, 0)) {
|
||||||
int res = close(fd);
|
int res = close(fd);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
throw newIOException("close", res);
|
throw newIOException("close", res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@code true} if the file descriptor is open.
|
* Returns {@code true} if the file descriptor is open.
|
||||||
*/
|
*/
|
||||||
public boolean isOpen() {
|
public boolean isOpen() {
|
||||||
return open;
|
return open == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final int write(ByteBuffer buf, int pos, int limit) throws IOException {
|
public final int write(ByteBuffer buf, int pos, int limit) throws IOException {
|
||||||
|
@ -44,80 +44,56 @@ public class SocketTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testKeepAlive() throws Exception {
|
public void testKeepAlive() throws Exception {
|
||||||
Socket socket = Socket.newSocketStream();
|
|
||||||
try {
|
|
||||||
assertFalse(socket.isKeepAlive());
|
assertFalse(socket.isKeepAlive());
|
||||||
socket.setKeepAlive(true);
|
socket.setKeepAlive(true);
|
||||||
assertTrue(socket.isKeepAlive());
|
assertTrue(socket.isKeepAlive());
|
||||||
} finally {
|
|
||||||
socket.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTcpCork() throws Exception {
|
public void testTcpCork() throws Exception {
|
||||||
Socket socket = Socket.newSocketStream();
|
|
||||||
try {
|
|
||||||
assertFalse(socket.isTcpCork());
|
assertFalse(socket.isTcpCork());
|
||||||
socket.setTcpCork(true);
|
socket.setTcpCork(true);
|
||||||
assertTrue(socket.isTcpCork());
|
assertTrue(socket.isTcpCork());
|
||||||
} finally {
|
|
||||||
socket.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTcpNoDelay() throws Exception {
|
public void testTcpNoDelay() throws Exception {
|
||||||
Socket socket = Socket.newSocketStream();
|
|
||||||
try {
|
|
||||||
assertFalse(socket.isTcpNoDelay());
|
assertFalse(socket.isTcpNoDelay());
|
||||||
socket.setTcpNoDelay(true);
|
socket.setTcpNoDelay(true);
|
||||||
assertTrue(socket.isTcpNoDelay());
|
assertTrue(socket.isTcpNoDelay());
|
||||||
} finally {
|
|
||||||
socket.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReceivedBufferSize() throws Exception {
|
public void testReceivedBufferSize() throws Exception {
|
||||||
Socket socket = Socket.newSocketStream();
|
|
||||||
try {
|
|
||||||
int size = socket.getReceiveBufferSize();
|
int size = socket.getReceiveBufferSize();
|
||||||
int newSize = 65535;
|
int newSize = 65535;
|
||||||
assertTrue(size > 0);
|
assertTrue(size > 0);
|
||||||
socket.setReceiveBufferSize(newSize);
|
socket.setReceiveBufferSize(newSize);
|
||||||
// Linux usually set it to double what is specified
|
// Linux usually set it to double what is specified
|
||||||
assertTrue(newSize <= socket.getReceiveBufferSize());
|
assertTrue(newSize <= socket.getReceiveBufferSize());
|
||||||
} finally {
|
|
||||||
socket.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSendBufferSize() throws Exception {
|
public void testSendBufferSize() throws Exception {
|
||||||
Socket socket = Socket.newSocketStream();
|
|
||||||
try {
|
|
||||||
int size = socket.getSendBufferSize();
|
int size = socket.getSendBufferSize();
|
||||||
int newSize = 65535;
|
int newSize = 65535;
|
||||||
assertTrue(size > 0);
|
assertTrue(size > 0);
|
||||||
socket.setSendBufferSize(newSize);
|
socket.setSendBufferSize(newSize);
|
||||||
// Linux usually set it to double what is specified
|
// Linux usually set it to double what is specified
|
||||||
assertTrue(newSize <= socket.getSendBufferSize());
|
assertTrue(newSize <= socket.getSendBufferSize());
|
||||||
} finally {
|
|
||||||
socket.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSoLinger() throws Exception {
|
public void testSoLinger() throws Exception {
|
||||||
Socket socket = Socket.newSocketStream();
|
|
||||||
try {
|
|
||||||
assertEquals(-1, socket.getSoLinger());
|
assertEquals(-1, socket.getSoLinger());
|
||||||
socket.setSoLinger(10);
|
socket.setSoLinger(10);
|
||||||
assertEquals(10, socket.getSoLinger());
|
assertEquals(10, socket.getSoLinger());
|
||||||
} finally {
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoubleCloseDoesNotThrow() throws IOException {
|
||||||
|
Socket socket = Socket.newSocketStream();
|
||||||
|
socket.close();
|
||||||
socket.close();
|
socket.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user