summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOran Agra <oran@redislabs.com>2021-07-05 10:34:20 +0300
committerGitHub <noreply@github.com>2021-07-05 10:34:20 +0300
commit5a3de81925130792f78c35e9e4d0204213a3a41e (patch)
tree34e46fe7b782a64f0ed7e0f04e59e6a419020714 /src
parentec582cc7ad0706e252bc905822226e49f4c4d0e4 (diff)
downloadredis-5a3de81925130792f78c35e9e4d0204213a3a41e.tar.gz
Use accept4 on linux instead of fcntl to make a client socket non-blocking (#9177)
This reduces system calls on linux when a new connection is made / accepted. Changes: * Add the SOCK_CLOEXEC option to the accept4() call This ensure that a fork/exec call does not leak a file descriptor. * Move anetCloexec and connNonBlock info anetGenericAccept * Moving connNonBlock from accept handlers to anetGenericAccept Moving connNonBlock from createClient, is safe because createClient is used in the following ways: 1. without a connection (fake client) 2. on an accepted connection (see above) 3. creating the master client by using connConnect (see below) The third case, can either use anetTcpNonBlockConnect, or connTLSConnect which is by default non-blocking. Co-authored-by: Rajiv Kurian <geetasen@gmail.com> Co-authored-by: Oran Agra <oran@redislabs.com> Co-authored-by: Yoav Steinberg <yoav@redislabs.com>
Diffstat (limited to 'src')
-rw-r--r--src/anet.c24
-rw-r--r--src/cluster.c1
-rw-r--r--src/config.h5
-rw-r--r--src/networking.c4
4 files changed, 29 insertions, 5 deletions
diff --git a/src/anet.c b/src/anet.c
index 381dda375..f4f3a98bf 100644
--- a/src/anet.c
+++ b/src/anet.c
@@ -47,6 +47,7 @@
#include <stdio.h>
#include "anet.h"
+#include "config.h"
static void anetSetError(char *err, const char *fmt, ...)
{
@@ -491,18 +492,39 @@ int anetUnixServer(char *err, char *path, mode_t perm, int backlog)
return s;
}
+/* Accept a connection and also make sure the socket is non-blocking, and CLOEXEC.
+ * returns the new socket FD, or -1 on error. */
static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) {
int fd;
do {
+ /* Use the accept4() call on linux to simultaneously accept and
+ * set a socket as non-blocking. */
+#ifdef HAVE_ACCEPT4
+ fd = accept4(s, sa, len, SOCK_NONBLOCK | SOCK_CLOEXEC);
+#else
fd = accept(s,sa,len);
+#endif
} while(fd == -1 && errno == EINTR);
if (fd == -1) {
anetSetError(err, "accept: %s", strerror(errno));
return ANET_ERR;
}
+#ifndef HAVE_ACCEPT4
+ if (anetCloexec(fd) == -1) {
+ anetSetError(err, "anetCloexec: %s", strerror(errno));
+ close(fd);
+ return ANET_ERR;
+ }
+ if (anetNonBlock(err, fd) != ANET_OK) {
+ close(fd);
+ return ANET_ERR;
+ }
+#endif
return fd;
}
+/* Accept a connection and also make sure the socket is non-blocking, and CLOEXEC.
+ * returns the new socket FD, or -1 on error. */
int anetTcpAccept(char *err, int s, char *ip, size_t ip_len, int *port) {
int fd;
struct sockaddr_storage sa;
@@ -522,6 +544,8 @@ int anetTcpAccept(char *err, int s, char *ip, size_t ip_len, int *port) {
return fd;
}
+/* Accept a connection and also make sure the socket is non-blocking, and CLOEXEC.
+ * returns the new socket FD, or -1 on error. */
int anetUnixAccept(char *err, int s) {
int fd;
struct sockaddr_un sa;
diff --git a/src/cluster.c b/src/cluster.c
index 12ea935d5..92601b001 100644
--- a/src/cluster.c
+++ b/src/cluster.c
@@ -735,7 +735,6 @@ void clusterAcceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
connClose(conn);
return;
}
- connNonBlock(conn);
connEnableTcpNoDelay(conn);
/* Use non-blocking I/O for cluster messages. */
diff --git a/src/config.h b/src/config.h
index 56c1ab6ae..af5209f89 100644
--- a/src/config.h
+++ b/src/config.h
@@ -78,6 +78,11 @@
#define HAVE_EPOLL 1
#endif
+/* Test for accept4() */
+#ifdef __linux__
+#define HAVE_ACCEPT4 1
+#endif
+
#if (defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__)
#define HAVE_KQUEUE 1
#endif
diff --git a/src/networking.c b/src/networking.c
index 805f3f0e9..8e16b7575 100644
--- a/src/networking.c
+++ b/src/networking.c
@@ -115,7 +115,6 @@ client *createClient(connection *conn) {
* in the context of a client. When commands are executed in other
* contexts (for instance a Lua script) we need a non connected client. */
if (conn) {
- connNonBlock(conn);
connEnableTcpNoDelay(conn);
if (server.tcpkeepalive)
connKeepAlive(conn,server.tcpkeepalive);
@@ -1122,7 +1121,6 @@ void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
"Accepting client connection: %s", server.neterr);
return;
}
- anetCloexec(cfd);
serverLog(LL_VERBOSE,"Accepted %s:%d", cip, cport);
acceptCommonHandler(connCreateAcceptedSocket(cfd),0,cip);
}
@@ -1143,7 +1141,6 @@ void acceptTLSHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
"Accepting client connection: %s", server.neterr);
return;
}
- anetCloexec(cfd);
serverLog(LL_VERBOSE,"Accepted %s:%d", cip, cport);
acceptCommonHandler(connCreateAcceptedTLS(cfd, server.tls_auth_clients),0,cip);
}
@@ -1163,7 +1160,6 @@ void acceptUnixHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
"Accepting client connection: %s", server.neterr);
return;
}
- anetCloexec(cfd);
serverLog(LL_VERBOSE,"Accepted connection to %s", server.unixsocket);
acceptCommonHandler(connCreateAcceptedSocket(cfd),CLIENT_UNIX_SOCKET,NULL);
}