From bd502a39acf8ad5d95c78c51bb6d8a90ea6eb586 Mon Sep 17 00:00:00 2001 From: vsc Date: Fri, 15 Oct 2010 01:13:49 +0100 Subject: [PATCH] fix RW_locks for x86 (code from Erlang). --- OPTYap/locks_x86.h | 159 ++++++++++++++++++++++++++++----------------- 1 file changed, 101 insertions(+), 58 deletions(-) diff --git a/OPTYap/locks_x86.h b/OPTYap/locks_x86.h index 38b7e0bb9..d14befa95 100644 --- a/OPTYap/locks_x86.h +++ b/OPTYap/locks_x86.h @@ -7,7 +7,7 @@ ** OPTYap extends the Yap Prolog engine to support or-parallel tabling ** ** ** ** ** -** Yap Prolog was developed at University of Porto, Portugal ** +** YAP Prolog was developed at University of Porto, Portugal ** ** ** ************************************************************************/ @@ -34,18 +34,18 @@ static inline void spin_unlock(spinlock_t *lock) { /* To unlock we move 0 to the lock. -* On i386 this needs to be a locked operation -* to avoid Pentium Pro errata 66 and 92. -*/ + * On i386 this needs to be a locked operation + * to avoid Pentium Pro errata 66 and 92. + */ #if defined(__x86_64__) __asm__ __volatile__("" : : : "memory"); *(unsigned char*)&lock->lock = 0; #else char tmp = 0; __asm__ __volatile__( -"xchgb %b0, %1" -: "=q"(tmp), "=m"(lock->lock) -: "0"(tmp) : "memory"); + "xchgb %b0, %1" + : "=q"(tmp), "=m"(lock->lock) + : "0"(tmp) : "memory"); #endif } @@ -60,68 +60,111 @@ spin_unlock(spinlock_t *lock) #define IS_UNLOCKED(LOCK_VAR) ((LOCK_VAR) == 0) #define UNLOCK(LOCK_VAR) spin_unlock((spinlock_t *)&(LOCK_VAR)) -/* This code has been copied from the sources of the Linux kernel */ +/* the code that follows has been adapted from the Erlang sources */ -/* - * On x86, we implement read-write locks as a 32-bit counter - * with the high bit (sign) being the "contended" bit. - * - * The inline assembly is non-obvious. Think about it. - * - * Changed to use the same technique as rw semaphores. See - * semaphore.h for details. -ben - */ -/* the spinlock helpers are in arch/i386/kernel/semaphore.S */ +typedef struct { + volatile int lock; +} rwlock_t; -typedef struct { unsigned long a[100]; } __dummy_lock_t; -#define __dummy_lock(lock) (*(__dummy_lock_t *)(lock)) +#define RWLOCK_OFFSET (1<<24) -typedef struct { volatile unsigned int lock; } rwlock_t; - -#define RW_LOCK_BIAS 0x01000000 -#define RW_LOCK_BIAS_STR "0x01000000" - -#define RW_LOCK_UNLOCKED RW_LOCK_BIAS - -#define __build_read_lock(rw, helper) \ - asm volatile("lock\n" \ - "subl $1,(%0)\n\t" \ - "js 2f\n" \ - "1:\n" \ - ".section .text.lock,\"ax\"\n" \ - "2:\tcall __read_lock_failed\n\t" \ - "jmp 1b\n" \ - ".previous" \ - ::"a" (rw) : "memory") - -#define __build_write_lock(rw, helper) \ - asm volatile("lock\n"\ - "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \ - "jnz 2f\n" \ - "1:\n" \ - ".section .text.lock,\"ax\"\n" \ - "2:\tcall __write_lock_failed\n\t" \ - "jmp 1b\n" \ - ".previous" \ - ::"a" (rw) : "memory") - -static inline void read_lock(rwlock_t *rw) +static inline void +init_rwlock(rwlock_t *lock) { - __build_read_lock(rw, "__read_lock_failed"); + lock->lock = 0; } -static inline void write_lock(rwlock_t *rw) +static inline void +read_unlock(rwlock_t *lock) { - __build_write_lock(rw, "__write_lock_failed"); + __asm__ __volatile__( + "lock; decl %0" + : "=m"(lock->lock) + : "m"(lock->lock) + ); } +static inline int +read_trylock(rwlock_t *lock) +{ + int tmp; -#define READ_LOCK(X) read_lock(&(X)) -#define WRITE_LOCK(X) write_lock(&(X)) + tmp = 1; + __asm__ __volatile__( + "lock; xaddl %0, %1" + : "=r"(tmp) + : "m"(lock->lock), "0"(tmp)); + /* tmp is now the lock's previous value */ + if (__builtin_expect(tmp >= 0, 1)) + return 1; + read_unlock(lock); + return 0; +} -#define READ_UNLOCK(rw) asm volatile("lock ; incl %0" :"=m" (__dummy_lock(&(rw)))) -#define WRITE_UNLOCK(rw) asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0":"=m" (__dummy_lock(&(rw)))) +static inline int +read_is_locked(rwlock_t *lock) +{ + return lock->lock < 0; +} -#define INIT_RWLOCK(RW) (RW).lock = RW_LOCK_UNLOCKED +static inline void +read_lock(rwlock_t *lock) +{ + for(;;) { + if (__builtin_expect(read_trylock(lock) != 0, 1)) + break; + do { + __asm__ __volatile__("rep;nop" : "=m"(lock->lock) : : "memory"); + } while (read_is_locked(lock)); + } +} +static inline void +write_unlock(rwlock_t *lock) +{ + __asm__ __volatile__( + "lock; addl %2,%0" + : "=m"(lock->lock) + : "m"(lock->lock), "i"(RWLOCK_OFFSET)); +} +static inline int +write_trylock(rwlock_t *lock) +{ + int tmp; + + tmp = -RWLOCK_OFFSET; + __asm__ __volatile__( + "lock; xaddl %0, %1" + : "=r"(tmp) + : "m"(lock->lock), "0"(tmp)); + /* tmp is now the lock's previous value */ + if (__builtin_expect(tmp == 0, 1)) + return 1; + write_unlock(lock); + return 0; +} + +static inline int +write_is_locked(rwlock_t *lock) +{ + return lock->lock != 0; +} + +static inline void +write_lock(rwlock_t *lock) +{ + for(;;) { + if (__builtin_expect(write_trylock(lock) != 0, 1)) + break; + do { + __asm__ __volatile__("rep;nop" : "=m"(lock->lock) : : "memory"); + } while (write_is_locked(lock)); + } +} + +#define INIT_RWLOCK(lock) init_rwlock(&(lock)) +#define READ_LOCK(lock) read_lock(&(lock)) +#define READ_UNLOCK(lock) read_unlock(&(lock)) +#define WRITE_LOCK(lock) write_lock(&(lock)) +#define WRITE_UNLOCK(lock) write_unlock(&(lock))