Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/configure.ac b/configure.ac
index ccd2ab8..c8f5e41 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,620 +1,624 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.61])
AC_INIT([libqb],
m4_esyscmd([build-aux/git-version-gen .tarball-version]),
[quarterback-devel@fedorahosted.org])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_SRCDIR([lib/ringbuffer.c])
AC_CONFIG_HEADERS([include/config.h include/qb/qbconfig.h])
AC_USE_SYSTEM_EXTENSIONS
AM_INIT_AUTOMAKE([-Wno-portability dist-xz])
dnl automake >= 1.11 offers --enable-silent-rules for suppressing the output from
dnl normal compilation. When a failure occurs, it will then display the full
dnl command line
dnl Wrap in m4_ifdef to avoid breaking on older platforms
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
LT_PREREQ([2.2.6])
LT_INIT
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_HOST
AC_PROG_LIBTOOL
AC_LANG([C])
dnl Fix default variables - "prefix" variable if not specified
if test "$prefix" = "NONE"; then
prefix="/usr"
if test "$localstatedir" = "\${prefix}/var"; then
localstatedir="/var"
fi
if test "$sysconfdir" = "\${prefix}/etc"; then
sysconfdir="/etc"
fi
if test "$libdir" = "\${exec_prefix}/lib"; then
if test -e /usr/lib64; then
libdir="/usr/lib64"
else
libdir="/usr/lib"
fi
fi
fi
if test "$srcdir" = "."; then
AC_MSG_NOTICE([building in place srcdir:$srcdir])
AC_DEFINE([BUILDING_IN_PLACE], 1, [building in place])
else
AC_MSG_NOTICE([building out of tree srcdir:$srcdir])
fi
# Checks for programs.
# check stolen from gnulib/m4/gnu-make.m4
if ! ${MAKE-make} --version /cannot/make/this >/dev/null 2>&1; then
AC_MSG_ERROR([you don't seem to have GNU make; it is required])
fi
AC_PROG_CXX
AC_PROG_AWK
AC_PROG_CC
AC_PROG_CPP
AM_PROG_CC_C_O
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_CHECK_PROGS([PKGCONFIG], [pkg-config])
AC_CHECK_PROGS([DOXYGEN], [doxygen])
AM_CONDITIONAL(HAVE_DOXYGEN, test -n "${DOXYGEN}")
AC_CHECK_PROGS([SPLINT], [splint])
AM_CONDITIONAL(HAVE_SPLINT, test -n "${SPLINT}")
## local helper functions
# this function checks if CC support options passed as
# args. Global CFLAGS are ignored during this test.
cc_supports_flag() {
BACKUP="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $@ -Werror"
AC_MSG_CHECKING([whether $CC supports "$@"])
AC_PREPROC_IFELSE([AC_LANG_PROGRAM([])],
[RC=0; AC_MSG_RESULT([yes])],
[RC=1; AC_MSG_RESULT([no])])
CPPFLAGS="$BACKUP"
return $RC
}
## cleanup
AC_MSG_NOTICE(Sanitizing prefix: ${prefix})
case $prefix in
NONE) prefix=/usr/local;;
esac
AC_MSG_NOTICE(Sanitizing exec_prefix: ${exec_prefix})
case $exec_prefix in
NONE) exec_prefix=$prefix;;
prefix) exec_prefix=$prefix;;
esac
# Checks for libraries.
dnl librt from glibc NEEDs libpthread
dnl so. if test for libpthread after librt
dnl it will always be "none needed", but it is not true
dnl when linking libraries. Looks like a bug.
AC_SEARCH_LIBS([pthread_create], [pthread])
AC_SEARCH_LIBS([mq_open], [rt])
AC_SEARCH_LIBS([dlopen], [dl])
AC_SEARCH_LIBS([socket], [socket])
AC_SEARCH_LIBS([gethostbyname], [nsl])
# look for testing harness "check"
PKG_CHECK_MODULES([CHECK], [check >= 0.9.4],[with_check=yes],[with_check=no])
AM_CONDITIONAL(HAVE_CHECK, test "${with_check}" = "yes")
# look for GLIB (used for testing integration)
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.0, have_glib=yes, have_glib=no)
AM_CONDITIONAL(HAVE_GLIB, test x$have_glib = xyes)
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
if test x"$have_glib" = xyes; then
AC_DEFINE_UNQUOTED([HAVE_GLIB], [1], [We have glib])
fi
# Checks for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS([arpa/inet.h link.h fcntl.h inttypes.h limits.h netinet/in.h \
stdint.h stddef.h stdlib.h string.h strings.h \
dlfcn.h time.h sys/time.h sys/types.h sys/stat.h \
sys/param.h sys/socket.h sys/time.h sys/poll.h sys/epoll.h \
sys/uio.h sys/event.h sys/sockio.h sys/un.h sys/resource.h \
syslog.h errno.h unistd.h sys/mman.h \
sys/sem.h sys/ipc.h sys/msg.h netdb.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_UID_T
AC_C_INLINE
AC_TYPE_INT32_T
AC_TYPE_INT64_T
AC_TYPE_INT8_T
AC_TYPE_MODE_T
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_TYPE_SSIZE_T
AC_TYPE_UINT64_T
AC_TYPE_UINT32_T
AC_TYPE_UINT16_T
AC_TYPE_UINT8_T
AC_CHECK_MEMBER([struct sockaddr_un.sun_len],
[AC_DEFINE([HAVE_STRUCT_SOCKADDR_UN_SUN_LEN],
1,
[Define to 1 if struct sockaddr_un has a member sun_len])],
[],
[#include <sys/un.h>])
AC_MSG_CHECKING(looking for union semun in sys/sem.h)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
[[#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>]],
[[union semun arg; semctl(0, 0, 0, arg);]])],
[
AC_MSG_RESULT([yes])
AC_DEFINE_UNQUOTED([HAVE_SEMUN], 1, [Define to 1 if you have union semun.])
],
[
AC_MSG_RESULT([no])
]
)
AC_MSG_CHECKING(for MSG_NOSIGNAL)
AC_TRY_COMPILE([#include <sys/socket.h>],
[ int f = MSG_NOSIGNAL; ],
[ AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_MSG_NOSIGNAL, 1,
[Define this symbol if you have MSG_NOSIGNAL])],
[ AC_MSG_RESULT(no)])
AC_MSG_CHECKING(for SO_NOSIGPIPE )
AC_TRY_COMPILE([#include <sys/socket.h>],
[ int f = SO_NOSIGPIPE; ],
[ AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_SO_NOSIGPIPE, 1,
[Define this symbol if you have SO_NOSIGPIPE]) ],
[ AC_MSG_RESULT(no)])
# Checks for library functions.
AC_FUNC_CHOWN
AC_FUNC_FORK
AC_FUNC_MMAP
AC_FUNC_STRERROR_R
AC_CHECK_FUNCS([alarm clock_gettime ftruncate gettimeofday \
localtime localtime_r memset munmap socket \
strchr strrchr strdup strstr strcasecmp \
poll epoll_create epoll_create1 kqueue \
random rand getrlimit sysconf \
pthread_spin_lock pthread_setschedparam \
pthread_mutexattr_setpshared \
pthread_condattr_setpshared \
sem_timedwait semtimedop \
sched_get_priority_max sched_setscheduler \
getpeerucred getpeereid])
AM_CONDITIONAL(HAVE_SEM_TIMEDWAIT,
[test "x$ac_cv_func_sem_timedwait" = xyes])
AM_CONDITIONAL(HAVE_EPOLL,
[test "x$ac_cv_func_epoll_create" = xyes])
AM_CONDITIONAL(HAVE_POLL,
[test "x$ac_cv_func_poll" = xyes])
AM_CONDITIONAL(HAVE_KQUEUE,
[test "x$ac_cv_func_kqueue" = xyes])
AC_CONFIG_LIBOBJ_DIR(lib)
AC_REPLACE_FUNCS(strlcpy strlcat strchrnul)
## local defines
PACKAGE_FEATURES=""
if test x$ac_cv_func_epoll_create = xyes; then
PACKAGE_FEATURES="$PACKAGE_FEATURES epoll"
fi
nongcc_memory_barrier_needed=no
arch_force_shmlba=no
AC_MSG_CHECKING([for architecture in ${host_cpu}])
case $host_cpu in
sparc*)
AC_MSG_RESULT([sparc])
AC_DEFINE_UNQUOTED([QB_ARCH_SPARC], [1], [sparc])
nongcc_memory_barrier_needed=yes
arch_force_shmlba=yes
;;
alpha*)
AC_MSG_RESULT([alpha])
AC_DEFINE_UNQUOTED([QB_ARCH_ALPHA], [1], [alpha])
nongcc_memory_barrier_needed=yes
;;
powerpc*)
AC_MSG_RESULT([powerpc])
AC_DEFINE_UNQUOTED([QB_ARCH_POWERPC], [1], [powerpc])
ac_cv_link_attribute_section=no
nongcc_memory_barrier_needed=yes
arch_force_shmlba=yes
;;
ia64)
AC_MSG_RESULT([ia64])
AC_DEFINE_UNQUOTED([QB_ARCH_IA64], [1], [ia64])
nongcc_memory_barrier_needed=yes
;;
arm*)
- AC_MSG_RESULT([ia64])
+ AC_MSG_RESULT([arm])
AC_DEFINE_UNQUOTED([QB_ARCH_ARM], [1], [arm])
arch_force_shmlba=yes
;;
+ hppa*)
+ AC_MSG_RESULT([hppa])
+ AC_DEFINE_UNQUOTED([QB_ARCH_HPPA], [1], [hppa])
+ ;;
mips*)
AC_MSG_RESULT([ia64])
AC_DEFINE_UNQUOTED([QB_ARCH_MIPS], [1], [mips])
arch_force_shmlba=yes
;;
*)
AC_MSG_RESULT([${host_cpu}])
;;
esac
if test $arch_force_shmlba = yes; then
AC_DEFINE_UNQUOTED([QB_FORCE_SHM_ALIGN], [1],
[shared and fixed mmap must align on 16k])
fi
# OS detection
# THIS SECTION MUST DIE!
CP=cp
AC_MSG_CHECKING([for os in ${host_os}])
case "$host_os" in
*linux*)
AC_DEFINE_UNQUOTED([QB_LINUX], [1],
[Compiling for Linux platform])
AC_MSG_RESULT([Linux])
;;
*cygwin*)
AC_DEFINE_UNQUOTED([QB_CYGWIN], [1],
[Compiling for Cygwin platform])
ac_cv_link_attribute_section=no
nongcc_memory_barrier_needed=yes
gcc_has_builtin_sync_operations=no
AC_MSG_RESULT([Cygwin])
;;
darwin*)
AC_DEFINE_UNQUOTED([QB_DARWIN], [1],
[Compiling for Darwin platform])
CP=rsync
ac_cv_link_attribute_section=no
dnl Attribute section appears to work here but fails later with:
dnl cc1: error in backend: Global variable 'descriptor.4902'
dnl has an invalid section specifier '__verbose': mach-o
dnl section specifier requires a segment and section
dnl separated by a comma
AC_DEFINE_UNQUOTED([DISABLE_POSIX_THREAD_PROCESS_SHARED], [1],
[Disable _POSIX_THREAD_PROCESS_SHARED])
AC_MSG_RESULT([Darwin])
;;
*bsd*)
AC_DEFINE_UNQUOTED([QB_BSD], [1],
[Compiling for BSD platform])
case "$host_os" in
*freebsd[[234567]]*)
;;
*freebsd*)
AC_DEFINE_UNQUOTED([QB_FREEBSD_GE_8], [1],
[Compiling for FreeBSD >= 8 platform])
;;
*netbsd*)
# this is because dlopen within a dl_iterate_phdr
# callback locks up.
ac_cv_link_attribute_section=no
AC_DEFINE_UNQUOTED([UNIX_PATH_MAX], [103],
[Unix path length])
;;
*openbsd*)
AC_DEFINE_UNQUOTED([UNIX_PATH_MAX], [104],
[Unix path length])
;;
esac
AC_MSG_RESULT([BSD])
;;
*solaris*)
ac_cv_link_attribute_section=no
AC_DEFINE_UNQUOTED(DISABLE_IPC_SHM, 1,
[Disable shared mem ipc])
AC_DEFINE_UNQUOTED([QB_SOLARIS], [1],
[Compiling for Solaris platform])
CP=rsync
AC_MSG_RESULT([Solaris])
;;
*)
AC_MSG_ERROR([Unsupported OS? hmmmm])
;;
esac
AC_MSG_CHECKING([whether GCC supports builtin sync intrinsics])
if test -z "$gcc_has_builtin_sync_operations"; then
gcc_has_builtin_sync_operations=no
if test x"$GCC" = xyes && test x$have_mingw != xyes; then
AC_TRY_LINK([],
[int i;
__sync_synchronize ();
__sync_bool_compare_and_swap (&i, 0, 1);
__sync_fetch_and_add (&i, 1);
],
[gcc_has_builtin_sync_operations=yes],
[gcc_has_builtin_sync_operations=no])
fi
fi
AC_MSG_RESULT($gcc_has_builtin_sync_operations)
AM_CONDITIONAL(HAVE_GCC_BUILTINS_FOR_SYNC_OPERATIONS,
[test "x$gcc_has_builtin_sync_operations" = xyes])
if test "x$gcc_has_builtin_sync_operations" = xyes; then
AC_DEFINE_UNQUOTED(HAVE_GCC_BUILTINS_FOR_SYNC_OPERATIONS, 1,
[have builtin sync operations])
fi
# __atomic_XXX
AC_MSG_CHECKING([whether GCC supports builtin atomic intrinsics])
if test -z "$gcc_has_builtin_atomic_operations"; then
gcc_has_builtin_atomic_operations=no
if test x"$GCC" = xyes && test x$have_mingw != xyes; then
AC_TRY_LINK([],
[int i;
__atomic_load_n(&i, __ATOMIC_ACQUIRE);
__atomic_exchange_n(&i, 0, __ATOMIC_RELEASE);
],
[gcc_has_builtin_atomic_operations=yes],
[gcc_has_builtin_atomic_operations=no])
fi
fi
AC_MSG_RESULT($gcc_has_builtin_atomic_operations)
AM_CONDITIONAL(HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS,
[test "x$gcc_has_builtin_atomic_operations" = xyes])
if test "x$gcc_has_builtin_atomic_operations" = xyes; then
AC_DEFINE_UNQUOTED(HAVE_GCC_BUILTINS_FOR_ATOMIC_OPERATIONS, 1,
[have builtin atomic operations])
fi
AC_MSG_CHECKING([whether atomics need memory barrier])
if test -n "$ac_cv_atomic_need_memory_barrier"; then
memory_barrier_needed=$ac_cv_atomic_need_memory_barrier
else
if test x$gcc_has_builtin_sync_operations = xyes; then
memory_barrier_needed=yes
PACKAGE_FEATURES="$PACKAGE_FEATURES gcc__sync"
else
memory_barrier_needed=$nongcc_memory_barrier_needed
AC_MSG_WARN([-----------------------------])
AC_MSG_WARN([You have gcc but not __sync_bool_compare_and_swap])
AC_MSG_WARN([try CFLAGS="-march=<your arch> -mtune=native" ./configure])
AC_MSG_WARN([-----------------------------])
fi
fi
AC_MSG_RESULT($memory_barrier_needed)
if test x"$memory_barrier_needed" != xno; then
AC_DEFINE_UNQUOTED(QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED, 1,
[need atomic memory barrier])
fi
LINT_FLAGS="-syntax -weak -unrecog +posixlib +ignoresigns -fcnuse \
-badflag -D__gnuc_va_list=va_list -D__attribute\(x\)= \
-warnposix +matchanyintegral -sysunrecog"
# local options
AC_ARG_ENABLE([ansi],
[ --enable-ansi : force to build with ANSI standards. ],
[ default="no" ])
AC_ARG_ENABLE([fatal-warnings],
[ --enable-fatal-warnings : enable fatal warnings. ],
[ default="no" ])
AC_ARG_ENABLE([debug],
[ --enable-debug : enable debug build. ],
[ default="no" ])
AC_ARG_ENABLE([coverage],
[ --enable-coverage : coverage analysis of the codebase. ],
[ default="no" ])
AC_ARG_ENABLE([slow-tests],
[ --enable-slow-tests : build and run slow tests. ],
[ default="no" ])
AC_ARG_WITH([socket-dir],
[ --with-socket-dir=DIR : socket dir. ],
[ SOCKETDIR="$withval" ],
[ SOCKETDIR="$localstatedir/run" ])
AC_SUBST(CP)
# *FLAGS handling goes here
ENV_CFLAGS="$CFLAGS"
ENV_CPPFLAGS="$CPPFLAGS"
ENV_LDFLAGS="$LDFLAGS"
# debug build stuff
if test "x${enable_debug}" = xyes; then
AC_DEFINE_UNQUOTED([DEBUG], [1], [Compiling Debugging code])
OPT_CFLAGS="-O0"
if test "x${GCC}" = xyes; then
GDB_FLAGS="-ggdb3"
else
GDB_FLAGS="-g"
fi
PACKAGE_FEATURES="$PACKAGE_FEATURES debug"
fi
# extra warnings
EXTRA_WARNINGS=""
WARNLIST="
all
shadow
missing-prototypes
missing-declarations
strict-prototypes
declaration-after-statement
pointer-arith
write-strings
cast-align
bad-function-cast
missing-format-attribute
format=2
format-security
no-format-nonliteral
no-long-long
unsigned-char
gnu89-inline
no-strict-aliasing
"
for j in $WARNLIST; do
if cc_supports_flag -W$j; then
EXTRA_WARNINGS="$EXTRA_WARNINGS -W$j";
fi
done
# --- coverage ---
if test "x${enable_coverage}" = xyes && \
cc_supports_flag -ftest-coverage && \
cc_supports_flag -fprofile-arcs ; then
AC_MSG_NOTICE([Enabling Coverage (enable -O0 by default)])
OPT_CFLAGS="-O0"
COVERAGE_CFLAGS="-ftest-coverage -fprofile-arcs"
COVERAGE_LDFLAGS="-ftest-coverage -fprofile-arcs"
PACKAGE_FEATURES="$PACKAGE_FEATURES coverage"
else
COVERAGE_CFLAGS=""
COVERAGE_LDFLAGS=""
fi
if test "x${enable_slow_tests}" = xyes ; then
AC_DEFINE([HAVE_SLOW_TESTS], 1,[have slow tests])
AC_MSG_NOTICE([Enabling Slow tests])
fi
AM_CONDITIONAL(HAVE_SLOW_TESTS, [test "x${enable_slow_tests}" = xyes])
AC_SUBST(HAVE_SLOW_TESTS)
# --- callsite sections ---
if test "x${GCC}" = xyes; then
AC_MSG_CHECKING([whether GCC supports __attribute__((section())])
if test "x${ac_cv_link_attribute_section}" = x ; then
AC_TRY_LINK([],
[static int my_var __attribute__((section("__verbose"))) = 5;
if (my_var == 5) return 0;
else return -1;
],
[gcc_has_attribute_section=yes],
[gcc_has_attribute_section=no])
else
gcc_has_attribute_section=${ac_cv_link_attribute_section}
fi
AC_MSG_RESULT($gcc_has_attribute_section)
if test $gcc_has_attribute_section = yes; then
AC_DEFINE([QB_HAVE_ATTRIBUTE_SECTION], 1,
[Enabling code using __attribute__((section))])
PACKAGE_FEATURES="$PACKAGE_FEATURES attribute-section"
fi
fi
# --- ansi ---
if test "x${enable_ansi}" = xyes && \
cc_supports_flag -std=iso9899:199409 ; then
AC_MSG_NOTICE([Enabling ANSI Compatibility])
ANSI_CPPFLAGS="-ansi -D_GNU_SOURCE -DANSI_ONLY"
PACKAGE_FEATURES="$PACKAGE_FEATURES ansi"
else
ANSI_CPPFLAGS=""
fi
# --- fatal warnings ---
if test "x${enable_fatal_warnings}" = xyes && \
cc_supports_flag -Werror ; then
AC_MSG_NOTICE([Enabling Fatal Warnings (-Werror)])
WERROR_CFLAGS="-Werror"
PACKAGE_FEATURES="$PACKAGE_FEATURES fatal-warnings"
else
WERROR_CFLAGS=""
fi
# final build of *FLAGS
CFLAGS="$ENV_CFLAGS $OPT_CFLAGS $GDB_FLAGS \
$COVERAGE_CFLAGS $EXTRA_WARNINGS $WERROR_CFLAGS"
CPPFLAGS="$ENV_CPPFLAGS $ANSI_CPPFLAGS"
LDFLAGS="$ENV_LDFLAGS $COVERAGE_LDFLAGS"
if test -f /usr/share/dict/words ; then
HAVE_DICT_WORDS=yes
AC_DEFINE([HAVE_DICT_WORDS], 1, "Have /usr/share/dict/words")
fi
AM_CONDITIONAL([HAVE_DICT_WORDS], [test "x$HAVE_DICT_WORDS" = xyes])
# substitute what we need:
AC_SUBST([SOCKETDIR])
AC_SUBST([LINT_FLAGS])
AC_DEFINE_UNQUOTED([SOCKETDIR], "$(eval echo ${SOCKETDIR})", [Socket directory])
AC_DEFINE_UNQUOTED([LOCALSTATEDIR], "$(eval echo ${localstatedir})", [localstate directory])
AC_DEFINE_UNQUOTED([PACKAGE_FEATURES], "${PACKAGE_FEATURES}", [quarterback built-in features])
AC_CONFIG_FILES([Makefile
include/Makefile
include/qb/Makefile
lib/Makefile
lib/libqb.pc
tools/Makefile
tests/Makefile
tests/test.conf
examples/Makefile
docs/Makefile
docs/man.dox
docs/html.dox])
AC_OUTPUT
AC_MSG_RESULT([])
AC_MSG_RESULT([$PACKAGE configuration:])
AC_MSG_RESULT([ Version = ${VERSION}])
AC_MSG_RESULT([ Prefix = ${prefix}])
AC_MSG_RESULT([ Executables = ${sbindir}])
AC_MSG_RESULT([ Man pages = ${mandir}])
AC_MSG_RESULT([ Doc dir = ${docdir}])
AC_MSG_RESULT([ Libraries = ${libdir}])
AC_MSG_RESULT([ Header files = ${includedir}])
AC_MSG_RESULT([ Arch-independent files = ${datadir}])
AC_MSG_RESULT([ State information = ${localstatedir}])
AC_MSG_RESULT([ System configuration = ${sysconfdir}])
AC_MSG_RESULT([ SOCKETDIR = ${SOCKETDIR}])
AC_MSG_RESULT([ Features =${PACKAGE_FEATURES}])
AC_MSG_RESULT([])
AC_MSG_RESULT([$PACKAGE build info:])
AC_MSG_RESULT([ Optimization = ${OPT_CFLAGS}])
AC_MSG_RESULT([ Debug options = ${GDB_CFLAGS}])
AC_MSG_RESULT([ Extra compiler warnings = ${EXTRA_WARNING}])
AC_MSG_RESULT([ Env. defined CFLAG = ${ENV_CFLAGS}])
AC_MSG_RESULT([ Env. defined CPPFLAGS = ${ENV_CPPFLAGS}])
AC_MSG_RESULT([ Env. defined LDFLAGS = ${ENV_LDFLAGS}])
AC_MSG_RESULT([ ANSI defined CPPFLAGS = ${ANSI_CPPFLAGS}])
AC_MSG_RESULT([ Coverage CFLAGS = ${COVERAGE_CFLAGS}])
AC_MSG_RESULT([ Coverage LDFLAGS = ${COVERAGE_LDFLAGS}])
AC_MSG_RESULT([ Fatal War. CFLAGS = ${WERROR_CFLAGS}])
AC_MSG_RESULT([ Final CFLAGS = ${CFLAGS}])
AC_MSG_RESULT([ Final CPPFLAGS = ${CPPFLAGS}])
AC_MSG_RESULT([ Final LDFLAGS = ${LDFLAGS}])
diff --git a/lib/ringbuffer.c b/lib/ringbuffer.c
index f6b1971..db842ce 100644
--- a/lib/ringbuffer.c
+++ b/lib/ringbuffer.c
@@ -1,960 +1,962 @@
/*
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* Author: Angus Salkeld <asalkeld@redhat.com>
*
* This file is part of libqb.
*
* libqb 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, either version 2.1 of the License, or
* (at your option) any later version.
*
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ringbuffer_int.h"
#include <qb/qbdefs.h>
#include "atomic_int.h"
#define QB_RB_FILE_HEADER_VERSION 1
/*
* #define CRAZY_DEBUG_PRINTFS 1
*/
#ifdef CRAZY_DEBUG_PRINTFS
#define DEBUG_PRINTF(format, args...) \
do { \
printf(format, ##args); \
} while(0)
#else
#define DEBUG_PRINTF(format, args...)
#endif /* CRAZY_DEBUG_PRINTFS */
/*
* move the write pointer to the next 128 byte boundary
* write_pt goes in 4 bytes (sizeof(uint32_t))
* #define USE_CACHE_LINE_ALIGNMENT 1
*/
#ifdef USE_CACHE_LINE_ALIGNMENT
#define QB_CACHE_LINE_SIZE 128
#define QB_CACHE_LINE_WORDS (QB_CACHE_LINE_SIZE/sizeof(uint32_t))
#define idx_cache_line_step(idx) \
do { \
if (idx % QB_CACHE_LINE_WORDS) { \
idx += (QB_CACHE_LINE_WORDS - (idx % QB_CACHE_LINE_WORDS)); \
} \
if (idx > (rb->shared_hdr->word_size - 1)) { \
idx = ((idx) % (rb->shared_hdr->word_size)); \
} \
} while (0)
#else
#define QB_CACHE_LINE_SIZE 0
#define QB_CACHE_LINE_WORDS 0
#define idx_cache_line_step(idx) \
do { \
if (idx > (rb->shared_hdr->word_size - 1)) { \
idx = ((idx) % (rb->shared_hdr->word_size)); \
} \
} while (0)
#endif
/* the chunk header is two words
* 1) the chunk data size
* 2) the magic number
*/
#define QB_RB_CHUNK_HEADER_WORDS 2
#define QB_RB_CHUNK_HEADER_SIZE (sizeof(uint32_t) * QB_RB_CHUNK_HEADER_WORDS)
/*
* margin is the gap we leave when checking to see if we have enough
* space for a new chunk.
* So:
* qb_rb_space_free() >= QB_RB_CHUNK_MARGIN + new data chunk
* The extra word size is to allow for non word sized data chunks.
* QB_CACHE_LINE_WORDS is to make sure we have space to align the
* chunk.
*/
#define QB_RB_WORD_ALIGN 1
#define QB_RB_CHUNK_MARGIN (sizeof(uint32_t) * (QB_RB_CHUNK_HEADER_WORDS +\
QB_RB_WORD_ALIGN +\
QB_CACHE_LINE_WORDS))
#define QB_RB_CHUNK_MAGIC 0xA1A1A1A1
#define QB_RB_CHUNK_MAGIC_DEAD 0xD0D0D0D0
#define QB_RB_CHUNK_MAGIC_ALLOC 0xA110CED0
#define QB_RB_CHUNK_SIZE_GET(rb, pointer) rb->shared_data[pointer]
#define QB_RB_CHUNK_MAGIC_GET(rb, pointer) \
qb_atomic_int_get_ex((int32_t*)&rb->shared_data[(pointer + 1) % rb->shared_hdr->word_size], \
QB_ATOMIC_ACQUIRE)
#define QB_RB_CHUNK_MAGIC_SET(rb, pointer, new_val) \
qb_atomic_int_set_ex((int32_t*)&rb->shared_data[(pointer + 1) % rb->shared_hdr->word_size], \
new_val, QB_ATOMIC_RELEASE)
#define QB_RB_CHUNK_DATA_GET(rb, pointer) \
&rb->shared_data[(pointer + QB_RB_CHUNK_HEADER_WORDS) % rb->shared_hdr->word_size]
#define QB_MAGIC_ASSERT(_ptr_) \
do { \
uint32_t chunk_magic = QB_RB_CHUNK_MAGIC_GET(rb, _ptr_); \
if (chunk_magic != QB_RB_CHUNK_MAGIC) print_header(rb); \
assert(chunk_magic == QB_RB_CHUNK_MAGIC); \
} while (0)
#define idx_step(idx) \
do { \
if (idx > (rb->shared_hdr->word_size - 1)) { \
idx = ((idx) % (rb->shared_hdr->word_size)); \
} \
} while (0)
static void print_header(struct qb_ringbuffer_s * rb);
static int _rb_chunk_reclaim(struct qb_ringbuffer_s * rb);
qb_ringbuffer_t *
qb_rb_open(const char *name, size_t size, uint32_t flags,
size_t shared_user_data_size)
{
return qb_rb_open_2(name, size, flags, shared_user_data_size, NULL);
}
qb_ringbuffer_t *
qb_rb_open_2(const char *name, size_t size, uint32_t flags,
size_t shared_user_data_size,
struct qb_rb_notifier *notifiers)
{
struct qb_ringbuffer_s *rb;
size_t real_size;
size_t shared_size;
char path[PATH_MAX];
int32_t fd_hdr;
int32_t fd_data;
uint32_t file_flags = O_RDWR;
char filename[PATH_MAX];
int32_t error = 0;
void *shm_addr;
long page_size = sysconf(_SC_PAGESIZE);
-#ifdef QB_FORCE_SHM_ALIGN
+#ifdef QB_ARCH_HPPA
+ page_size = QB_MAX(page_size, 0x00400000); /* align to page colour */
+#elif defined(QB_FORCE_SHM_ALIGN)
page_size = QB_MAX(page_size, 16 * 1024);
#endif /* QB_FORCE_SHM_ALIGN */
/* The user of this api expects the 'size' parameter passed into this function
* to be reflective of the max size single write we can do to the
* ringbuffer. This means we have to add both the 'margin' space used
* to calculate if there is enough space for a new chunk as well as the '+1' that
* prevents overlap of the read/write pointers */
size += QB_RB_CHUNK_MARGIN + 1;
real_size = QB_ROUNDUP(size, page_size);
shared_size =
sizeof(struct qb_ringbuffer_shared_s) + shared_user_data_size;
if (flags & QB_RB_FLAG_CREATE) {
file_flags |= O_CREAT | O_TRUNC;
}
rb = calloc(1, sizeof(struct qb_ringbuffer_s));
if (rb == NULL) {
return NULL;
}
/*
* Create a shared_hdr memory segment for the header.
*/
snprintf(filename, PATH_MAX, "qb-%s-header", name);
fd_hdr = qb_sys_mmap_file_open(path, filename,
shared_size, file_flags);
if (fd_hdr < 0) {
error = fd_hdr;
qb_util_log(LOG_ERR, "couldn't create file for mmap");
goto cleanup_hdr;
}
rb->shared_hdr = mmap(0,
shared_size,
PROT_READ | PROT_WRITE, MAP_SHARED, fd_hdr, 0);
if (rb->shared_hdr == MAP_FAILED) {
error = -errno;
qb_util_log(LOG_ERR, "couldn't create mmap for header");
goto cleanup_hdr;
}
qb_atomic_init();
rb->flags = flags;
/*
* create the semaphore
*/
if (flags & QB_RB_FLAG_CREATE) {
rb->shared_data = NULL;
/* rb->shared_hdr->word_size tracks data by ints and not bytes/chars. */
rb->shared_hdr->word_size = real_size / sizeof(uint32_t);
rb->shared_hdr->write_pt = 0;
rb->shared_hdr->read_pt = 0;
(void)strlcpy(rb->shared_hdr->hdr_path, path, PATH_MAX);
}
if (notifiers && notifiers->post_fn) {
error = 0;
memcpy(&rb->notifier,
notifiers,
sizeof(struct qb_rb_notifier));
} else {
error = qb_rb_sem_create(rb, flags);
}
if (error < 0) {
errno = -error;
qb_util_perror(LOG_ERR, "couldn't create a semaphore");
goto cleanup_hdr;
}
/* Create the shared_data memory segment for the actual ringbuffer.
* They have to be separate.
*/
if (flags & QB_RB_FLAG_CREATE) {
snprintf(filename, PATH_MAX, "qb-%s-data", name);
fd_data = qb_sys_mmap_file_open(path,
filename,
real_size, file_flags);
(void)strlcpy(rb->shared_hdr->data_path, path, PATH_MAX);
} else {
fd_data = qb_sys_mmap_file_open(path,
rb->shared_hdr->data_path,
real_size, file_flags);
}
if (fd_data < 0) {
error = fd_data;
qb_util_log(LOG_ERR, "couldn't create file for mmap");
goto cleanup_hdr;
}
qb_util_log(LOG_DEBUG,
"shm size:%ld; real_size:%ld; rb->word_size:%d", size,
real_size, rb->shared_hdr->word_size);
/* this function closes fd_data */
error = qb_sys_circular_mmap(fd_data, &shm_addr, real_size);
rb->shared_data = shm_addr;
if (error != 0) {
qb_util_log(LOG_ERR, "couldn't create circular mmap on %s",
rb->shared_hdr->data_path);
goto cleanup_data;
}
if (flags & QB_RB_FLAG_CREATE) {
memset(rb->shared_data, 0, real_size);
rb->shared_data[rb->shared_hdr->word_size] = 5;
rb->shared_hdr->ref_count = 1;
} else {
qb_atomic_int_inc(&rb->shared_hdr->ref_count);
}
close(fd_hdr);
return rb;
cleanup_data:
if (flags & QB_RB_FLAG_CREATE) {
unlink(rb->shared_hdr->data_path);
}
cleanup_hdr:
if (fd_hdr >= 0) {
close(fd_hdr);
}
if (rb && (flags & QB_RB_FLAG_CREATE)) {
unlink(rb->shared_hdr->hdr_path);
if (rb->notifier.destroy_fn) {
(void)rb->notifier.destroy_fn(rb->notifier.instance);
}
}
if (rb && (rb->shared_hdr != MAP_FAILED && rb->shared_hdr != NULL)) {
munmap(rb->shared_hdr, sizeof(struct qb_ringbuffer_shared_s));
}
free(rb);
errno = -error;
return NULL;
}
void
qb_rb_close(struct qb_ringbuffer_s * rb)
{
if (rb == NULL) {
return;
}
qb_enter();
(void)qb_atomic_int_dec_and_test(&rb->shared_hdr->ref_count);
if (rb->flags & QB_RB_FLAG_CREATE) {
if (rb->notifier.destroy_fn) {
(void)rb->notifier.destroy_fn(rb->notifier.instance);
}
unlink(rb->shared_hdr->data_path);
unlink(rb->shared_hdr->hdr_path);
qb_util_log(LOG_DEBUG,
"Free'ing ringbuffer: %s",
rb->shared_hdr->hdr_path);
} else {
qb_util_log(LOG_DEBUG,
"Closing ringbuffer: %s", rb->shared_hdr->hdr_path);
}
munmap(rb->shared_data, (rb->shared_hdr->word_size * sizeof(uint32_t)) << 1);
munmap(rb->shared_hdr, sizeof(struct qb_ringbuffer_shared_s));
free(rb);
}
void
qb_rb_force_close(struct qb_ringbuffer_s * rb)
{
if (rb == NULL) {
return;
}
qb_enter();
if (rb->notifier.destroy_fn) {
(void)rb->notifier.destroy_fn(rb->notifier.instance);
}
errno = 0;
unlink(rb->shared_hdr->data_path);
qb_util_perror(LOG_DEBUG,
"Force free'ing ringbuffer: %s",
rb->shared_hdr->data_path);
errno = 0;
unlink(rb->shared_hdr->hdr_path);
qb_util_perror(LOG_DEBUG,
"Force free'ing ringbuffer: %s",
rb->shared_hdr->hdr_path);
munmap(rb->shared_data, (rb->shared_hdr->word_size * sizeof(uint32_t)) << 1);
munmap(rb->shared_hdr, sizeof(struct qb_ringbuffer_shared_s));
free(rb);
}
char *
qb_rb_name_get(struct qb_ringbuffer_s * rb)
{
if (rb == NULL) {
return NULL;
}
return rb->shared_hdr->hdr_path;
}
void *
qb_rb_shared_user_data_get(struct qb_ringbuffer_s * rb)
{
if (rb == NULL) {
return NULL;
}
return rb->shared_hdr->user_data;
}
int32_t
qb_rb_refcount_get(struct qb_ringbuffer_s * rb)
{
if (rb == NULL) {
return -EINVAL;
}
return qb_atomic_int_get(&rb->shared_hdr->ref_count);
}
ssize_t
qb_rb_space_free(struct qb_ringbuffer_s * rb)
{
uint32_t write_size;
uint32_t read_size;
size_t space_free = 0;
if (rb == NULL) {
return -EINVAL;
}
if (rb->notifier.space_used_fn) {
return (rb->shared_hdr->word_size * sizeof(uint32_t)) -
rb->notifier.space_used_fn(rb->notifier.instance);
}
write_size = rb->shared_hdr->write_pt;
read_size = rb->shared_hdr->read_pt;
if (write_size > read_size) {
space_free =
(read_size - write_size + rb->shared_hdr->word_size) - 1;
} else if (write_size < read_size) {
space_free = (read_size - write_size) - 1;
} else {
if (rb->notifier.q_len_fn && rb->notifier.q_len_fn(rb->notifier.instance) > 0) {
space_free = 0;
} else {
space_free = rb->shared_hdr->word_size;
}
}
/* word -> bytes */
return (space_free * sizeof(uint32_t));
}
ssize_t
qb_rb_space_used(struct qb_ringbuffer_s * rb)
{
uint32_t write_size;
uint32_t read_size;
size_t space_used;
if (rb == NULL) {
return -EINVAL;
}
if (rb->notifier.space_used_fn) {
return rb->notifier.space_used_fn(rb->notifier.instance);
}
write_size = rb->shared_hdr->write_pt;
read_size = rb->shared_hdr->read_pt;
if (write_size > read_size) {
space_used = write_size - read_size;
} else if (write_size < read_size) {
space_used =
(write_size - read_size + rb->shared_hdr->word_size) - 1;
} else {
space_used = 0;
}
/* word -> bytes */
return (space_used * sizeof(uint32_t));
}
ssize_t
qb_rb_chunks_used(struct qb_ringbuffer_s *rb)
{
if (rb == NULL) {
return -EINVAL;
}
if (rb->notifier.q_len_fn) {
return rb->notifier.q_len_fn(rb->notifier.instance);
}
return -ENOTSUP;
}
void *
qb_rb_chunk_alloc(struct qb_ringbuffer_s * rb, size_t len)
{
uint32_t write_pt;
if (rb == NULL) {
errno = EINVAL;
return NULL;
}
/*
* Reclaim data if we are over writing and we need space
*/
if (rb->flags & QB_RB_FLAG_OVERWRITE) {
while (qb_rb_space_free(rb) < (len + QB_RB_CHUNK_MARGIN)) {
int rc = _rb_chunk_reclaim(rb);
if (rc != 0) {
errno = rc;
return NULL;
}
}
} else {
if (qb_rb_space_free(rb) < (len + QB_RB_CHUNK_MARGIN)) {
errno = EAGAIN;
return NULL;
}
}
write_pt = rb->shared_hdr->write_pt;
/*
* insert the chunk header
*/
rb->shared_data[write_pt] = 0;
QB_RB_CHUNK_MAGIC_SET(rb, write_pt, QB_RB_CHUNK_MAGIC_ALLOC);
/*
* return a pointer to the beginning of the chunk data
*/
return (void *)QB_RB_CHUNK_DATA_GET(rb, write_pt);
}
static uint32_t
qb_rb_chunk_step(struct qb_ringbuffer_s * rb, uint32_t pointer)
{
uint32_t chunk_size = QB_RB_CHUNK_SIZE_GET(rb, pointer);
/*
* skip over the chunk header
*/
pointer += QB_RB_CHUNK_HEADER_WORDS;
/*
* skip over the user's data.
*/
pointer += (chunk_size / sizeof(uint32_t));
/* make allowance for non-word sizes */
if ((chunk_size % (sizeof(uint32_t) * QB_RB_WORD_ALIGN)) != 0) {
pointer++;
}
idx_cache_line_step(pointer);
return pointer;
}
int32_t
qb_rb_chunk_commit(struct qb_ringbuffer_s * rb, size_t len)
{
uint32_t old_write_pt;
if (rb == NULL) {
return -EINVAL;
}
/*
* commit the magic & chunk_size
*/
old_write_pt = rb->shared_hdr->write_pt;
rb->shared_data[old_write_pt] = len;
/*
* commit the new write pointer
*/
rb->shared_hdr->write_pt = qb_rb_chunk_step(rb, old_write_pt);
QB_RB_CHUNK_MAGIC_SET(rb, old_write_pt, QB_RB_CHUNK_MAGIC);
DEBUG_PRINTF("commit [%zd] read: %u, write: %u -> %u (%u)\n",
(rb->notifier.q_len_fn ?
rb->notifier.q_len_fn(rb->notifier.instance) : 0),
rb->shared_hdr->read_pt,
old_write_pt,
rb->shared_hdr->write_pt,
rb->shared_hdr->word_size);
/*
* post the notification to the reader
*/
if (rb->notifier.post_fn) {
return rb->notifier.post_fn(rb->notifier.instance, len);
}
return 0;
}
ssize_t
qb_rb_chunk_write(struct qb_ringbuffer_s * rb, const void *data, size_t len)
{
char *dest = qb_rb_chunk_alloc(rb, len);
int32_t res = 0;
if (rb == NULL) {
return -EINVAL;
}
if (dest == NULL) {
return -errno;
}
memcpy(dest, data, len);
res = qb_rb_chunk_commit(rb, len);
if (res < 0) {
return res;
}
return len;
}
static int
_rb_chunk_reclaim(struct qb_ringbuffer_s * rb)
{
uint32_t old_read_pt;
uint32_t new_read_pt;
uint32_t old_chunk_size;
uint32_t chunk_magic;
int rc = 0;
old_read_pt = rb->shared_hdr->read_pt;
chunk_magic = QB_RB_CHUNK_MAGIC_GET(rb, old_read_pt);
if (chunk_magic != QB_RB_CHUNK_MAGIC) {
return -EINVAL;
}
old_chunk_size = QB_RB_CHUNK_SIZE_GET(rb, old_read_pt);
new_read_pt = qb_rb_chunk_step(rb, old_read_pt);
/*
* clear the header
*/
rb->shared_data[old_read_pt] = 0;
QB_RB_CHUNK_MAGIC_SET(rb, old_read_pt, QB_RB_CHUNK_MAGIC_DEAD);
/*
* set the new read pointer after clearing the header
* to prevent a situation where a fast writer will write their
* new chunk between setting the new read pointer and clearing the
* header.
*/
rb->shared_hdr->read_pt = new_read_pt;
if (rb->notifier.reclaim_fn) {
rc = rb->notifier.reclaim_fn(rb->notifier.instance,
old_chunk_size);
if (rc < 0) {
errno = -rc;
qb_util_perror(LOG_WARNING, "reclaim_fn");
}
}
DEBUG_PRINTF("reclaim [%zd]: read: %u -> %u, write: %u\n",
(rb->notifier.q_len_fn ?
rb->notifier.q_len_fn(rb->notifier.instance) : 0),
old_read_pt,
rb->shared_hdr->read_pt,
rb->shared_hdr->write_pt);
return rc;
}
void
qb_rb_chunk_reclaim(struct qb_ringbuffer_s * rb)
{
if (rb == NULL) {
return;
}
_rb_chunk_reclaim(rb);
}
ssize_t
qb_rb_chunk_peek(struct qb_ringbuffer_s * rb, void **data_out, int32_t timeout)
{
uint32_t read_pt;
uint32_t chunk_size;
uint32_t chunk_magic;
int32_t res = 0;
if (rb == NULL) {
return -EINVAL;
}
if (rb->notifier.timedwait_fn) {
res = rb->notifier.timedwait_fn(rb->notifier.instance, timeout);
}
if (res < 0 && res != -EIDRM) {
if (res == -ETIMEDOUT) {
return 0;
} else {
errno = -res;
qb_util_perror(LOG_ERR, "sem_timedwait");
}
return res;
}
read_pt = rb->shared_hdr->read_pt;
chunk_magic = QB_RB_CHUNK_MAGIC_GET(rb, read_pt);
if (chunk_magic != QB_RB_CHUNK_MAGIC) {
if (rb->notifier.post_fn) {
(void)rb->notifier.post_fn(rb->notifier.instance, res);
}
return 0;
}
chunk_size = QB_RB_CHUNK_SIZE_GET(rb, read_pt);
*data_out = QB_RB_CHUNK_DATA_GET(rb, read_pt);
return chunk_size;
}
ssize_t
qb_rb_chunk_read(struct qb_ringbuffer_s * rb, void *data_out, size_t len,
int32_t timeout)
{
uint32_t read_pt;
uint32_t chunk_size;
uint32_t chunk_magic;
int32_t res = 0;
if (rb == NULL) {
return -EINVAL;
}
if (rb->notifier.timedwait_fn) {
res = rb->notifier.timedwait_fn(rb->notifier.instance, timeout);
}
if (res < 0 && res != -EIDRM) {
if (res != -ETIMEDOUT) {
errno = -res;
qb_util_perror(LOG_ERR, "sem_timedwait");
}
return res;
}
read_pt = rb->shared_hdr->read_pt;
chunk_magic = QB_RB_CHUNK_MAGIC_GET(rb, read_pt);
if (chunk_magic != QB_RB_CHUNK_MAGIC) {
if (rb->notifier.timedwait_fn == NULL) {
return -ETIMEDOUT;
} else {
(void)rb->notifier.post_fn(rb->notifier.instance, res);
#ifdef EBADMSG
return -EBADMSG;
#else
return -EINVAL;
#endif
}
}
chunk_size = QB_RB_CHUNK_SIZE_GET(rb, read_pt);
if (len < chunk_size) {
qb_util_log(LOG_ERR,
"trying to recv chunk of size %d but %d available",
len, chunk_size);
if (rb->notifier.post_fn) {
(void)rb->notifier.post_fn(rb->notifier.instance, chunk_size);
}
return -ENOBUFS;
}
memcpy(data_out,
QB_RB_CHUNK_DATA_GET(rb, read_pt),
chunk_size);
_rb_chunk_reclaim(rb);
return chunk_size;
}
static void
print_header(struct qb_ringbuffer_s * rb)
{
printf("Ringbuffer: \n");
if (rb->flags & QB_RB_FLAG_OVERWRITE) {
printf(" ->OVERWRITE\n");
} else {
printf(" ->NORMAL\n");
}
printf(" ->write_pt [%d]\n", rb->shared_hdr->write_pt);
printf(" ->read_pt [%d]\n", rb->shared_hdr->read_pt);
printf(" ->size [%d words]\n", rb->shared_hdr->word_size);
#ifndef S_SPLINT_S
printf(" =>free [%zu bytes]\n", qb_rb_space_free(rb));
printf(" =>used [%zu bytes]\n", qb_rb_space_used(rb));
#endif /* S_SPLINT_S */
}
/*
* FILE HEADER ORDER
* 1. word_size
* 2. write_pt
* 3. read_pt
* 4. version
* 5. header_hash
*
* 6. data
*/
ssize_t
qb_rb_write_to_file(struct qb_ringbuffer_s * rb, int32_t fd)
{
ssize_t result;
ssize_t written_size = 0;
uint32_t hash = 0;
uint32_t version = QB_RB_FILE_HEADER_VERSION;
if (rb == NULL) {
return -EINVAL;
}
print_header(rb);
/*
* 1. word_size
*/
result = write(fd, &rb->shared_hdr->word_size, sizeof(uint32_t));
if (result != sizeof(uint32_t)) {
return -errno;
}
written_size += result;
/*
* 2. 3. store the read & write pointers
*/
result = write(fd, (void *)&rb->shared_hdr->write_pt, sizeof(uint32_t));
if (result != sizeof(uint32_t)) {
return -errno;
}
written_size += result;
result = write(fd, (void *)&rb->shared_hdr->read_pt, sizeof(uint32_t));
if (result != sizeof(uint32_t)) {
return -errno;
}
written_size += result;
/*
* 4. version used
*/
result = write(fd, &version, sizeof(uint32_t));
if (result != sizeof(uint32_t)) {
return -errno;
}
written_size += result;
/*
* 5. hash helps us verify header is not corrupted on file read
*/
hash = rb->shared_hdr->word_size + rb->shared_hdr->write_pt + rb->shared_hdr->read_pt + QB_RB_FILE_HEADER_VERSION;
result = write(fd, &hash, sizeof(uint32_t));
if (result != sizeof(uint32_t)) {
return -errno;
}
written_size += result;
result = write(fd, rb->shared_data,
rb->shared_hdr->word_size * sizeof(uint32_t));
if (result != rb->shared_hdr->word_size * sizeof(uint32_t)) {
return -errno;
}
written_size += result;
qb_util_log(LOG_DEBUG, " writing total of: %zd\n", written_size);
return written_size;
}
qb_ringbuffer_t *
qb_rb_create_from_file(int32_t fd, uint32_t flags)
{
ssize_t n_read;
size_t n_required;
size_t total_read = 0;
uint32_t read_pt;
uint32_t write_pt;
struct qb_ringbuffer_s *rb;
uint32_t word_size = 0;
uint32_t version = 0;
uint32_t hash = 0;
uint32_t calculated_hash = 0;
if (fd < 0) {
return NULL;
}
/*
* 1. word size
*/
n_required = sizeof(uint32_t);
n_read = read(fd, &word_size, n_required);
if (n_read != n_required) {
qb_util_perror(LOG_ERR, "Unable to read blackbox file header");
return NULL;
}
total_read += n_read;
/*
* 2. 3. read & write pointers
*/
n_read = read(fd, &write_pt, sizeof(uint32_t));
assert(n_read == sizeof(uint32_t));
total_read += n_read;
n_read = read(fd, &read_pt, sizeof(uint32_t));
assert(n_read == sizeof(uint32_t));
total_read += n_read;
/*
* 4. version
*/
n_required = sizeof(uint32_t);
n_read = read(fd, &version, n_required);
if (n_read != n_required) {
qb_util_perror(LOG_ERR, "Unable to read blackbox file header");
return NULL;
}
total_read += n_read;
/*
* 5. Hash
*/
n_required = sizeof(uint32_t);
n_read = read(fd, &hash, n_required);
if (n_read != n_required) {
qb_util_perror(LOG_ERR, "Unable to read blackbox file header");
return NULL;
}
total_read += n_read;
calculated_hash = word_size + write_pt + read_pt + version;
if (hash != calculated_hash) {
qb_util_log(LOG_ERR, "Corrupt blackbox: File header hash (%d) does not match calculated hash (%d)", hash, calculated_hash);
return NULL;
} else if (version != QB_RB_FILE_HEADER_VERSION) {
qb_util_log(LOG_ERR, "Wrong file header version. Expected %d got %d",
QB_RB_FILE_HEADER_VERSION, version);
return NULL;
}
/*
* 6. data
*/
n_required = (word_size * sizeof(uint32_t));
/*
* qb_rb_open adds QB_RB_CHUNK_MARGIN + 1 to the requested size.
*/
rb = qb_rb_open("create_from_file", n_required - (QB_RB_CHUNK_MARGIN + 1),
QB_RB_FLAG_CREATE | QB_RB_FLAG_NO_SEMAPHORE, 0);
if (rb == NULL) {
return NULL;
}
rb->shared_hdr->read_pt = read_pt;
rb->shared_hdr->write_pt = write_pt;
n_read = read(fd, rb->shared_data, n_required);
if (n_read < 0) {
qb_util_perror(LOG_ERR, "Unable to read blackbox file data");
goto cleanup_fail;
}
total_read += n_read;
if (n_read != n_required) {
qb_util_log(LOG_WARNING, "read %zd bytes, but expected %zu",
n_read, n_required);
goto cleanup_fail;
}
qb_util_log(LOG_DEBUG, "read total of: %zd", total_read);
print_header(rb);
return rb;
cleanup_fail:
qb_rb_close(rb);
return NULL;
}
int32_t
qb_rb_chown(struct qb_ringbuffer_s * rb, uid_t owner, gid_t group)
{
int32_t res;
if (rb == NULL) {
return -EINVAL;
}
res = chown(rb->shared_hdr->data_path, owner, group);
if (res < 0 && errno != EPERM) {
return -errno;
}
res = chown(rb->shared_hdr->hdr_path, owner, group);
if (res < 0 && errno != EPERM) {
return -errno;
}
return 0;
}
int32_t
qb_rb_chmod(qb_ringbuffer_t * rb, mode_t mode)
{
int32_t res;
if (rb == NULL) {
return -EINVAL;
}
res = chmod(rb->shared_hdr->data_path, mode);
if (res < 0) {
return -errno;
}
res = chmod(rb->shared_hdr->hdr_path, mode);
if (res < 0) {
return -errno;
}
return 0;
}
diff --git a/lib/unix.c b/lib/unix.c
index 79ed538..3ce61bc 100644
--- a/lib/unix.c
+++ b/lib/unix.c
@@ -1,494 +1,508 @@
/*
* Copyright (C) 2011 Red Hat, Inc.
*
* All rights reserved.
*
* Author: Angus Salkeld <asalkeld@redhat.com>
*
* libqb 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, either version 2.1 of the License, or
* (at your option) any later version.
*
* libqb 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 libqb. If not, see <http://www.gnu.org/licenses/>.
*/
#include "os_base.h"
#ifdef HAVE_SYS_SHM_H
#include <sys/shm.h>
#endif
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#include "util_int.h"
#include <qb/qbdefs.h>
#include <qb/qbutil.h>
#include <qb/qbatomic.h>
#if defined(MAP_ANON) && ! defined(MAP_ANONYMOUS)
/*
* BSD derivatives usually have MAP_ANON, not MAP_ANONYMOUS
**/
#define MAP_ANONYMOUS MAP_ANON
#endif
char *
qb_strerror_r(int errnum, char *buf, size_t buflen)
{
#ifdef STRERROR_R_CHAR_P
return strerror_r(errnum, buf, buflen);
#else
if (strerror_r(errnum, buf, buflen) != 0) {
buf[0] = '\0';
}
return buf;
#endif /* STRERROR_R_CHAR_P */
}
static int32_t
open_mmap_file(char *path, uint32_t file_flags)
{
if (strstr(path, "XXXXXX") != NULL) {
mode_t old_mode = umask(077);
int32_t temp_fd = mkstemp(path);
(void)umask(old_mode);
return temp_fd;
}
return open(path, file_flags, 0600);
}
int32_t
qb_sys_mmap_file_open(char *path, const char *file, size_t bytes,
uint32_t file_flags)
{
int32_t fd;
int32_t i;
int32_t res = 0;
ssize_t written;
char *buffer = NULL;
char *is_absolute = strchr(file, '/');
if (is_absolute) {
(void)strlcpy(path, file, PATH_MAX);
} else {
#if defined(QB_LINUX) || defined(QB_CYGWIN)
snprintf(path, PATH_MAX, "/dev/shm/%s", file);
#else
snprintf(path, PATH_MAX, LOCALSTATEDIR "/run/%s", file);
is_absolute = path;
#endif
}
fd = open_mmap_file(path, file_flags);
if (fd < 0 && !is_absolute) {
qb_util_perror(LOG_ERR, "couldn't open file %s", path);
snprintf(path, PATH_MAX, LOCALSTATEDIR "/run/%s", file);
fd = open_mmap_file(path, file_flags);
if (fd < 0) {
res = -errno;
qb_util_perror(LOG_ERR, "couldn't open file %s", path);
return res;
}
} else if (fd < 0 && is_absolute) {
res = -errno;
qb_util_perror(LOG_ERR, "couldn't open file %s", path);
return res;
}
if (ftruncate(fd, bytes) == -1) {
res = -errno;
qb_util_perror(LOG_ERR, "couldn't truncate file %s", path);
goto unlink_exit;
}
if (file_flags & O_CREAT) {
long page_size = sysconf(_SC_PAGESIZE);
long write_size = QB_MIN(page_size, bytes);
if (page_size < 0) {
res = -errno;
goto unlink_exit;
}
buffer = calloc(1, write_size);
if (buffer == NULL) {
res = -ENOMEM;
goto unlink_exit;
}
for (i = 0; i < (bytes / write_size); i++) {
retry_write:
written = write(fd, buffer, write_size);
if (written == -1 && errno == EINTR) {
goto retry_write;
}
if (written != write_size) {
res = -ENOSPC;
free(buffer);
goto unlink_exit;
}
}
free(buffer);
}
return fd;
unlink_exit:
unlink(path);
if (fd >= 0) {
close(fd);
}
return res;
}
int32_t
qb_sys_circular_mmap(int32_t fd, void **buf, size_t bytes)
{
void *addr_orig = NULL;
void *addr;
void *addr_next;
int32_t res;
int flags = MAP_ANONYMOUS;
#ifdef QB_FORCE_SHM_ALIGN
/* On a number of arches any fixed and shared mmap() mapping address
* must be aligned to 16k. If the first mmap() below is not shared then
* the first mmap() will succeed because these restrictions do not apply to
* private mappings. The second mmap() wants a shared memory mapping but
* the address returned by the first one is only page-aligned and not
* aligned to 16k.
*/
flags |= MAP_SHARED;
#else
flags |= MAP_PRIVATE;
#endif /* QB_FORCE_SHM_ALIGN */
+#if defined(QB_ARCH_HPPA)
+ /* map twice the size we want to make sure we have already mapped
+ the second memory location behind it too. Otherwise the Linux
+ kernel may map it in the upper memory so that we can't map
+ the second part afterwards since it will conflict. */
+ addr = mmap(NULL, 2*bytes, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0);
+
+ if (addr == MAP_FAILED)
+ return -errno;
+
+ addr_orig = addr;
+#else
addr_orig = mmap(NULL, bytes << 1, PROT_NONE, flags, -1, 0);
if (addr_orig == MAP_FAILED) {
return -errno;
}
addr = mmap(addr_orig, bytes, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, fd, 0);
+#endif
if (addr != addr_orig) {
res = -errno;
goto cleanup_fail;
}
#if defined(QB_BSD) && defined(MADV_NOSYNC)
madvise(addr_orig, bytes, MADV_NOSYNC);
#endif
addr_next = ((char *)addr_orig) + bytes;
addr = mmap(addr_next,
bytes, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, fd, 0);
if (addr != addr_next) {
res = -errno;
goto cleanup_fail;
}
#if defined(QB_BSD) && defined(MADV_NOSYNC)
madvise(((char *)addr_orig) + bytes, bytes, MADV_NOSYNC);
#endif
res = close(fd);
if (res) {
goto cleanup_fail;
}
*buf = addr_orig;
return 0;
cleanup_fail:
if (addr_orig) {
munmap(addr_orig, bytes << 1);
}
close(fd);
return res;
}
int32_t
qb_sys_fd_nonblock_cloexec_set(int32_t fd)
{
int32_t res = 0;
int32_t oldflags = fcntl(fd, F_GETFD, 0);
if (oldflags < 0) {
oldflags = 0;
}
oldflags |= FD_CLOEXEC;
res = fcntl(fd, F_SETFD, oldflags);
if (res == -1) {
res = -errno;
qb_util_perror(LOG_ERR,
"Could not set close-on-exit on fd:%d", fd);
return res;
}
res = fcntl(fd, F_SETFL, O_NONBLOCK);
if (res == -1) {
res = -errno;
qb_util_log(LOG_ERR, "Could not set non-blocking on fd:%d", fd);
}
return res;
}
void
qb_sigpipe_ctl(enum qb_sigpipe_ctl ctl)
{
#if !defined(HAVE_MSG_NOSIGNAL) && !defined(HAVE_SO_NOSIGPIPE)
struct sigaction act;
struct sigaction oact;
act.sa_handler = SIG_IGN;
if (ctl == QB_SIGPIPE_IGNORE) {
sigaction(SIGPIPE, &act, &oact);
} else {
sigaction(SIGPIPE, &oact, NULL);
}
#endif /* !MSG_NOSIGNAL && !SO_NOSIGPIPE */
}
void
qb_socket_nosigpipe(int32_t s)
{
#if !defined(HAVE_MSG_NOSIGNAL) && defined(HAVE_SO_NOSIGPIPE)
int32_t on = 1;
setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&on, sizeof(on));
#endif /* !MSG_NOSIGNAL && SO_NOSIGPIPE */
}
/*
* atomic operations
* --------------------------------------------------------------------------
*/
#ifndef HAVE_GCC_BUILTINS_FOR_SYNC_OPERATIONS
/*
* We have to use the slow, but safe locking method
*/
static qb_thread_lock_t *qb_atomic_mutex = NULL;
void
qb_atomic_init(void)
{
if (qb_atomic_mutex == NULL) {
qb_atomic_mutex = qb_thread_lock_create(QB_THREAD_LOCK_SHORT);
}
assert(qb_atomic_mutex);
}
int32_t
qb_atomic_int_exchange_and_add(volatile int32_t QB_GNUC_MAY_ALIAS * atomic,
int32_t val)
{
int32_t result;
qb_thread_lock(qb_atomic_mutex);
result = *atomic;
*atomic += val;
qb_thread_unlock(qb_atomic_mutex);
return result;
}
void
qb_atomic_int_add(volatile int32_t QB_GNUC_MAY_ALIAS * atomic, int32_t val)
{
qb_thread_lock(qb_atomic_mutex);
*atomic += val;
qb_thread_unlock(qb_atomic_mutex);
}
int32_t
qb_atomic_int_compare_and_exchange(volatile int32_t QB_GNUC_MAY_ALIAS * atomic,
int32_t oldval, int32_t newval)
{
int32_t result;
qb_thread_lock(qb_atomic_mutex);
if (*atomic == oldval) {
result = QB_TRUE;
*atomic = newval;
} else {
result = QB_FALSE;
}
qb_thread_unlock(qb_atomic_mutex);
return result;
}
int32_t
qb_atomic_pointer_compare_and_exchange(volatile void *QB_GNUC_MAY_ALIAS *
atomic, void *oldval, void *newval)
{
int32_t result;
qb_thread_lock(qb_atomic_mutex);
if (*atomic == oldval) {
result = QB_TRUE;
*atomic = newval;
} else {
result = QB_FALSE;
}
qb_thread_unlock(qb_atomic_mutex);
return result;
}
#ifdef QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED
int32_t
(qb_atomic_int_get) (volatile int32_t QB_GNUC_MAY_ALIAS * atomic)
{
int32_t result;
qb_thread_lock(qb_atomic_mutex);
result = *atomic;
qb_thread_unlock(qb_atomic_mutex);
return result;
}
void
(qb_atomic_int_set) (volatile int32_t QB_GNUC_MAY_ALIAS * atomic,
int32_t newval)
{
qb_thread_lock(qb_atomic_mutex);
*atomic = newval;
qb_thread_unlock(qb_atomic_mutex);
}
void *
(qb_atomic_pointer_get) (volatile void *QB_GNUC_MAY_ALIAS * atomic)
{
void *result;
qb_thread_lock(qb_atomic_mutex);
result = (void*)*atomic;
qb_thread_unlock(qb_atomic_mutex);
return result;
}
void
(qb_atomic_pointer_set) (volatile void *QB_GNUC_MAY_ALIAS * atomic,
void *newval)
{
qb_thread_lock(qb_atomic_mutex);
*atomic = newval;
qb_thread_unlock(qb_atomic_mutex);
}
#endif /* QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
#else
/*
* gcc built-ins
*/
void
qb_atomic_init(void)
{
}
int32_t
qb_atomic_int_exchange_and_add(volatile int32_t QB_GNUC_MAY_ALIAS * atomic,
int32_t val)
{
return __sync_fetch_and_add(atomic, val);
}
void
qb_atomic_int_add(volatile int32_t QB_GNUC_MAY_ALIAS * atomic, int32_t val)
{
__sync_fetch_and_add(atomic, val);
}
int32_t
qb_atomic_int_compare_and_exchange(volatile int32_t QB_GNUC_MAY_ALIAS * atomic,
int32_t oldval, int32_t newval)
{
return __sync_bool_compare_and_swap(atomic, oldval, newval);
}
int32_t
qb_atomic_pointer_compare_and_exchange(volatile void *QB_GNUC_MAY_ALIAS *
atomic, void *oldval, void *newval)
{
return __sync_bool_compare_and_swap(atomic, oldval, newval);
}
#ifdef QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED
#define QB_ATOMIC_MEMORY_BARRIER __sync_synchronize ()
int32_t
(qb_atomic_int_get) (volatile int32_t QB_GNUC_MAY_ALIAS * atomic)
{
QB_ATOMIC_MEMORY_BARRIER;
return *atomic;
}
void
(qb_atomic_int_set) (volatile int32_t QB_GNUC_MAY_ALIAS * atomic,
int32_t newval)
{
*atomic = newval;
QB_ATOMIC_MEMORY_BARRIER;
}
void *
(qb_atomic_pointer_get) (volatile void *QB_GNUC_MAY_ALIAS * atomic)
{
QB_ATOMIC_MEMORY_BARRIER;
return (void*)*atomic;
}
void
(qb_atomic_pointer_set) (volatile void *QB_GNUC_MAY_ALIAS * atomic,
void *newval)
{
*atomic = newval;
QB_ATOMIC_MEMORY_BARRIER;
}
#endif /* QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED */
#endif /* HAVE_GCC_BUILTINS_FOR_SYNC_OPERATIONS */
#ifndef QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED
int32_t
(qb_atomic_int_get) (volatile int32_t QB_GNUC_MAY_ALIAS * atomic)
{
return qb_atomic_int_get(atomic);
}
void
(qb_atomic_int_set) (volatile int32_t QB_GNUC_MAY_ALIAS * atomic,
int32_t newval)
{
qb_atomic_int_set(atomic, newval);
}
void *
(qb_atomic_pointer_get) (volatile void *QB_GNUC_MAY_ALIAS * atomic)
{
return qb_atomic_pointer_get(atomic);
}
void
(qb_atomic_pointer_set) (volatile void *QB_GNUC_MAY_ALIAS * atomic,
void *newval)
{
qb_atomic_pointer_set(atomic, newval);
}
#endif /* !QB_ATOMIC_OP_MEMORY_BARRIER_NEEDED */

File Metadata

Mime Type
text/x-diff
Expires
Mon, Apr 21, 2:19 PM (1 d, 7 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1664914
Default Alt Text
(53 KB)

Event Timeline