1
0
mirror of http://git.haproxy.org/git/haproxy.git/ synced 2025-03-23 03:16:47 +00:00

MEDIUM: listener: add support for linux's accept4() syscall

On Linux, accept4() does the same as accept() except that it allows
the caller to specify some flags to set on the resulting socket. We
use this to set the O_NONBLOCK flag and thus to save one fcntl()
call in each connection. The effect is a small performance gain of
around 1%.

The option is automatically enabled when target linux2628 is set, or
when the USE_ACCEPT4 Makefile variable is set. If the libc is too old
to provide the equivalent function, this is automatically detected and
our own function is used instead. In any case it is possible to force
the use of our implementation with USE_MY_ACCEPT4.
This commit is contained in:
Willy Tarreau 2012-10-08 20:11:03 +02:00
parent 1b6c00cb99
commit 1bc4aab290
6 changed files with 115 additions and 2 deletions

View File

@ -28,6 +28,8 @@
# USE_GETADDRINFO : use getaddrinfo() to resolve IPv6 host names.
# USE_OPENSSL : enable use of OpenSSL. Recommended, but see below.
# USE_FUTEX : enable use of futex on kernel 2.6. Automatic.
# USE_ACCEPT4 : enable use of accept4() on linux. Automatic.
# USE_MY_ACCEPT4 : use own implemention of accept4() if glibc < 2.10.
#
# Options can be forced by specifying "USE_xxx=1" or can be disabled by using
# "USE_xxx=" (empty string).
@ -240,6 +242,7 @@ ifeq ($(TARGET),linux2628)
USE_LIBCRYPT = implicit
USE_LINUX_SPLICE= implicit
USE_LINUX_TPROXY= implicit
USE_ACCEPT4 = implicit
USE_FUTEX = implicit
else
ifeq ($(TARGET),solaris)
@ -439,6 +442,16 @@ OPTIONS_CFLAGS += -DUSE_MY_SPLICE
BUILD_OPTIONS += $(call ignore_implicit,USE_MY_SPLICE)
endif
ifneq ($(USE_ACCEPT4),)
OPTIONS_CFLAGS += -DUSE_ACCEPT4
BUILD_OPTIONS += $(call ignore_implicit,USE_ACCEPT4)
endif
ifneq ($(USE_MY_ACCEPT4),)
OPTIONS_CFLAGS += -DUSE_MY_ACCEPT4
BUILD_OPTIONS += $(call ignore_implicit,USE_MY_ACCEPT4)
endif
ifneq ($(USE_NETFILTER),)
OPTIONS_CFLAGS += -DNETFILTER
BUILD_OPTIONS += $(call ignore_implicit,USE_NETFILTER)

72
include/common/accept4.h Normal file
View File

@ -0,0 +1,72 @@
/*
* include/common/accept4.h
* Definition of the accept4 system call for older Linux libc.
*
* Copyright 2000-2012 Willy Tarreau <w@1wt.eu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, version 2.1
* exclusively.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef _COMMON_ACCEPT4_H
#define _COMMON_ACCEPT4_H
#if defined (__linux__) && defined(USE_ACCEPT4)
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <common/syscall.h>
/* On recent Linux kernels, the accept4() syscall may be used to avoid an fcntl()
* call to set O_NONBLOCK on the resulting socket. It was introduced in Linux
* 2.6.28 and is not present in older libcs.
*/
#ifndef SOCK_NONBLOCK
#define SOCK_NONBLOCK O_NONBLOCK
#endif
#if defined(USE_MY_ACCEPT4) || !defined(SYS_ACCEPT4)
#if defined(CONFIG_HAP_LINUX_VSYSCALL) && defined(__linux__) && defined(__i386__)
/* The syscall is redefined somewhere else */
extern int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
#elif ACCEPT4_USE_SOCKETCALL
static int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)
{
unsigned long args[4];
static _syscall2(int, socketcall, int, call, unsigned long *, args);
args[0] = (unsigned long)sockfd;
args[1] = (unsigned long)addr;
args[2] = (unsigned long)addrlen;
args[3] = (unsigned long)flags;
return socketcall(SYS_ACCEPT4, args);
}
#else
static _syscall4(int, accept4, int, sockfd, struct sockaddr *, addr, socklen_t *, addrlen, int, flags);
#endif /* VSYSCALL etc... */
#endif /* USE_MY_ACCEPT4 */
#endif /* __linux__ && USE_ACCEPT4 */
#endif /* _COMMON_ACCEPT4_H */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*/

View File

@ -2,7 +2,7 @@
* include/common/syscall.h
* Redefinition of some missing OS-specific system calls.
*
* Copyright 2000-2011 Willy Tarreau <w@1wt.eu>
* Copyright 2000-2012 Willy Tarreau <w@1wt.eu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -124,6 +124,21 @@
#endif /* $arch */
#endif /* __NR_splice */
/* accept4() appeared in Linux 2.6.28, but it might not be in all libcs. Some
* archs have it as a native syscall, other ones use the socketcall instead.
*/
#ifndef __NR_accept4
#if defined(__x86_64__)
#define __NR_accept4 288
#elif defined(__sparc__) || defined(__sparc64__)
#define __NR_splice 323
#else
#define ACCEPT4_USE_SOCKETCALL 1
#ifndef SYS_ACCEPT4
#define SYS_ACCEPT4 18
#endif /* SYS_ACCEPT4 */
#endif /* $arch */
#endif /* __NR_accept4 */
#endif /* __linux__ */
#endif /* _COMMON_SYSCALL_H */

View File

@ -120,6 +120,10 @@ asm
" mov $0x05, %eax\n"
" jmp socketcall\n"
"accept4: .GLOBL accept4\n"
" mov $0x12, %eax\n"
" jmp socketcall\n"
"getsockname: .GLOBL getsockname\n"
" mov $0x06, %eax\n"
" jmp socketcall\n"

View File

@ -14,6 +14,7 @@
#include <stdio.h>
#include <string.h>
#include <common/accept4.h>
#include <common/config.h>
#include <common/errors.h>
#include <common/mini-clist.h>
@ -308,7 +309,11 @@ void listener_accept(int fd)
return;
}
#ifdef USE_ACCEPT4
cfd = accept4(fd, (struct sockaddr *)&addr, &laddr, SOCK_NONBLOCK);
#else
cfd = accept(fd, (struct sockaddr *)&addr, &laddr);
#endif
if (unlikely(cfd == -1)) {
switch (errno) {
case EAGAIN:

View File

@ -126,9 +126,13 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
goto out_free_session;
}
/* Adjust some socket options */
#ifndef USE_ACCEPT4
/* Adjust some socket options if the connection was accepted by a plain
* accept() syscall.
*/
if (unlikely(fcntl(cfd, F_SETFL, O_NONBLOCK) == -1))
goto out_free_session;
#endif
/* monitor-net and health mode are processed immediately after TCP
* connection rules. This way it's possible to block them, but they