From 49617de1d80d771ac9a1d45b1710b16fac65e0aa Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Thu, 8 Oct 2009 17:36:31 -0400 Subject: [PATCH] Compat futex Signed-off-by: Mathieu Desnoyers --- Makefile.am | 2 +- compat_futex.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 15 +++--- urcu-pointer.c | 2 + urcu/arch_ppc.h | 3 +- urcu/arch_s390.h | 9 ++++ urcu/arch_x86.h | 4 +- urcu/config.h.in | 12 +++++ urcu/urcu-futex.h | 58 +++++++++++++++++++++++ 9 files changed, 207 insertions(+), 13 deletions(-) create mode 100644 compat_futex.c create mode 100644 urcu/config.h.in create mode 100644 urcu/urcu-futex.h diff --git a/Makefile.am b/Makefile.am index df67b1e..e485834 100644 --- a/Makefile.am +++ b/Makefile.am @@ -37,7 +37,7 @@ liburcu_defer_la_SOURCES = urcu-defer.c $(COMPAT) liburcu_qsbr_la_SOURCES = urcu-qsbr.c urcu-pointer.c $(COMPAT) -*.h *.c: urcu/arch.h urcu/uatomic_arch.h +$(top_srcdir)/*.h $(top_srcdir)/*.c: urcu/arch.h urcu/uatomic_arch.h urcu/arch.h: $(top_srcdir)/urcu/arch_@ARCHTYPE@.h $(MKDIR_P) $(top_builddir)/urcu diff --git a/compat_futex.c b/compat_futex.c new file mode 100644 index 0000000..27fc66b --- /dev/null +++ b/compat_futex.c @@ -0,0 +1,115 @@ +/* + * compat_futex.c + * + * Userspace RCU library - sys_futex compatibility code + * + * Copyright (c) 2009 Mathieu Desnoyers + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include + +#include +#include + +static pthread_mutex_t compat_futex_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t compat_futex_cond = PTHREAD_COND_INITIALIZER; + +/* + * _NOT SIGNAL-SAFE_. pthread_cond is not signal-safe anyway. Though. + * For now, timeout, uaddr2 and val3 are unused. + * Waiter will relinquish the CPU until woken up. + */ + +int compat_futex_noasync(int *uaddr, int op, int val, + const struct timespec *timeout, int *uaddr2, int val3) +{ + int ret, i, gret = 0; + + /* + * Check if NULL. Don't let users expect that they are taken into + * account. + */ + assert(!timeout); + assert(!uaddr2); + assert(!val3); + + /* + * memory barriers to serialize with the previous uaddr modification. + */ + smp_mb(); + + ret = pthread_mutex_lock(&compat_futex_lock); + assert(!ret); + switch (op) { + case FUTEX_WAIT: + if (*uaddr != val) + goto end; + pthread_cond_wait(&compat_futex_cond, &compat_futex_lock); + break; + case FUTEX_WAKE: + for (i = 0; i < val; i++) + pthread_cond_signal(&compat_futex_cond); + break; + default: + gret = -EINVAL; + } +end: + ret = pthread_mutex_unlock(&compat_futex_lock); + assert(!ret); + return gret; +} + +/* + * _ASYNC SIGNAL-SAFE_. + * For now, timeout, uaddr2 and val3 are unused. + * Waiter will busy-loop trying to read the condition. + */ + +int compat_futex_async(int *uaddr, int op, int val, + const struct timespec *timeout, int *uaddr2, int val3) +{ + int ret, i; + + /* + * Check if NULL. Don't let users expect that they are taken into + * account. + */ + assert(!timeout); + assert(!uaddr2); + assert(!val3); + + /* + * Ensure previous memory operations on uaddr have completed. + */ + smp_mb(); + + switch (op) { + case FUTEX_WAIT: + while (*uaddr == val) + poll(NULL, 0, 10); + break; + case FUTEX_WAKE: + break; + default: + return -EINVAL; + } +} diff --git a/configure.ac b/configure.ac index e7cc181..be9fd72 100644 --- a/configure.ac +++ b/configure.ac @@ -9,10 +9,9 @@ AC_CANONICAL_HOST AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip]) AC_CONFIG_SRCDIR([urcu.h]) -AH_TEMPLATE([CONFIG_SMP], [Enable SMP support. With SMP support enabled, uniprocessors are also supported. With SMP support disabled, UP systems work fine, but the behavior of SMP systems is undefined.]) -AH_TEMPLATE([CONFIG_HAVE_FENCE], [Defined when on a system that has memory fence -instructions.]) -AH_TEMPLATE([CONFIG_HAVE_FUTEX], [Defined when on a system with futex support.]) +AH_TEMPLATE([CONFIG_URCU_SMP], [Enable SMP support. With SMP support enabled, uniprocessors are also supported. With SMP support disabled, UP systems work fine, but the behavior of SMP systems is undefined.]) +AH_TEMPLATE([CONFIG_URCU_HAVE_FENCE], [Defined when on a system that has memory fence instructions.]) +AH_TEMPLATE([CONFIG_URCU_HAVE_FUTEX], [Defined when on a system with futex support.]) AC_CONFIG_HEADERS([urcu/config.h]) # Checks for programs. @@ -55,12 +54,12 @@ AC_SUBST(SUBARCHTYPE) [ if test "x$ARCHTYPE" = "xx86" -a "x$target_cpu" != "xi386" -a "x$target_cpu" != "xi486" -a "x$target_cpu" != "xi586"; then ] - AC_DEFINE([CONFIG_HAVE_FENCE], [1]) + AC_DEFINE([CONFIG_URCU_HAVE_FENCE], [1]) [ fi ] -AC_MSG_CHECKING([presence of sys_futex()]) +AC_MSG_CHECKING([sys_futex()]) AC_TRY_COMPILE( [ #include @@ -72,7 +71,7 @@ AC_TRY_COMPILE( ], [ AC_MSG_RESULT([yes]) - AC_DEFINE([CONFIG_HAVE_FUTEX], [1]) + AC_DEFINE([CONFIG_URCU_HAVE_FUTEX], [1]) compat_futex_test=0 ] , @@ -96,7 +95,7 @@ if test "$def_smp_support" = "no"; then echo "SMP support disabled." else ] - AC_DEFINE([CONFIG_SMP], [1]) + AC_DEFINE([CONFIG_URCU_SMP], [1]) [ echo "SMP support enabled." fi diff --git a/urcu-pointer.c b/urcu-pointer.c index 79ee72a..83f0ffd 100644 --- a/urcu-pointer.c +++ b/urcu-pointer.c @@ -24,6 +24,8 @@ * IBM's contributions to this file may be relicensed under LGPLv2 or later. */ +#include + #include "urcu-pointer-static.h" /* Do not #define _LGPL_SOURCE to ensure we can emit the wrapper symbols */ #include "urcu-pointer.h" diff --git a/urcu/arch_ppc.h b/urcu/arch_ppc.h index 2f9460b..12b018e 100644 --- a/urcu/arch_ppc.h +++ b/urcu/arch_ppc.h @@ -25,7 +25,6 @@ #include #include -#define CONFIG_HAVE_FENCE 1 #define CONFIG_HAVE_MEM_COHERENCY /* Include size of POWER5+ L3 cache lines: 256 bytes */ @@ -54,7 +53,7 @@ #define rmc() barrier() #define wmc() barrier() -#ifdef CONFIG_SMP +#ifdef CONFIG_URCU_SMP #define smp_mb() mb() #define smp_rmb() rmb() #define smp_wmb() wmb() diff --git a/urcu/arch_s390.h b/urcu/arch_s390.h index aec91b9..bf46d3b 100644 --- a/urcu/arch_s390.h +++ b/urcu/arch_s390.h @@ -44,12 +44,21 @@ #define rmc() barrier() #define wmc() barrier() +#ifdef CONFIG_URCU_SMP #define smp_mb() mb() #define smp_rmb() rmb() #define smp_wmb() wmb() #define smp_mc() mc() #define smp_rmc() rmc() #define smp_wmc() wmc() +#else +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#define smp_mc() barrier() +#define smp_rmc() barrier() +#define smp_wmc() barrier() +#endif /* Nop everywhere except on alpha. */ #define smp_read_barrier_depends() diff --git a/urcu/arch_x86.h b/urcu/arch_x86.h index a72ef06..4ba08f7 100644 --- a/urcu/arch_x86.h +++ b/urcu/arch_x86.h @@ -33,7 +33,7 @@ #define BITS_PER_LONG (__SIZEOF_LONG__ * 8) #endif -#ifdef CONFIG_HAVE_FENCE +#ifdef CONFIG_URCU_HAVE_FENCE #define mb() asm volatile("mfence":::"memory") #define rmb() asm volatile("lfence":::"memory") #define wmb() asm volatile("sfence"::: "memory") @@ -62,7 +62,7 @@ #define rmc() barrier() #define wmc() barrier() -#ifdef CONFIG_SMP +#ifdef CONFIG_URCU_SMP #define smp_mb() mb() #define smp_rmb() rmb() #define smp_wmb() wmb() diff --git a/urcu/config.h.in b/urcu/config.h.in new file mode 100644 index 0000000..d61d2a9 --- /dev/null +++ b/urcu/config.h.in @@ -0,0 +1,12 @@ +/* urcu/config.h.in. Manually generatad for control over the contained defs. */ + +/* Defined when on a system that has memory fence instructions. */ +#undef CONFIG_URCU_HAVE_FENCE + +/* Defined when on a system with futex support. */ +#undef CONFIG_URCU_HAVE_FUTEX + +/* Enable SMP support. With SMP support enabled, uniprocessors are also + supported. With SMP support disabled, UP systems work fine, but the + behavior of SMP systems is undefined. */ +#undef CONFIG_URCU_SMP diff --git a/urcu/urcu-futex.h b/urcu/urcu-futex.h new file mode 100644 index 0000000..14fb5c0 --- /dev/null +++ b/urcu/urcu-futex.h @@ -0,0 +1,58 @@ +#ifndef _URCU_FUTEX_H +#define _URCU_FUTEX_H + +/* + * urcu-futex.h + * + * Userspace RCU - sys_futex/compat_futex header. + * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +/* + * sys_futex compatibility header. + * Use *only* *either of* futex_noasync OR futex_async on a given address. + * + * futex_noasync cannot be executed in signal handlers, but ensures that + * it will be put in a wait queue even in compatibility mode. + * + * futex_async is signal-handler safe for the wakeup. It uses polling + * on the wait-side in compatibility mode. + */ + +#ifdef CONFIG_URCU_HAVE_FUTEX +#include +#define futex(...) syscall(__NR_futex, __VA_ARGS__) +#define futex_noasync(uaddr, op, val, timeout, uaddr2, val3) \ + futex(uaddr, op, val, timeout, uaddr2, val3) +#define futex_async(uaddr, op, val, timeout, uaddr2, val3) \ + futex(uaddr, op, val, timeout, uaddr2, val3) +#else +extern int compat_futex_noasync(int *uaddr, int op, int val, + const struct timespec *timeout, int *uaddr2, int val3); +#define futex_noasync(uaddr, op, val, timeout, uaddr2, val3) \ + compat_futex_noasync(uaddr, op, val, timeout, uaddr2, val3) +extern int compat_futex_async(int *uaddr, int op, int val, + const struct timespec *timeout, int *uaddr2, int val3); +#define futex_async(uaddr, op, val, timeout, uaddr2, val3) \ + compat_futex_async(uaddr, op, val, timeout, uaddr2, val3) +#endif + +#endif /* _URCU_FUTEX_H */ -- 2.34.1