diff --git a/transport-native-epoll/src/main/c/netty_epoll_linuxsocket.c b/transport-native-epoll/src/main/c/netty_epoll_linuxsocket.c index d6e3ead94f..05d889f175 100644 --- a/transport-native-epoll/src/main/c/netty_epoll_linuxsocket.c +++ b/transport-native-epoll/src/main/c/netty_epoll_linuxsocket.c @@ -50,6 +50,11 @@ #define TCP_NOTSENT_LOWAT 25 #endif +// SO_BUSY_POLL is defined in linux 3.11. We define this here so older kernels can compile. +#ifndef SO_BUSY_POLL +#define SO_BUSY_POLL 46 +#endif + static jclass peerCredentialsClass = NULL; static jmethodID peerCredentialsMethodId = NULL; @@ -111,6 +116,10 @@ static void netty_epoll_linuxsocket_setIpRecvOrigDestAddr(JNIEnv* env, jclass cl netty_unix_socket_setOption(env, fd, IPPROTO_IP, IP_RECVORIGDSTADDR, &optval, sizeof(optval)); } +static void netty_epoll_linuxsocket_setSoBusyPoll(JNIEnv* env, jclass clazz, jint fd, jint optval) { + netty_unix_socket_setOption(env, fd, SOL_SOCKET, SO_BUSY_POLL, &optval, sizeof(optval)); +} + static void netty_epoll_linuxsocket_setTcpMd5Sig(JNIEnv* env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jbyteArray key) { struct sockaddr_storage addr; socklen_t addrSize; @@ -256,6 +265,14 @@ static jint netty_epoll_linuxsocket_isTcpCork(JNIEnv* env, jclass clazz, jint fd return optval; } +static jint netty_epoll_linuxsocket_getSoBusyPoll(JNIEnv* env, jclass clazz, jint fd) { + int optval; + if (netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_BUSY_POLL, &optval, sizeof(optval)) == -1) { + return -1; + } + return optval; +} + static jint netty_epoll_linuxsocket_getTcpDeferAccept(JNIEnv* env, jclass clazz, jint fd) { int optval; if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &optval, sizeof(optval)) == -1) { @@ -341,10 +358,12 @@ static jlong netty_epoll_linuxsocket_sendFile(JNIEnv* env, jclass clazz, jint fd // JNI Method Registration Table Begin static const JNINativeMethod fixed_method_table[] = { { "setTcpCork", "(II)V", (void *) netty_epoll_linuxsocket_setTcpCork }, + { "setSoBusyPoll", "(II)V", (void *) netty_epoll_linuxsocket_setSoBusyPoll }, { "setTcpQuickAck", "(II)V", (void *) netty_epoll_linuxsocket_setTcpQuickAck }, { "setTcpDeferAccept", "(II)V", (void *) netty_epoll_linuxsocket_setTcpDeferAccept }, { "setTcpNotSentLowAt", "(II)V", (void *) netty_epoll_linuxsocket_setTcpNotSentLowAt }, { "isTcpCork", "(I)I", (void *) netty_epoll_linuxsocket_isTcpCork }, + { "getSoBusyPoll", "(I)I", (void *) netty_epoll_linuxsocket_getSoBusyPoll }, { "getTcpDeferAccept", "(I)I", (void *) netty_epoll_linuxsocket_getTcpDeferAccept }, { "getTcpNotSentLowAt", "(I)I", (void *) netty_epoll_linuxsocket_getTcpNotSentLowAt }, { "isTcpQuickAck", "(I)I", (void *) netty_epoll_linuxsocket_isTcpQuickAck }, diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollChannelOption.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollChannelOption.java index d03e3e7236..1f5127c5dc 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollChannelOption.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollChannelOption.java @@ -38,6 +38,7 @@ public final class EpollChannelOption extends UnixChannelOption { public static final ChannelOption TCP_DEFER_ACCEPT = ChannelOption.valueOf(EpollChannelOption.class, "TCP_DEFER_ACCEPT"); public static final ChannelOption TCP_QUICKACK = valueOf(EpollChannelOption.class, "TCP_QUICKACK"); + public static final ChannelOption SO_BUSY_POLL = valueOf(EpollChannelOption.class, "SO_BUSY_POLL"); public static final ChannelOption EPOLL_MODE = ChannelOption.valueOf(EpollChannelOption.class, "EPOLL_MODE"); diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollSocketChannelConfig.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollSocketChannelConfig.java index 67468910b2..d61bf19e27 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollSocketChannelConfig.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollSocketChannelConfig.java @@ -62,7 +62,7 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement ALLOW_HALF_CLOSURE, EpollChannelOption.TCP_CORK, EpollChannelOption.TCP_NOTSENT_LOWAT, EpollChannelOption.TCP_KEEPCNT, EpollChannelOption.TCP_KEEPIDLE, EpollChannelOption.TCP_KEEPINTVL, EpollChannelOption.TCP_MD5SIG, EpollChannelOption.TCP_QUICKACK, EpollChannelOption.IP_TRANSPARENT, - EpollChannelOption.TCP_FASTOPEN_CONNECT); + EpollChannelOption.TCP_FASTOPEN_CONNECT, EpollChannelOption.SO_BUSY_POLL); } @SuppressWarnings("unchecked") @@ -119,6 +119,9 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement if (option == EpollChannelOption.TCP_FASTOPEN_CONNECT) { return (T) Boolean.valueOf(isTcpFastOpenConnect()); } + if (option == EpollChannelOption.SO_BUSY_POLL) { + return (T) Integer.valueOf(getSoBusyPoll()); + } return super.getOption(option); } @@ -164,6 +167,8 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement setTcpQuickAck((Boolean) value); } else if (option == EpollChannelOption.TCP_FASTOPEN_CONNECT) { setTcpFastOpenConnect((Boolean) value); + } else if (option == EpollChannelOption.SO_BUSY_POLL) { + setSoBusyPoll((Integer) value); } else { return super.setOption(option, value); } @@ -245,6 +250,17 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement } } + /** + * Get the {@code SO_BUSY_POLL} option on the socket. See {@code man 7 tcp} for more details. + */ + public int getSoBusyPoll() { + try { + return channel.socket.getSoBusyPoll(); + } catch (IOException e) { + throw new ChannelException(e); + } + } + /** * Get the {@code TCP_NOTSENT_LOWAT} option on the socket. See {@code man 7 tcp} for more details. * @return value is a uint32_t @@ -380,6 +396,18 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement } } + /** + * Set the {@code SO_BUSY_POLL} option on the socket. See {@code man 7 tcp} for more details. + */ + public EpollSocketChannelConfig setSoBusyPoll(int loopMicros) { + try { + channel.socket.setSoBusyPoll(loopMicros); + return this; + } catch (IOException e) { + throw new ChannelException(e); + } + } + /** * Set the {@code TCP_NOTSENT_LOWAT} option on the socket. See {@code man 7 tcp} for more details. * @param tcpNotSentLowAt is a uint32_t diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/LinuxSocket.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/LinuxSocket.java index f0a5304a74..d3578b4dae 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/LinuxSocket.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/LinuxSocket.java @@ -56,6 +56,10 @@ final class LinuxSocket extends Socket { setTcpCork(intValue(), tcpCork ? 1 : 0); } + void setSoBusyPoll(int loopMicros) throws IOException { + setSoBusyPoll(intValue(), loopMicros); + } + void setTcpNotSentLowAt(long tcpNotSentLowAt) throws IOException { if (tcpNotSentLowAt < 0 || tcpNotSentLowAt > MAX_UINT32_T) { throw new IllegalArgumentException("tcpNotSentLowAt must be a uint32_t"); @@ -116,6 +120,10 @@ final class LinuxSocket extends Socket { return isTcpCork(intValue()) != 0; } + int getSoBusyPoll() throws IOException { + return getSoBusyPoll(intValue()); + } + int getTcpDeferAccept() throws IOException { return getTcpDeferAccept(intValue()); } @@ -190,6 +198,7 @@ final class LinuxSocket extends Socket { private static native int getTcpDeferAccept(int fd) throws IOException; private static native int isTcpQuickAck(int fd) throws IOException; private static native int isTcpCork(int fd) throws IOException; + private static native int getSoBusyPoll(int fd) throws IOException; private static native int getTcpNotSentLowAt(int fd) throws IOException; private static native int getTcpKeepIdle(int fd) throws IOException; private static native int getTcpKeepIntvl(int fd) throws IOException; @@ -205,6 +214,7 @@ final class LinuxSocket extends Socket { private static native void setTcpDeferAccept(int fd, int deferAccept) throws IOException; private static native void setTcpQuickAck(int fd, int quickAck) throws IOException; private static native void setTcpCork(int fd, int tcpCork) throws IOException; + private static native void setSoBusyPoll(int fd, int loopMicros) throws IOException; private static native void setTcpNotSentLowAt(int fd, int tcpNotSentLowAt) throws IOException; private static native void setTcpFastOpen(int fd, int tcpFastopenBacklog) throws IOException; private static native void setTcpFastOpenConnect(int fd, int tcpFastOpenConnect) throws IOException;