Hello community, here is the log from the commit of package userspace-rcu for openSUSE:Factory checked in at 2013-11-29 12:05:36 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/userspace-rcu (Old) and /work/SRC/openSUSE:Factory/.userspace-rcu.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "userspace-rcu" Changes: -------- --- /work/SRC/openSUSE:Factory/userspace-rcu/userspace-rcu.changes 2013-09-11 13:23:34.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.userspace-rcu.new/userspace-rcu.changes 2013-11-29 12:05:39.000000000 +0100 @@ -1,0 +2,17 @@ +Tue Nov 26 15:07:34 UTC 2013 - pgaj...@suse.com + +- updated to 0.8.1: + * tls-compat: fix comment typo + * Keep ABI compatible with already compiled LGPL applications + * Fix: tls-compat multi-lib conflict + * Use cross compiler for doc examples + * gcc warning fixes: -Wsign-compare and -Wextra + * Fix: urcu-qsbr: reversed logic on RCU_DEBUG + * Fix: urcu-bp segfault in glibc pthread_kill() + * Fix urcu-bp: don't move registry + * Fix: compat futex duplicated lock and completion + * Fix: i386 compat code duplicated mutex instances + * Fix: urcu-bp: Bulletproof RCU arena resize bug + * Fix: test_mutex.c uninitialized mutex + +------------------------------------------------------------------- Old: ---- userspace-rcu-0.8.0.tar.bz2 userspace-rcu-0.8.0.tar.bz2.asc New: ---- userspace-rcu-0.8.1.tar.bz2 userspace-rcu-0.8.1.tar.bz2.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ userspace-rcu.spec ++++++ --- /var/tmp/diff_new_pack.v3DpEj/_old 2013-11-29 12:05:39.000000000 +0100 +++ /var/tmp/diff_new_pack.v3DpEj/_new 2013-11-29 12:05:39.000000000 +0100 @@ -19,7 +19,7 @@ Name: userspace-rcu -Version: 0.8.0 +Version: 0.8.1 Release: 0 %define soname 2 Summary: Userspace Read-Copy-Update Library ++++++ userspace-rcu-0.8.0.tar.bz2 -> userspace-rcu-0.8.1.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/userspace-rcu-0.8.0/ChangeLog new/userspace-rcu-0.8.1/ChangeLog --- old/userspace-rcu-0.8.0/ChangeLog 2013-09-06 13:58:25.000000000 +0200 +++ new/userspace-rcu-0.8.1/ChangeLog 2013-11-12 17:08:39.000000000 +0100 @@ -1,3 +1,17 @@ +2013-11-12 Userspace RCU 0.8.1 + * tls-compat: fix comment typo + * Keep ABI compatible with already compiled LGPL applications + * Fix: tls-compat multi-lib conflict + * Use cross compiler for doc examples + * gcc warning fixes: -Wsign-compare and -Wextra + * Fix: urcu-qsbr: reversed logic on RCU_DEBUG + * Fix: urcu-bp segfault in glibc pthread_kill() + * Fix urcu-bp: don't move registry + * Fix: compat futex duplicated lock and completion + * Fix: i386 compat code duplicated mutex instances + * Fix: urcu-bp: Bulletproof RCU arena resize bug + * Fix: test_mutex.c uninitialized mutex + 2013-09-06 Userspace RCU 0.8.0 * Fix: hash table growth (for small tables) should be limited * Fix: doc/examples cross-build diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/userspace-rcu-0.8.0/compat_arch_x86.c new/userspace-rcu-0.8.1/compat_arch_x86.c --- old/userspace-rcu-0.8.0/compat_arch_x86.c 2013-05-14 16:18:25.000000000 +0200 +++ new/userspace-rcu-0.8.1/compat_arch_x86.c 2013-11-11 23:10:16.000000000 +0100 @@ -27,6 +27,14 @@ #include <urcu/uatomic.h> /* + * Using attribute "weak" for __rcu_cas_avail and + * __urcu_x86_compat_mutex. Those are globally visible by the entire + * program, even though many shared objects may have their own version. + * The first version that gets loaded will be used by the entire + * program (executable and all shared objects). + */ + +/* * It does not really matter if the constructor is called before using * the library, as long as the caller checks if __rcu_cas_avail < 0 and calls * compat_arch_init() explicitely if needed. @@ -38,9 +46,11 @@ * 1: available * 0: unavailable */ +__attribute__((weak)) int __rcu_cas_avail = -1; -static pthread_mutex_t compat_mutex = PTHREAD_MUTEX_INITIALIZER; +__attribute__((weak)) +pthread_mutex_t __urcu_x86_compat_mutex = PTHREAD_MUTEX_INITIALIZER; /* * get_eflags/set_eflags/compare_and_swap_is_available imported from glibc @@ -84,7 +94,7 @@ assert(!ret); ret = pthread_sigmask(SIG_BLOCK, &newmask, oldmask); assert(!ret); - ret = pthread_mutex_lock(&compat_mutex); + ret = pthread_mutex_lock(&__urcu_x86_compat_mutex); assert(!ret); } @@ -92,7 +102,7 @@ { int ret; - ret = pthread_mutex_unlock(&compat_mutex); + ret = pthread_mutex_unlock(&__urcu_x86_compat_mutex); assert(!ret); ret = pthread_sigmask(SIG_SETMASK, oldmask, NULL); assert(!ret); @@ -103,7 +113,7 @@ sigset_t mask; unsigned long result; - mutex_lock_signal_save(&compat_mutex, &mask); + mutex_lock_signal_save(&__urcu_x86_compat_mutex, &mask); switch (len) { case 1: *(unsigned char *)addr = (unsigned char)_new; @@ -125,7 +135,7 @@ result = 0; __asm__ __volatile__("ud2"); } - mutex_lock_signal_restore(&compat_mutex, &mask); + mutex_lock_signal_restore(&__urcu_x86_compat_mutex, &mask); return result; } @@ -134,7 +144,7 @@ sigset_t mask; unsigned long retval; - mutex_lock_signal_save(&compat_mutex, &mask); + mutex_lock_signal_save(&__urcu_x86_compat_mutex, &mask); switch (len) { case 1: retval = *(unsigned char *)addr; @@ -156,7 +166,7 @@ retval = 0; /* silence gcc warnings */ __asm__ __volatile__("ud2"); } - mutex_lock_signal_restore(&compat_mutex, &mask); + mutex_lock_signal_restore(&__urcu_x86_compat_mutex, &mask); return retval; } @@ -166,7 +176,7 @@ unsigned long retval; sigset_t mask; - mutex_lock_signal_save(&compat_mutex, &mask); + mutex_lock_signal_save(&__urcu_x86_compat_mutex, &mask); switch (len) { case 1: { @@ -200,7 +210,7 @@ retval = 0; /* silence gcc warnings */ __asm__ __volatile__("ud2"); } - mutex_lock_signal_restore(&compat_mutex, &mask); + mutex_lock_signal_restore(&__urcu_x86_compat_mutex, &mask); return retval; } @@ -208,7 +218,7 @@ { sigset_t mask; - mutex_lock_signal_save(&compat_mutex, &mask); + mutex_lock_signal_save(&__urcu_x86_compat_mutex, &mask); switch (len) { case 1: *(unsigned char *)addr |= (unsigned char)v; @@ -226,14 +236,14 @@ */ __asm__ __volatile__("ud2"); } - mutex_lock_signal_restore(&compat_mutex, &mask); + mutex_lock_signal_restore(&__urcu_x86_compat_mutex, &mask); } void _compat_uatomic_and(void *addr, unsigned long v, int len) { sigset_t mask; - mutex_lock_signal_save(&compat_mutex, &mask); + mutex_lock_signal_save(&__urcu_x86_compat_mutex, &mask); switch (len) { case 1: *(unsigned char *)addr &= (unsigned char)v; @@ -251,7 +261,7 @@ */ __asm__ __volatile__("ud2"); } - mutex_lock_signal_restore(&compat_mutex, &mask); + mutex_lock_signal_restore(&__urcu_x86_compat_mutex, &mask); } unsigned long _compat_uatomic_add_return(void *addr, unsigned long v, int len) @@ -259,7 +269,7 @@ sigset_t mask; unsigned long result; - mutex_lock_signal_save(&compat_mutex, &mask); + mutex_lock_signal_save(&__urcu_x86_compat_mutex, &mask); switch (len) { case 1: *(unsigned char *)addr += (unsigned char)v; @@ -281,7 +291,7 @@ result = 0; /* silence gcc warnings */ __asm__ __volatile__("ud2"); } - mutex_lock_signal_restore(&compat_mutex, &mask); + mutex_lock_signal_restore(&__urcu_x86_compat_mutex, &mask); return result; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/userspace-rcu-0.8.0/compat_futex.c new/userspace-rcu-0.8.1/compat_futex.c --- old/userspace-rcu-0.8.0/compat_futex.c 2013-07-04 21:33:07.000000000 +0200 +++ new/userspace-rcu-0.8.1/compat_futex.c 2013-11-11 23:10:16.000000000 +0100 @@ -31,8 +31,18 @@ #include <urcu/arch.h> #include <urcu/futex.h> -static pthread_mutex_t compat_futex_lock = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t compat_futex_cond = PTHREAD_COND_INITIALIZER; +/* + * Using attribute "weak" for __urcu_compat_futex_lock and + * __urcu_compat_futex_cond. Those are globally visible by the entire + * program, even though many shared objects may have their own version. + * The first version that gets loaded will be used by the entire program + * (executable and all shared objects). + */ + +__attribute__((weak)) +pthread_mutex_t __urcu_compat_futex_lock = PTHREAD_MUTEX_INITIALIZER; +__attribute__((weak)) +pthread_cond_t __urcu_compat_futex_cond = PTHREAD_COND_INITIALIZER; /* * _NOT SIGNAL-SAFE_. pthread_cond is not signal-safe anyway. Though. @@ -58,22 +68,22 @@ */ cmm_smp_mb(); - ret = pthread_mutex_lock(&compat_futex_lock); + ret = pthread_mutex_lock(&__urcu_compat_futex_lock); assert(!ret); switch (op) { case FUTEX_WAIT: if (*uaddr != val) goto end; - pthread_cond_wait(&compat_futex_cond, &compat_futex_lock); + pthread_cond_wait(&__urcu_compat_futex_cond, &__urcu_compat_futex_lock); break; case FUTEX_WAKE: - pthread_cond_broadcast(&compat_futex_cond); + pthread_cond_broadcast(&__urcu_compat_futex_cond); break; default: gret = -EINVAL; } end: - ret = pthread_mutex_unlock(&compat_futex_lock); + ret = pthread_mutex_unlock(&__urcu_compat_futex_lock); assert(!ret); return gret; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/userspace-rcu-0.8.0/configure new/userspace-rcu-0.8.1/configure --- old/userspace-rcu-0.8.0/configure 2013-09-04 16:01:42.000000000 +0200 +++ new/userspace-rcu-0.8.1/configure 2013-11-12 17:09:25.000000000 +0100 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for userspace-rcu 0.8.0. +# Generated by GNU Autoconf 2.69 for userspace-rcu 0.8.1. # # Report bugs to <mathieu dot desnoyers at efficios dot com>. # @@ -590,8 +590,8 @@ # Identity of this package. PACKAGE_NAME='userspace-rcu' PACKAGE_TARNAME='userspace-rcu' -PACKAGE_VERSION='0.8.0' -PACKAGE_STRING='userspace-rcu 0.8.0' +PACKAGE_VERSION='0.8.1' +PACKAGE_STRING='userspace-rcu 0.8.1' PACKAGE_BUGREPORT='mathieu dot desnoyers at efficios dot com' PACKAGE_URL='' @@ -1326,7 +1326,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures userspace-rcu 0.8.0 to adapt to many kinds of systems. +\`configure' configures userspace-rcu 0.8.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1397,7 +1397,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of userspace-rcu 0.8.0:";; + short | recursive ) echo "Configuration of userspace-rcu 0.8.1:";; esac cat <<\_ACEOF @@ -1504,7 +1504,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -userspace-rcu configure 0.8.0 +userspace-rcu configure 0.8.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1927,7 +1927,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by userspace-rcu $as_me 0.8.0, which was +It was created by userspace-rcu $as_me 0.8.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2863,7 +2863,7 @@ # Define the identity of the package. PACKAGE='userspace-rcu' - VERSION='0.8.0' + VERSION='0.8.1' cat >>confdefs.h <<_ACEOF @@ -13588,7 +13588,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by userspace-rcu $as_me 0.8.0, which was +This file was extended by userspace-rcu $as_me 0.8.1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13658,7 +13658,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -userspace-rcu config.status 0.8.0 +userspace-rcu config.status 0.8.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/userspace-rcu-0.8.0/configure.ac new/userspace-rcu-0.8.1/configure.ac --- old/userspace-rcu-0.8.0/configure.ac 2013-09-04 16:01:34.000000000 +0200 +++ new/userspace-rcu-0.8.1/configure.ac 2013-11-12 17:07:29.000000000 +0100 @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. -AC_INIT([userspace-rcu],[0.8.0],[mathieu dot desnoyers at efficios dot com]) +AC_INIT([userspace-rcu],[0.8.1],[mathieu dot desnoyers at efficios dot com]) # Following the numbering scheme proposed by libtool for the library version # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/userspace-rcu-0.8.0/doc/examples/Makefile.examples.template new/userspace-rcu-0.8.1/doc/examples/Makefile.examples.template --- old/userspace-rcu-0.8.0/doc/examples/Makefile.examples.template 2013-08-30 20:25:20.000000000 +0200 +++ new/userspace-rcu-0.8.1/doc/examples/Makefile.examples.template 2013-11-11 23:10:16.000000000 +0100 @@ -11,7 +11,9 @@ # # This makefile is purposefully kept simple to support GNU and BSD make. +ifndef CC CC = gcc +endif CFLAGS = -g -O2 -Wall all: $(BINARY) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/userspace-rcu-0.8.0/tests/benchmark/test_mutex.c new/userspace-rcu-0.8.1/tests/benchmark/test_mutex.c --- old/userspace-rcu-0.8.0/tests/benchmark/test_mutex.c 2013-08-30 20:25:20.000000000 +0200 +++ new/userspace-rcu-0.8.1/tests/benchmark/test_mutex.c 2013-11-11 23:10:16.000000000 +0100 @@ -52,7 +52,7 @@ int a; }; -static pthread_mutex_t lock; +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static volatile int test_go, test_stop; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/userspace-rcu-0.8.0/tests/benchmark/test_urcu_hash.c new/userspace-rcu-0.8.1/tests/benchmark/test_urcu_hash.c --- old/userspace-rcu-0.8.0/tests/benchmark/test_urcu_hash.c 2013-08-30 20:25:20.000000000 +0200 +++ new/userspace-rcu-0.8.1/tests/benchmark/test_urcu_hash.c 2013-11-12 17:06:57.000000000 +0100 @@ -82,13 +82,13 @@ return test_hash_cb[test_choice].populate_hash; } -DEFINE_URCU_TLS(unsigned int, rand_lookup); -DEFINE_URCU_TLS(unsigned long, nr_add); -DEFINE_URCU_TLS(unsigned long, nr_addexist); -DEFINE_URCU_TLS(unsigned long, nr_del); -DEFINE_URCU_TLS(unsigned long, nr_delnoent); -DEFINE_URCU_TLS(unsigned long, lookup_fail); -DEFINE_URCU_TLS(unsigned long, lookup_ok); +__DEFINE_URCU_TLS_GLOBAL(unsigned int, rand_lookup); +__DEFINE_URCU_TLS_GLOBAL(unsigned long, nr_add); +__DEFINE_URCU_TLS_GLOBAL(unsigned long, nr_addexist); +__DEFINE_URCU_TLS_GLOBAL(unsigned long, nr_del); +__DEFINE_URCU_TLS_GLOBAL(unsigned long, nr_delnoent); +__DEFINE_URCU_TLS_GLOBAL(unsigned long, lookup_fail); +__DEFINE_URCU_TLS_GLOBAL(unsigned long, lookup_ok); struct cds_lfht *test_ht; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/userspace-rcu-0.8.0/urcu/compiler.h new/userspace-rcu-0.8.1/urcu/compiler.h --- old/userspace-rcu-0.8.0/urcu/compiler.h 2013-08-30 20:25:20.000000000 +0200 +++ new/userspace-rcu-0.8.1/urcu/compiler.h 2013-11-11 23:10:16.000000000 +0100 @@ -86,10 +86,15 @@ #define URCU_FORCE_CAST(type, arg) ((type) (arg)) #endif -#define caa_is_signed_type(type) (((type) (-1)) < 0) +#define caa_is_signed_type(type) ((type) -1 < (type) 0) -#define caa_cast_long_keep_sign(v) \ - (caa_is_signed_type(__typeof__(v)) ? (long) (v) : (unsigned long) (v)) +/* + * Sign-extend to long if needed, and output type is unsigned long. + */ +#define caa_cast_long_keep_sign(v) \ + (caa_is_signed_type(__typeof__(v)) ? \ + (unsigned long) (long) (v) : \ + (unsigned long) (v)) #if defined (__GNUC__) \ && ((__GNUC_MAJOR__ == 4) && (__GNUC_MINOR__ >= 5) \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/userspace-rcu-0.8.0/urcu/tls-compat.h new/userspace-rcu-0.8.1/urcu/tls-compat.h --- old/userspace-rcu-0.8.0/urcu/tls-compat.h 2013-08-30 20:25:20.000000000 +0200 +++ new/userspace-rcu-0.8.1/urcu/tls-compat.h 2013-11-12 17:06:57.000000000 +0100 @@ -70,10 +70,22 @@ # define DEFINE_URCU_TLS(type, name) \ CONFIG_RCU_TLS type name +# define __DEFINE_URCU_TLS_GLOBAL(type, name) \ + CONFIG_RCU_TLS type name + # define URCU_TLS(name) (name) #else /* #ifndef CONFIG_RCU_TLS */ +/* + * The *_1() macros ensure macro parameters are expanded. + * + * __DEFINE_URCU_TLS_GLOBAL and __URCU_TLS_CALL exist for the sole + * purpose of notifying applications compiled against non-fixed 0.7 and + * 0.8 userspace RCU headers and using multiple flavors concurrently to + * recompile against fixed userspace RCU headers. + */ + # include <pthread.h> struct urcu_tls { @@ -82,15 +94,24 @@ int init_done; }; +# define DECLARE_URCU_TLS_1(type, name) \ + type *__tls_access2_ ## name(void) + # define DECLARE_URCU_TLS(type, name) \ - type *__tls_access_ ## name(void) + DECLARE_URCU_TLS_1(type, name) /* * Note: we don't free memory at process exit, since it will be dealt * with by the OS. */ -# define DEFINE_URCU_TLS(type, name) \ - type *__tls_access_ ## name(void) \ +# define __URCU_TLS_CALL_1(name) \ + __tls_access2_ ## name + +# define __URCU_TLS_CALL(name) \ + __URCU_TLS_CALL_1(name) + +# define DEFINE_URCU_TLS_1(type, name) \ + type *__tls_access2_ ## name(void) \ { \ static struct urcu_tls __tls_ ## name = { \ .init_mutex = PTHREAD_MUTEX_INITIALIZER,\ @@ -118,7 +139,34 @@ return __tls_p; \ } -# define URCU_TLS(name) (*__tls_access_ ## name()) +/* + * Define with and without macro expansion to handle erroneous callers. + * Trigger an abort() if the caller application uses the clashing symbol + * if a weak symbol is overridden. + */ +# define __DEFINE_URCU_TLS_GLOBAL(type, name) \ + DEFINE_URCU_TLS_1(type, name) \ + int __urcu_tls_symbol_refcount_ ## name __attribute__((weak)); \ + static __attribute__((constructor)) \ + void __urcu_tls_inc_refcount_ ## name(void) \ + { \ + __urcu_tls_symbol_refcount_ ## name++; \ + } \ + type *__tls_access_ ## name(void) \ + { \ + if (__urcu_tls_symbol_refcount_ ## name > 1) { \ + fprintf(stderr, "Error: Userspace RCU symbol clash for multiple concurrent flavors. Please upgrade liburcu libraries and headers, then recompile your application.\n"); \ + abort(); \ + } \ + return __URCU_TLS_CALL(name)(); \ + } + +# define DEFINE_URCU_TLS(type, name) \ + DEFINE_URCU_TLS_1(type, name) + +# define URCU_TLS_1(name) (*__tls_access2_ ## name()) + +# define URCU_TLS(name) URCU_TLS_1(name) #endif /* #else #ifndef CONFIG_RCU_TLS */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/userspace-rcu-0.8.0/urcu-bp.c new/userspace-rcu-0.8.1/urcu-bp.c --- old/userspace-rcu-0.8.0/urcu-bp.c 2013-08-30 20:25:20.000000000 +0200 +++ new/userspace-rcu-0.8.1/urcu-bp.c 2013-11-12 17:06:57.000000000 +0100 @@ -66,47 +66,46 @@ #define MREMAP_FIXED 2 /* - * mremap wrapper for non-Linux systems. Maps a RW, anonymous private mapping. + * mremap wrapper for non-Linux systems not allowing MAYMOVE. * This is not generic. */ static void *mremap_wrapper(void *old_address, size_t old_size, size_t new_size, int flags) { - void *new_address; + assert(!(flags & MREMAP_MAYMOVE)); - assert(flags & MREMAP_MAYMOVE); - assert(!(flags & MREMAP_FIXED)); - new_address = mmap(old_address, new_size, - PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, - -1, 0); - if (new_address == MAP_FAILED) - return MAP_FAILED; - if (old_address) { - memcpy(new_address, old_address, old_size); - munmap(old_address, old_size); - } - return new_address; + return MAP_FAILED; } #endif /* Sleep delay in us */ #define RCU_SLEEP_DELAY 1000 -#define ARENA_INIT_ALLOC 16 +#define INIT_NR_THREADS 8 +#define ARENA_INIT_ALLOC \ + sizeof(struct registry_chunk) \ + + INIT_NR_THREADS * sizeof(struct rcu_reader) /* * Active attempts to check for reader Q.S. before calling sleep(). */ #define RCU_QS_ACTIVE_ATTEMPTS 100 +static +void __attribute__((constructor)) rcu_bp_init(void); +static void __attribute__((destructor)) rcu_bp_exit(void); static pthread_mutex_t rcu_gp_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t init_lock = PTHREAD_MUTEX_INITIALIZER; +static int initialized; + +static pthread_key_t urcu_bp_key; + #ifdef DEBUG_YIELD unsigned int rcu_yield_active; -DEFINE_URCU_TLS(unsigned int, rcu_rand_yield); +__DEFINE_URCU_TLS_GLOBAL(unsigned int, rcu_rand_yield); #endif struct rcu_gp rcu_gp = { .ctr = RCU_GP_COUNT }; @@ -115,23 +114,28 @@ * Pointer to registry elements. Written to only by each individual reader. Read * by both the reader and the writers. */ -DEFINE_URCU_TLS(struct rcu_reader *, rcu_reader); +__DEFINE_URCU_TLS_GLOBAL(struct rcu_reader *, rcu_reader); static CDS_LIST_HEAD(registry); +struct registry_chunk { + size_t data_len; /* data length */ + size_t used; /* amount of data used */ + struct cds_list_head node; /* chunk_list node */ + char data[]; +}; + struct registry_arena { - void *p; - size_t len; - size_t used; + struct cds_list_head chunk_list; }; -static struct registry_arena registry_arena; +static struct registry_arena registry_arena = { + .chunk_list = CDS_LIST_HEAD_INIT(registry_arena.chunk_list), +}; /* Saved fork signal mask, protected by rcu_gp_lock */ static sigset_t saved_fork_signal_mask; -static void rcu_gc_registry(void); - static void mutex_lock(pthread_mutex_t *mutex) { int ret; @@ -228,9 +232,6 @@ /* Write new ptr before changing the qparity */ cmm_smp_mb(); - /* Remove old registry elements */ - rcu_gc_registry(); - /* * Wait for readers to observe original parity or be quiescent. */ @@ -301,82 +302,165 @@ } /* - * only grow for now. + * Only grow for now. If empty, allocate a ARENA_INIT_ALLOC sized chunk. + * Else, try expanding the last chunk. If this fails, allocate a new + * chunk twice as big as the last chunk. + * Memory used by chunks _never_ moves. A chunk could theoretically be + * freed when all "used" slots are released, but we don't do it at this + * point. */ -static void resize_arena(struct registry_arena *arena, size_t len) +static +void expand_arena(struct registry_arena *arena) { - void *new_arena; + struct registry_chunk *new_chunk, *last_chunk; + size_t old_chunk_len, new_chunk_len; - if (!arena->p) - new_arena = mmap(arena->p, len, - PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, - -1, 0); - else - new_arena = mremap_wrapper(arena->p, arena->len, - len, MREMAP_MAYMOVE); - assert(new_arena != MAP_FAILED); + /* No chunk. */ + if (cds_list_empty(&arena->chunk_list)) { + assert(ARENA_INIT_ALLOC >= + sizeof(struct registry_chunk) + + sizeof(struct rcu_reader)); + new_chunk_len = ARENA_INIT_ALLOC; + new_chunk = mmap(NULL, new_chunk_len, + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, + -1, 0); + if (new_chunk == MAP_FAILED) + abort(); + bzero(new_chunk, new_chunk_len); + new_chunk->data_len = + new_chunk_len - sizeof(struct registry_chunk); + cds_list_add_tail(&new_chunk->node, &arena->chunk_list); + return; /* We're done. */ + } - /* - * re-used the same region ? - */ - if (new_arena == arena->p) - return; + /* Try expanding last chunk. */ + last_chunk = cds_list_entry(arena->chunk_list.prev, + struct registry_chunk, node); + old_chunk_len = + last_chunk->data_len + sizeof(struct registry_chunk); + new_chunk_len = old_chunk_len << 1; + + /* Don't allow memory mapping to move, just expand. */ + new_chunk = mremap_wrapper(last_chunk, old_chunk_len, + new_chunk_len, 0); + if (new_chunk != MAP_FAILED) { + /* Should not have moved. */ + assert(new_chunk == last_chunk); + bzero((char *) last_chunk + old_chunk_len, + new_chunk_len - old_chunk_len); + last_chunk->data_len = + new_chunk_len - sizeof(struct registry_chunk); + return; /* We're done. */ + } - bzero(new_arena + arena->len, len - arena->len); - arena->p = new_arena; + /* Remap did not succeed, we need to add a new chunk. */ + new_chunk = mmap(NULL, new_chunk_len, + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, + -1, 0); + if (new_chunk == MAP_FAILED) + abort(); + bzero(new_chunk, new_chunk_len); + new_chunk->data_len = + new_chunk_len - sizeof(struct registry_chunk); + cds_list_add_tail(&new_chunk->node, &arena->chunk_list); } -/* Called with signals off and mutex locked */ -static void add_thread(void) +static +struct rcu_reader *arena_alloc(struct registry_arena *arena) { + struct registry_chunk *chunk; struct rcu_reader *rcu_reader_reg; + int expand_done = 0; /* Only allow to expand once per alloc */ + size_t len = sizeof(struct rcu_reader); - if (registry_arena.len - < registry_arena.used + sizeof(struct rcu_reader)) - resize_arena(®istry_arena, - caa_max(registry_arena.len << 1, ARENA_INIT_ALLOC)); - /* - * Find a free spot. - */ - for (rcu_reader_reg = registry_arena.p; - (void *)rcu_reader_reg < registry_arena.p + registry_arena.len; - rcu_reader_reg++) { - if (!rcu_reader_reg->alloc) - break; +retry: + cds_list_for_each_entry(chunk, &arena->chunk_list, node) { + if (chunk->data_len - chunk->used < len) + continue; + /* Find spot */ + for (rcu_reader_reg = (struct rcu_reader *) &chunk->data[0]; + rcu_reader_reg < (struct rcu_reader *) &chunk->data[chunk->data_len]; + rcu_reader_reg++) { + if (!rcu_reader_reg->alloc) { + rcu_reader_reg->alloc = 1; + chunk->used += len; + return rcu_reader_reg; + } + } + } + + if (!expand_done) { + expand_arena(arena); + expand_done = 1; + goto retry; } - rcu_reader_reg->alloc = 1; - registry_arena.used += sizeof(struct rcu_reader); + + return NULL; +} + +/* Called with signals off and mutex locked */ +static +void add_thread(void) +{ + struct rcu_reader *rcu_reader_reg; + int ret; + + rcu_reader_reg = arena_alloc(®istry_arena); + if (!rcu_reader_reg) + abort(); + ret = pthread_setspecific(urcu_bp_key, rcu_reader_reg); + if (ret) + abort(); /* Add to registry */ rcu_reader_reg->tid = pthread_self(); assert(rcu_reader_reg->ctr == 0); cds_list_add(&rcu_reader_reg->node, ®istry); + /* + * Reader threads are pointing to the reader registry. This is + * why its memory should never be relocated. + */ URCU_TLS(rcu_reader) = rcu_reader_reg; } -/* Called with signals off and mutex locked */ -static void rcu_gc_registry(void) +/* Called with mutex locked */ +static +void cleanup_thread(struct registry_chunk *chunk, + struct rcu_reader *rcu_reader_reg) { - struct rcu_reader *rcu_reader_reg; - pthread_t tid; - int ret; + rcu_reader_reg->ctr = 0; + cds_list_del(&rcu_reader_reg->node); + rcu_reader_reg->tid = 0; + rcu_reader_reg->alloc = 0; + chunk->used -= sizeof(struct rcu_reader); +} + +static +struct registry_chunk *find_chunk(struct rcu_reader *rcu_reader_reg) +{ + struct registry_chunk *chunk; - for (rcu_reader_reg = registry_arena.p; - (void *)rcu_reader_reg < registry_arena.p + registry_arena.len; - rcu_reader_reg++) { - if (!rcu_reader_reg->alloc) + cds_list_for_each_entry(chunk, ®istry_arena.chunk_list, node) { + if (rcu_reader_reg < (struct rcu_reader *) &chunk->data[0]) continue; - tid = rcu_reader_reg->tid; - ret = pthread_kill(tid, 0); - assert(ret != EINVAL); - if (ret == ESRCH) { - cds_list_del(&rcu_reader_reg->node); - rcu_reader_reg->ctr = 0; - rcu_reader_reg->alloc = 0; - registry_arena.used -= sizeof(struct rcu_reader); - } + if (rcu_reader_reg >= (struct rcu_reader *) &chunk->data[chunk->data_len]) + continue; + return chunk; } + return NULL; +} + +/* Called with signals off and mutex locked */ +static +void remove_thread(void) +{ + struct rcu_reader *rcu_reader_reg; + + rcu_reader_reg = URCU_TLS(rcu_reader); + cleanup_thread(find_chunk(rcu_reader_reg), rcu_reader_reg); + URCU_TLS(rcu_reader) = NULL; } /* Disable signals, take mutex, add to registry */ @@ -386,28 +470,95 @@ int ret; ret = sigfillset(&newmask); - assert(!ret); + if (ret) + abort(); ret = pthread_sigmask(SIG_BLOCK, &newmask, &oldmask); - assert(!ret); + if (ret) + abort(); /* * Check if a signal concurrently registered our thread since - * the check in rcu_read_lock(). */ + * the check in rcu_read_lock(). + */ if (URCU_TLS(rcu_reader)) goto end; + /* + * Take care of early registration before urcu_bp constructor. + */ + rcu_bp_init(); + mutex_lock(&rcu_gp_lock); add_thread(); mutex_unlock(&rcu_gp_lock); end: ret = pthread_sigmask(SIG_SETMASK, &oldmask, NULL); - assert(!ret); + if (ret) + abort(); +} + +/* Disable signals, take mutex, remove from registry */ +static +void rcu_bp_unregister(void) +{ + sigset_t newmask, oldmask; + int ret; + + ret = sigfillset(&newmask); + if (ret) + abort(); + ret = pthread_sigmask(SIG_BLOCK, &newmask, &oldmask); + if (ret) + abort(); + + mutex_lock(&rcu_gp_lock); + remove_thread(); + mutex_unlock(&rcu_gp_lock); + ret = pthread_sigmask(SIG_SETMASK, &oldmask, NULL); + if (ret) + abort(); } +/* + * Remove thread from the registry when it exits, and flag it as + * destroyed so garbage collection can take care of it. + */ +static +void urcu_bp_thread_exit_notifier(void *rcu_key) +{ + assert(rcu_key == URCU_TLS(rcu_reader)); + rcu_bp_unregister(); +} + +static +void rcu_bp_init(void) +{ + mutex_lock(&init_lock); + if (!initialized) { + int ret; + + ret = pthread_key_create(&urcu_bp_key, + urcu_bp_thread_exit_notifier); + if (ret) + abort(); + initialized = 1; + } + mutex_unlock(&init_lock); +} + +static void rcu_bp_exit(void) { - if (registry_arena.p) - munmap(registry_arena.p, registry_arena.len); + struct registry_chunk *chunk, *tmp; + int ret; + + cds_list_for_each_entry_safe(chunk, tmp, + ®istry_arena.chunk_list, node) { + munmap(chunk, chunk->data_len + sizeof(struct registry_chunk)); + } + ret = pthread_key_delete(urcu_bp_key); + if (ret) + abort(); } /* @@ -439,12 +590,35 @@ assert(!ret); } +/* + * Prune all entries from registry except our own thread. Fits the Linux + * fork behavior. Called with rcu_gp_lock held. + */ +static +void urcu_bp_prune_registry(void) +{ + struct registry_chunk *chunk; + struct rcu_reader *rcu_reader_reg; + + cds_list_for_each_entry(chunk, ®istry_arena.chunk_list, node) { + for (rcu_reader_reg = (struct rcu_reader *) &chunk->data[0]; + rcu_reader_reg < (struct rcu_reader *) &chunk->data[chunk->data_len]; + rcu_reader_reg++) { + if (!rcu_reader_reg->alloc) + continue; + if (rcu_reader_reg->tid == pthread_self()) + continue; + cleanup_thread(chunk, rcu_reader_reg); + } + } +} + void rcu_bp_after_fork_child(void) { sigset_t oldmask; int ret; - rcu_gc_registry(); + urcu_bp_prune_registry(); oldmask = saved_fork_signal_mask; mutex_unlock(&rcu_gp_lock); ret = pthread_sigmask(SIG_SETMASK, &oldmask, NULL); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/userspace-rcu-0.8.0/urcu-qsbr.c new/userspace-rcu-0.8.1/urcu-qsbr.c --- old/userspace-rcu-0.8.0/urcu-qsbr.c 2013-08-30 20:25:20.000000000 +0200 +++ new/userspace-rcu-0.8.1/urcu-qsbr.c 2013-11-12 17:06:57.000000000 +0100 @@ -64,11 +64,11 @@ * Written to only by each individual reader. Read by both the reader and the * writers. */ -DEFINE_URCU_TLS(struct rcu_reader, rcu_reader); +__DEFINE_URCU_TLS_GLOBAL(struct rcu_reader, rcu_reader); #ifdef DEBUG_YIELD unsigned int rcu_yield_active; -DEFINE_URCU_TLS(unsigned int, rcu_rand_yield); +__DEFINE_URCU_TLS_GLOBAL(unsigned int, rcu_rand_yield); #endif static CDS_LIST_HEAD(registry); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/userspace-rcu-0.8.0/urcu-qsbr.h new/userspace-rcu-0.8.1/urcu-qsbr.h --- old/userspace-rcu-0.8.0/urcu-qsbr.h 2013-08-30 20:25:20.000000000 +0200 +++ new/userspace-rcu-0.8.1/urcu-qsbr.h 2013-11-11 23:10:16.000000000 +0100 @@ -91,7 +91,7 @@ * library debugging & tracing features we could come up with. */ -#if (!defined(BUILD_QSBR_LIB) && defined(RCU_DEBUG)) +#if (!defined(BUILD_QSBR_LIB) && !defined(RCU_DEBUG)) static inline void rcu_read_lock(void) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/userspace-rcu-0.8.0/urcu.c new/userspace-rcu-0.8.1/urcu.c --- old/userspace-rcu-0.8.0/urcu.c 2013-08-30 20:25:20.000000000 +0200 +++ new/userspace-rcu-0.8.1/urcu.c 2013-11-12 17:06:57.000000000 +0100 @@ -107,11 +107,11 @@ * Written to only by each individual reader. Read by both the reader and the * writers. */ -DEFINE_URCU_TLS(struct rcu_reader, rcu_reader); +__DEFINE_URCU_TLS_GLOBAL(struct rcu_reader, rcu_reader); #ifdef DEBUG_YIELD unsigned int rcu_yield_active; -DEFINE_URCU_TLS(unsigned int, rcu_rand_yield); +__DEFINE_URCU_TLS_GLOBAL(unsigned int, rcu_rand_yield); #endif static CDS_LIST_HEAD(registry); -- To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org For additional commands, e-mail: opensuse-commit+h...@opensuse.org