[REORG] build: move syscall redefinition to specific places

Some older libc don't define splice() and and don't define _syscall*()
either, which causes build errors if splicing is enabled.

To solve this, we now split the syscall redefinition into two layers :
  - one file per syscall (epoll, splice)
  - one common file to declare the _syscall*() macros

The code is cleaner because files using the syscalls just have to include
their respective file. It's not adviced to merge multiple syscall families
into a same file if all are not intended to be used simultaneously, because
defining unused static functions causes warnings to be emitted during build.

As a result, the new USE_MY_SPLICE parameter was added in order to be able
to define the splice() syscall separately.
This commit is contained in:
Willy Tarreau 2011-08-22 17:12:02 +02:00
parent 87cf51406c
commit 43d8fb2d3a
7 changed files with 277 additions and 114 deletions

View File

@ -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)

View File

@ -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

83
include/common/splice.h Normal file
View File

@ -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:
*/

136
include/common/syscall.h Normal file
View File

@ -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:
*/

View File

@ -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.

View File

@ -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 :

View File

@ -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().