diff --git a/Makefile b/Makefile index cd6aac942..587b4e098 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ # USE_GETSOCKNAME : enable getsockname() on Linux 2.2. Automatic. # USE_KQUEUE : enable kqueue() on BSD. Automatic. # USE_MY_EPOLL : redefine epoll_* syscalls. Automatic. +# USE_MY_SPLICE : redefine the splice syscall if build fails without. # USE_NETFILTER : enable netfilter on Linux. Automatic. # USE_PCRE : enable use of libpcre for regex. Recommended. # USE_POLL : enable poll(). Automatic. @@ -397,6 +398,11 @@ OPTIONS_CFLAGS += -DCONFIG_HAP_LINUX_VSYSCALL BUILD_OPTIONS += $(call ignore_implicit,USE_VSYSCALL) endif +ifneq ($(USE_MY_SPLICE),) +OPTIONS_CFLAGS += -DUSE_MY_SPLICE +BUILD_OPTIONS += $(call ignore_implicit,USE_MY_SPLICE) +endif + ifneq ($(USE_NETFILTER),) OPTIONS_CFLAGS += -DNETFILTER BUILD_OPTIONS += $(call ignore_implicit,USE_NETFILTER) diff --git a/include/common/epoll.h b/include/common/epoll.h index 10f7fa91f..495323018 100644 --- a/include/common/epoll.h +++ b/include/common/epoll.h @@ -1,23 +1,23 @@ /* - include/common/epoll.h - epoll definitions for older libc. - - Copyright (C) 2000-2006 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 -*/ + * include/common/epoll.h + * epoll definitions for older libc. + * + * Copyright (C) 2000-2011 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 + */ /* * Those constants were found both in glibc and in the Linux kernel. @@ -29,10 +29,18 @@ #ifndef _COMMON_EPOLL_H #define _COMMON_EPOLL_H +#if defined (__linux__) && (defined(ENABLE_EPOLL) || defined(ENABLE_SEPOLL)) + +#ifndef USE_MY_EPOLL +#include <sys/epoll.h> +#else + +#include <errno.h> #include <sys/types.h> #include <linux/unistd.h> - +#include <sys/syscall.h> #include <common/config.h> +#include <common/syscall.h> /* epoll_ctl() commands */ #ifndef EPOLL_CTL_ADD @@ -62,42 +70,34 @@ struct epoll_event { } data; }; - -#if defined(__powerpc__) || defined(__powerpc64__) -#define __NR_epoll_create 236 -#define __NR_epoll_ctl 237 -#define __NR_epoll_wait 238 -#elif defined(__sparc__) || defined(__sparc64__) -#define __NR_epoll_create 193 -#define __NR_epoll_ctl 194 -#define __NR_epoll_wait 195 -#elif defined(__x86_64__) -#define __NR_epoll_create 213 -#define __NR_epoll_ctl 214 -#define __NR_epoll_wait 215 -#elif defined(__alpha__) -#define __NR_epoll_create 407 -#define __NR_epoll_ctl 408 -#define __NR_epoll_wait 409 -#elif defined (__i386__) -#define __NR_epoll_create 254 -#define __NR_epoll_ctl 255 -#define __NR_epoll_wait 256 +#if defined(CONFIG_HAP_LINUX_VSYSCALL) && defined(__linux__) && defined(__i386__) +/* Those are our self-defined functions */ +extern int epoll_create(int size); +extern int epoll_ctl(int epfd, int op, int fd, struct epoll_event * event); +extern int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); #else + +/* We'll define a syscall, so for this we need __NR_splice. It should have + * been provided by syscall.h. + */ +#if !defined(__NR_epoll_ctl) #warning unsupported architecture, guessing __NR_epoll_create=254 like x86... #define __NR_epoll_create 254 #define __NR_epoll_ctl 255 #define __NR_epoll_wait 256 -#endif +#endif /* __NR_epoll_ctl */ -/* Those are our self-defined functions */ -static int epoll_create(int size); -static int epoll_ctl(int epfd, int op, int fd, struct epoll_event * event); -static int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); +static inline _syscall1 (int, epoll_create, int, size); +static inline _syscall4 (int, epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event *, event); +static inline _syscall4 (int, epoll_wait, int, epfd, struct epoll_event *, events, int, maxevents, int, timeout); +#endif /* VSYSCALL */ + +#endif /* USE_MY_EPOLL */ + +#endif /* __linux__ && (ENABLE_EPOLL || ENABLE_SEPOLL) */ #endif /* _COMMON_EPOLL_H */ - /* * Local variables: * c-indent-level: 8 diff --git a/include/common/splice.h b/include/common/splice.h new file mode 100644 index 000000000..a776b9b7c --- /dev/null +++ b/include/common/splice.h @@ -0,0 +1,83 @@ +/* + * include/common/splice.h + * Splice definition for older Linux libc. + * + * Copyright 2000-2011 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_SPLICE_H +#define _COMMON_SPLICE_H + +#if defined (__linux__) && defined(CONFIG_HAP_LINUX_SPLICE) + +#include <errno.h> +#include <unistd.h> +#include <sys/syscall.h> +#include <common/syscall.h> + +/* On recent Linux kernels, the splice() syscall may be used for faster data copy. + * But it's not always defined on some OS versions, and it even happens that some + * definitions are wrong with some glibc due to an offset bug in syscall(). + */ + +#ifndef SPLICE_F_MOVE +#define SPLICE_F_MOVE 0x1 +#endif + +#ifndef SPLICE_F_NONBLOCK +#define SPLICE_F_NONBLOCK 0x2 +#endif + +#ifndef SPLICE_F_MORE +#define SPLICE_F_MORE 0x4 +#endif + +#if defined(USE_MY_SPLICE) + +#if defined(CONFIG_HAP_LINUX_VSYSCALL) && defined(__linux__) && defined(__i386__) +/* The syscall is redefined somewhere else */ +extern int splice(int fdin, loff_t *off_in, int fdout, loff_t *off_out, size_t len, unsigned long flags); +#else + +/* We'll define a syscall, so for this we need __NR_splice. It should have + * been provided by syscall.h. + */ +#ifndef __NR_splice +#warning unsupported architecture, guessing __NR_splice=313 like x86... +#define __NR_splice 313 +#endif /* __NR_splice */ + +static _syscall6(int, splice, int, fdin, loff_t *, off_in, int, fdout, loff_t *, off_out, size_t, len, unsigned long, flags); +#endif /* VSYSCALL */ + +#else +/* use the system's definition */ +#include <fcntl.h> + +#endif /* USE_MY_SPLICE */ + +#endif /* __linux__ && CONFIG_HAP_LINUX_SPLICE */ + +#endif /* _COMMON_SPLICE_H */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */ diff --git a/include/common/syscall.h b/include/common/syscall.h new file mode 100644 index 000000000..a3b27eb16 --- /dev/null +++ b/include/common/syscall.h @@ -0,0 +1,136 @@ +/* + * include/common/syscall.h + * Redefinition of some missing OS-specific system calls. + * + * Copyright 2000-2011 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_SYSCALL_H +#define _COMMON_SYSCALL_H + +#ifdef __linux__ + +#include <errno.h> +#include <unistd.h> +#include <sys/syscall.h> + +/* On Linux, _syscall macros were removed after 2.6.18, but we still prefer + * them because syscall() is buggy on old libcs. If _syscall is not defined, + * we're on a recent kernel with a recent libc and we should be safe, so we + * emulate is using syscall(). + */ +#ifndef _syscall1 +#define _syscall1(tr, nr, t1, n1) \ + inline tr nr(t1 n1) { \ + return syscall(__NR_##nr, n1); \ + } +#endif + +#ifndef _syscall2 +#define _syscall2(tr, nr, t1, n1, t2, n2) \ + inline tr nr(t1 n1, t2 n2) { \ + return syscall(__NR_##nr, n1, n2); \ + } +#endif + +#ifndef _syscall3 +#define _syscall3(tr, nr, t1, n1, t2, n2, t3, n3) \ + inline tr nr(t1 n1, t2 n2, t3 n3) { \ + return syscall(__NR_##nr, n1, n2, n3); \ + } +#endif + +#ifndef _syscall4 +#define _syscall4(tr, nr, t1, n1, t2, n2, t3, n3, t4, n4) \ + inline tr nr(t1 n1, t2 n2, t3 n3, t4 n4) { \ + return syscall(__NR_##nr, n1, n2, n3, n4); \ + } +#endif + +#ifndef _syscall5 +#define _syscall5(tr, nr, t1, n1, t2, n2, t3, n3, t4, n4, t5, n5) \ + inline tr nr(t1 n1, t2 n2, t3 n3, t4 n4, t5 n5) { \ + return syscall(__NR_##nr, n1, n2, n3, n4, n5); \ + } +#endif + +#ifndef _syscall6 +#define _syscall6(tr, nr, t1, n1, t2, n2, t3, n3, t4, n4, t5, n5, t6, n6) \ + inline tr nr(t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6) { \ + return syscall(__NR_##nr, n1, n2, n3, n4, n5, n6); \ + } +#endif + + +/* Define some syscall numbers that are sometimes needed */ + +/* Epoll was provided as a patch for 2.4 for a long time and was not always + * exported as a known sysctl number by libc. + */ +#if !defined(__NR_epoll_ctl) +#if defined(__powerpc__) || defined(__powerpc64__) +#define __NR_epoll_create 236 +#define __NR_epoll_ctl 237 +#define __NR_epoll_wait 238 +#elif defined(__sparc__) || defined(__sparc64__) +#define __NR_epoll_create 193 +#define __NR_epoll_ctl 194 +#define __NR_epoll_wait 195 +#elif defined(__x86_64__) +#define __NR_epoll_create 213 +#define __NR_epoll_ctl 214 +#define __NR_epoll_wait 215 +#elif defined(__alpha__) +#define __NR_epoll_create 407 +#define __NR_epoll_ctl 408 +#define __NR_epoll_wait 409 +#elif defined (__i386__) +#define __NR_epoll_create 254 +#define __NR_epoll_ctl 255 +#define __NR_epoll_wait 256 +#endif /* $arch */ +#endif /* __NR_epoll_ctl */ + +/* splice is even more recent than epoll. It appeared around 2.6.18 but was + * not in libc for a while. + */ +#ifndef __NR_splice +#if defined(__powerpc__) || defined(__powerpc64__) +#define __NR_splice 283 +#elif defined(__sparc__) || defined(__sparc64__) +#define __NR_splice 232 +#elif defined(__x86_64__) +#define __NR_splice 275 +#elif defined(__alpha__) +#define __NR_splice 468 +#elif defined (__i386__) +#define __NR_splice 313 +#endif /* $arch */ +#endif /* __NR_splice */ + + +#endif /* __linux__ */ +#endif /* _COMMON_SYSCALL_H */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */ diff --git a/src/ev_epoll.c b/src/ev_epoll.c index b976868ea..958c4e68f 100644 --- a/src/ev_epoll.c +++ b/src/ev_epoll.c @@ -1,7 +1,7 @@ /* * FD polling functions for linux epoll() * - * Copyright 2000-2008 Willy Tarreau <w@1wt.eu> + * Copyright 2000-2011 Willy Tarreau <w@1wt.eu> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -16,6 +16,7 @@ #include <common/compat.h> #include <common/config.h> +#include <common/epoll.h> #include <common/standard.h> #include <common/ticks.h> #include <common/time.h> @@ -27,17 +28,6 @@ #include <proto/signal.h> #include <proto/task.h> -#if defined(USE_MY_EPOLL) -#include <common/epoll.h> -#include <errno.h> -#include <sys/syscall.h> -static _syscall1 (int, epoll_create, int, size); -static _syscall4 (int, epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event *, event); -static _syscall4 (int, epoll_wait, int, epfd, struct epoll_event *, events, int, maxevents, int, timeout); -#else -#include <sys/epoll.h> -#endif - /* This is what we store in a list. It consists in old values and fds to detect changes. */ struct fd_chg { unsigned int prev:2; // previous state mask. New one is in fd_evts. diff --git a/src/ev_sepoll.c b/src/ev_sepoll.c index 248f1f4c7..c9c597877 100644 --- a/src/ev_sepoll.c +++ b/src/ev_sepoll.c @@ -1,7 +1,7 @@ /* * FD polling functions for Speculative I/O combined with Linux epoll() * - * Copyright 2000-2009 Willy Tarreau <w@1wt.eu> + * Copyright 2000-2011 Willy Tarreau <w@1wt.eu> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -51,6 +51,7 @@ #include <common/compat.h> #include <common/config.h> #include <common/debug.h> +#include <common/epoll.h> #include <common/standard.h> #include <common/ticks.h> #include <common/time.h> @@ -62,17 +63,6 @@ #include <proto/signal.h> #include <proto/task.h> -#if defined(USE_MY_EPOLL) -#include <common/epoll.h> -#include <errno.h> -#include <sys/syscall.h> -static _syscall1 (int, epoll_create, int, size); -static _syscall4 (int, epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event *, event); -static _syscall4 (int, epoll_wait, int, epfd, struct epoll_event *, events, int, maxevents, int, timeout); -#else -#include <sys/epoll.h> -#endif - /* * We define 4 states for each direction of a file descriptor, which we store * as 2 bits : diff --git a/src/stream_sock.c b/src/stream_sock.c index 61947ebfa..11e74fdbb 100644 --- a/src/stream_sock.c +++ b/src/stream_sock.c @@ -41,50 +41,8 @@ #include <types/global.h> -/* On recent Linux kernels, the splice() syscall may be used for faster data copy. - * But it's not always defined on some OS versions, and it even happens that some - * definitions are wrong with some glibc due to an offset bug in syscall(). - */ - #if defined(CONFIG_HAP_LINUX_SPLICE) -#include <unistd.h> -#include <sys/syscall.h> - -#ifndef SPLICE_F_MOVE -#define SPLICE_F_MOVE 0x1 -#endif - -#ifndef SPLICE_F_NONBLOCK -#define SPLICE_F_NONBLOCK 0x2 -#endif - -#ifndef SPLICE_F_MORE -#define SPLICE_F_MORE 0x4 -#endif - -#ifndef __NR_splice -#if defined(__powerpc__) || defined(__powerpc64__) -#define __NR_splice 283 -#elif defined(__sparc__) || defined(__sparc64__) -#define __NR_splice 232 -#elif defined(__x86_64__) -#define __NR_splice 275 -#elif defined(__alpha__) -#define __NR_splice 468 -#elif defined (__i386__) -#define __NR_splice 313 -#else -#warning unsupported architecture, guessing __NR_splice=313 like x86... -#define __NR_splice 313 -#endif /* $arch */ - -#if defined(CONFIG_HAP_LINUX_VSYSCALL) && defined(__linux__) && defined(__i386__) -/* the syscall is redefined somewhere else */ -extern int splice(int fdin, loff_t *off_in, int fdout, loff_t *off_out, size_t len, unsigned long flags); -#else -_syscall6(int, splice, int, fdin, loff_t *, off_in, int, fdout, loff_t *, off_out, size_t, len, unsigned long, flags) -#endif -#endif /* __NR_splice */ +#include <common/splice.h> /* A pipe contains 16 segments max, and it's common to see segments of 1448 bytes * because of timestamps. Use this as a hint for not looping on splice().