diff options
Diffstat (limited to 'sysdeps/i386/i486/bits/atomic.h')
-rw-r--r-- | sysdeps/i386/i486/bits/atomic.h | 370 |
1 files changed, 270 insertions, 100 deletions
diff --git a/sysdeps/i386/i486/bits/atomic.h b/sysdeps/i386/i486/bits/atomic.h index c748761758..a27734c37e 100644 --- a/sysdeps/i386/i486/bits/atomic.h +++ b/sysdeps/i386/i486/bits/atomic.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -18,6 +18,7 @@ 02111-1307 USA. */ #include <stdint.h> +#include <tls.h> /* For tcbhead_t. */ typedef int8_t atomic8_t; @@ -76,6 +77,40 @@ typedef uintmax_t uatomic_max_t; : "r" (newval), "m" (*mem), "0" (oldval)); \ ret; }) + +#define __arch_c_compare_and_exchange_val_8_acq(mem, newval, oldval) \ + ({ __typeof (*mem) ret; \ + __asm __volatile ("cmpl $0, %%gs:%P5\n\t" \ + "je 0f\n\t" \ + "lock\n" \ + "0:\tcmpxchgb %b2, %1" \ + : "=a" (ret), "=m" (*mem) \ + : "q" (newval), "m" (*mem), "0" (oldval), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + ret; }) + +#define __arch_c_compare_and_exchange_val_16_acq(mem, newval, oldval) \ + ({ __typeof (*mem) ret; \ + __asm __volatile ("cmpl $0, %%gs:%P5\n\t" \ + "je 0f\n\t" \ + "lock\n" \ + "0:\tcmpxchgw %w2, %1" \ + : "=a" (ret), "=m" (*mem) \ + : "r" (newval), "m" (*mem), "0" (oldval), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + ret; }) + +#define __arch_c_compare_and_exchange_val_32_acq(mem, newval, oldval) \ + ({ __typeof (*mem) ret; \ + __asm __volatile ("cmpl $0, %%gs:%P5\n\t" \ + "je 0f\n\t" \ + "lock\n" \ + "0:\tcmpxchgl %2, %1" \ + : "=a" (ret), "=m" (*mem) \ + : "r" (newval), "m" (*mem), "0" (oldval), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + ret; }) + /* XXX We do not really need 64-bit compare-and-exchange. At least not in the moment. Using it would mean causing portability problems since not many other 32-bit architectures have support for @@ -85,6 +120,8 @@ typedef uintmax_t uatomic_max_t; #if 1 # define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ ({ __typeof (*mem) ret = *(mem); abort (); ret = (newval); ret = (oldval); }) +# define __arch_c_compare_and_exchange_val_64_acq(mem, newval, oldval) \ + ({ __typeof (*mem) ret = *(mem); abort (); ret = (newval); ret = (oldval); }) #else # ifdef __PIC__ # define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ @@ -100,6 +137,24 @@ typedef uintmax_t uatomic_max_t; & 0xffffffff), \ "d" (((unsigned long long int) (oldval)) >> 32)); \ ret; }) + +# define __arch_c_compare_and_exchange_val_64_acq(mem, newval, oldval) \ + ({ __typeof (*mem) ret; \ + __asm __volatile ("xchgl %2, %%ebx\n\t" \ + "cmpl $0, %%gs:%P7\n\t" \ + "je 0f\n\t" \ + "lock\n" \ + "0:\tcmpxchg8b %1\n\t" \ + "xchgl %2, %%ebx" \ + : "=A" (ret), "=m" (*mem) \ + : "DS" (((unsigned long long int) (newval)) \ + & 0xffffffff), \ + "c" (((unsigned long long int) (newval)) >> 32), \ + "m" (*mem), "a" (((unsigned long long int) (oldval)) \ + & 0xffffffff), \ + "d" (((unsigned long long int) (oldval)) >> 32), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + ret; }) # else # define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ ({ __typeof (*mem) ret; \ @@ -112,6 +167,22 @@ typedef uintmax_t uatomic_max_t; & 0xffffffff), \ "d" (((unsigned long long int) (oldval)) >> 32)); \ ret; }) + +# define __arch_c_compare_and_exchange_val_64_acq(mem, newval, oldval) \ + ({ __typeof (*mem) ret; \ + __asm __volatile ("cmpl $0, %%gs:%P7\n\t" \ + "je 0f\n\t" \ + "lock\n" \ + "0:\tcmpxchg8b %1" \ + : "=A" (ret), "=m" (*mem) \ + : "b" (((unsigned long long int) (newval)) \ + & 0xffffffff), \ + "c" (((unsigned long long int) (newval)) >> 32), \ + "m" (*mem), "a" (((unsigned long long int) (oldval)) \ + & 0xffffffff), \ + "d" (((unsigned long long int) (oldval)) >> 32), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + ret; }) # endif #endif @@ -139,21 +210,24 @@ typedef uintmax_t uatomic_max_t; result; }) -#define atomic_exchange_and_add(mem, value) \ +#define __arch_exchange_and_add_body(lock, pfx, mem, value) \ ({ __typeof (*mem) __result; \ __typeof (value) __addval = (value); \ if (sizeof (*mem) == 1) \ - __asm __volatile (LOCK_PREFIX "xaddb %b0, %1" \ + __asm __volatile (lock "xaddb %b0, %1" \ : "=r" (__result), "=m" (*mem) \ - : "0" (__addval), "m" (*mem)); \ + : "0" (__addval), "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ else if (sizeof (*mem) == 2) \ - __asm __volatile (LOCK_PREFIX "xaddw %w0, %1" \ + __asm __volatile (lock "xaddw %w0, %1" \ : "=r" (__result), "=m" (*mem) \ - : "0" (__addval), "m" (*mem)); \ + : "0" (__addval), "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ else if (sizeof (*mem) == 4) \ - __asm __volatile (LOCK_PREFIX "xaddl %0, %1" \ + __asm __volatile (lock "xaddl %0, %1" \ : "=r" (__result), "=m" (*mem) \ - : "0" (__addval), "m" (*mem)); \ + : "0" (__addval), "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ else \ { \ __typeof (mem) __memp = (mem); \ @@ -161,41 +235,64 @@ typedef uintmax_t uatomic_max_t; __result = *__memp; \ do \ __tmpval = __result; \ - while ((__result = __arch_compare_and_exchange_val_64_acq \ + while ((__result = pfx##_compare_and_exchange_val_64_acq \ (__memp, __result + __addval, __result)) == __tmpval); \ } \ __result; }) +#define atomic_exchange_and_add(mem, value) \ + __arch_exchange_and_add_body (LOCK_PREFIX, __arch, mem, value) + +#define __arch_exchange_and_add_cprefix \ + "cmpl $0, %%gs:%P4\n\tje 0f\n\tlock\n0:\t" + +#define catomic_exchange_and_add(mem, value) \ + __arch_exchange_and_add_body (__arch_exchange_and_add_cprefix, __arch_c, \ + mem, value) + + +#define __arch_add_body(lock, pfx, mem, value) \ + do { \ + if (__builtin_constant_p (value) && (value) == 1) \ + atomic_increment (mem); \ + else if (__builtin_constant_p (value) && (value) == -1) \ + atomic_decrement (mem); \ + else if (sizeof (*mem) == 1) \ + __asm __volatile (lock "addb %b1, %0" \ + : "=m" (*mem) \ + : "ir" (value), "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + else if (sizeof (*mem) == 2) \ + __asm __volatile (lock "addw %w1, %0" \ + : "=m" (*mem) \ + : "ir" (value), "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + else if (sizeof (*mem) == 4) \ + __asm __volatile (lock "addl %1, %0" \ + : "=m" (*mem) \ + : "ir" (value), "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + else \ + { \ + __typeof (value) __addval = (value); \ + __typeof (mem) __memp = (mem); \ + __typeof (*mem) __oldval = *__memp; \ + __typeof (*mem) __tmpval; \ + do \ + __tmpval = __oldval; \ + while ((__oldval = pfx##_compare_and_exchange_val_64_acq \ + (__memp, __oldval + __addval, __oldval)) == __tmpval); \ + } \ + } while (0) #define atomic_add(mem, value) \ - (void) ({ if (__builtin_constant_p (value) && (value) == 1) \ - atomic_increment (mem); \ - else if (__builtin_constant_p (value) && (value) == -1) \ - atomic_decrement (mem); \ - else if (sizeof (*mem) == 1) \ - __asm __volatile (LOCK_PREFIX "addb %b1, %0" \ - : "=m" (*mem) \ - : "ir" (value), "m" (*mem)); \ - else if (sizeof (*mem) == 2) \ - __asm __volatile (LOCK_PREFIX "addw %w1, %0" \ - : "=m" (*mem) \ - : "ir" (value), "m" (*mem)); \ - else if (sizeof (*mem) == 4) \ - __asm __volatile (LOCK_PREFIX "addl %1, %0" \ - : "=m" (*mem) \ - : "ir" (value), "m" (*mem)); \ - else \ - { \ - __typeof (value) __addval = (value); \ - __typeof (mem) __memp = (mem); \ - __typeof (*mem) __oldval = *__memp; \ - __typeof (*mem) __tmpval; \ - do \ - __tmpval = __oldval; \ - while ((__oldval = __arch_compare_and_exchange_val_64_acq \ - (__memp, __oldval + __addval, __oldval)) == __tmpval); \ - } \ - }) + __arch_add_body (LOCK_PREFIX, __arch, mem, value) + +#define __arch_add_cprefix \ + "cmpl $0, %%gs:%P3\n\tje 0f\n\tlock\n0:\t" + +#define catomic_add(mem, value) \ + __arch_add_body (__arch_add_cprefix, __arch_c, mem, value) #define atomic_add_negative(mem, value) \ @@ -236,30 +333,42 @@ typedef uintmax_t uatomic_max_t; __result; }) -#define atomic_increment(mem) \ - (void) ({ if (sizeof (*mem) == 1) \ - __asm __volatile (LOCK_PREFIX "incb %b0" \ - : "=m" (*mem) \ - : "m" (*mem)); \ - else if (sizeof (*mem) == 2) \ - __asm __volatile (LOCK_PREFIX "incw %w0" \ - : "=m" (*mem) \ - : "m" (*mem)); \ - else if (sizeof (*mem) == 4) \ - __asm __volatile (LOCK_PREFIX "incl %0" \ - : "=m" (*mem) \ - : "m" (*mem)); \ - else \ - { \ - __typeof (mem) __memp = (mem); \ - __typeof (*mem) __oldval = *__memp; \ - __typeof (*mem) __tmpval; \ - do \ - __tmpval = __oldval; \ - while ((__oldval = __arch_compare_and_exchange_val_64_acq \ - (__memp, __oldval + 1, __oldval)) == __tmpval); \ - } \ - }) +#define __arch_increment_body(lock, pfx, mem) \ + do { \ + if (sizeof (*mem) == 1) \ + __asm __volatile (lock "incb %b0" \ + : "=m" (*mem) \ + : "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + else if (sizeof (*mem) == 2) \ + __asm __volatile (lock "incw %w0" \ + : "=m" (*mem) \ + : "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + else if (sizeof (*mem) == 4) \ + __asm __volatile (lock "incl %0" \ + : "=m" (*mem) \ + : "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + else \ + { \ + __typeof (mem) __memp = (mem); \ + __typeof (*mem) __oldval = *__memp; \ + __typeof (*mem) __tmpval; \ + do \ + __tmpval = __oldval; \ + while ((__oldval = pfx##_compare_and_exchange_val_64_acq \ + (__memp, __oldval + 1, __oldval)) == __tmpval); \ + } \ + } while (0) + +#define atomic_increment(mem) __arch_increment_body (LOCK_PREFIX, __arch, mem) + +#define __arch_increment_cprefix \ + "cmpl $0, %%gs:%P2\n\tje 0f\n\tlock\n0:\t" + +#define catomic_increment(mem) \ + __arch_increment_body (__arch_increment_cprefix, __arch_c, mem) #define atomic_increment_and_test(mem) \ @@ -281,30 +390,42 @@ typedef uintmax_t uatomic_max_t; __result; }) -#define atomic_decrement(mem) \ - (void) ({ if (sizeof (*mem) == 1) \ - __asm __volatile (LOCK_PREFIX "decb %b0" \ - : "=m" (*mem) \ - : "m" (*mem)); \ - else if (sizeof (*mem) == 2) \ - __asm __volatile (LOCK_PREFIX "decw %w0" \ - : "=m" (*mem) \ - : "m" (*mem)); \ - else if (sizeof (*mem) == 4) \ - __asm __volatile (LOCK_PREFIX "decl %0" \ - : "=m" (*mem) \ - : "m" (*mem)); \ - else \ - { \ - __typeof (mem) __memp = (mem); \ - __typeof (*mem) __oldval = *__memp; \ - __typeof (*mem) __tmpval; \ - do \ - __tmpval = __oldval; \ - while ((__oldval = __arch_compare_and_exchange_val_64_acq \ - (__memp, __oldval - 1, __oldval)) == __tmpval); \ - } \ - }) +#define __arch_decrement_body(lock, pfx, mem) \ + do { \ + if (sizeof (*mem) == 1) \ + __asm __volatile (lock "decb %b0" \ + : "=m" (*mem) \ + : "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + else if (sizeof (*mem) == 2) \ + __asm __volatile (lock "decw %w0" \ + : "=m" (*mem) \ + : "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + else if (sizeof (*mem) == 4) \ + __asm __volatile (lock "decl %0" \ + : "=m" (*mem) \ + : "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + else \ + { \ + __typeof (mem) __memp = (mem); \ + __typeof (*mem) __oldval = *__memp; \ + __typeof (*mem) __tmpval; \ + do \ + __tmpval = __oldval; \ + while ((__oldval = pfx##_compare_and_exchange_val_64_acq \ + (__memp, __oldval - 1, __oldval)) == __tmpval); \ + } \ + } while (0) + +#define atomic_decrement(mem) __arch_decrement_body (LOCK_PREFIX, __arch, mem) + +#define __arch_decrement_cprefix \ + "cmpl $0, %%gs:%P2\n\tje 0f\n\tlock\n0:\t" + +#define catomic_decrement(mem) \ + __arch_decrement_body (__arch_decrement_cprefix, __arch_c, mem) #define atomic_decrement_and_test(mem) \ @@ -327,21 +448,22 @@ typedef uintmax_t uatomic_max_t; #define atomic_bit_set(mem, bit) \ - (void) ({ if (sizeof (*mem) == 1) \ - __asm __volatile (LOCK_PREFIX "orb %b2, %0" \ - : "=m" (*mem) \ - : "m" (*mem), "ir" (1 << (bit))); \ - else if (sizeof (*mem) == 2) \ - __asm __volatile (LOCK_PREFIX "orw %w2, %0" \ - : "=m" (*mem) \ - : "m" (*mem), "ir" (1 << (bit))); \ - else if (sizeof (*mem) == 4) \ - __asm __volatile (LOCK_PREFIX "orl %2, %0" \ - : "=m" (*mem) \ - : "m" (*mem), "ir" (1 << (bit))); \ - else \ - abort (); \ - }) + do { \ + if (sizeof (*mem) == 1) \ + __asm __volatile (LOCK_PREFIX "orb %b2, %0" \ + : "=m" (*mem) \ + : "m" (*mem), "ir" (1 << (bit))); \ + else if (sizeof (*mem) == 2) \ + __asm __volatile (LOCK_PREFIX "orw %w2, %0" \ + : "=m" (*mem) \ + : "m" (*mem), "ir" (1 << (bit))); \ + else if (sizeof (*mem) == 4) \ + __asm __volatile (LOCK_PREFIX "orl %2, %0" \ + : "=m" (*mem) \ + : "m" (*mem), "ir" (1 << (bit))); \ + else \ + abort (); \ + } while (0) #define atomic_bit_test_set(mem, bit) \ @@ -364,3 +486,51 @@ typedef uintmax_t uatomic_max_t; #define atomic_delay() asm ("rep; nop") + + +#define atomic_and(mem, mask) \ + do { \ + if (sizeof (*mem) == 1) \ + __asm __volatile (LOCK_PREFIX "andb %1, %b0" \ + : "=m" (*mem) \ + : "ir" (mask), "m" (*mem)); \ + else if (sizeof (*mem) == 2) \ + __asm __volatile (LOCK_PREFIX "andw %1, %w0" \ + : "=m" (*mem) \ + : "ir" (mask), "m" (*mem)); \ + else if (sizeof (*mem) == 4) \ + __asm __volatile (LOCK_PREFIX "andl %1, %0" \ + : "=m" (*mem) \ + : "ir" (mask), "m" (*mem)); \ + else \ + abort (); \ + } while (0) + + +#define __arch_or_body(lock, mem, mask) \ + do { \ + if (sizeof (*mem) == 1) \ + __asm __volatile (lock "orb %1, %b0" \ + : "=m" (*mem) \ + : "ir" (mask), "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + else if (sizeof (*mem) == 2) \ + __asm __volatile (lock "orw %1, %w0" \ + : "=m" (*mem) \ + : "ir" (mask), "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + else if (sizeof (*mem) == 4) \ + __asm __volatile (lock "orl %1, %0" \ + : "=m" (*mem) \ + : "ir" (mask), "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ + else \ + abort (); \ + } while (0) + +#define atomic_or(mem, mask) __arch_or_body (LOCK_PREFIX, mem, mask) + +#define __arch_or_cprefix \ + "cmpl $0, %%gs:%P3\n\tje 0f\n\tlock\n0:\t" + +#define catomic_or(mem, mask) __arch_or_body (__arch_or_cprefix, mem, mask) |