diff options
Diffstat (limited to 'sysdeps')
-rw-r--r-- | sysdeps/i386/i486/bits/atomic.h | 206 |
1 files changed, 167 insertions, 39 deletions
diff --git a/sysdeps/i386/i486/bits/atomic.h b/sysdeps/i386/i486/bits/atomic.h index 541d7a5..218656b 100644 --- a/sysdeps/i386/i486/bits/atomic.h +++ b/sysdeps/i386/i486/bits/atomic.h @@ -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,30 +235,43 @@ 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 atomic_add(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_PREFIX "addb %b1, %0" \ + __asm __volatile (lock "addb %b1, %0" \ : "=m" (*mem) \ - : "ir" (value), "m" (*mem)); \ + : "ir" (value), "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ else if (sizeof (*mem) == 2) \ - __asm __volatile (LOCK_PREFIX "addw %w1, %0" \ + __asm __volatile (lock "addw %w1, %0" \ : "=m" (*mem) \ - : "ir" (value), "m" (*mem)); \ + : "ir" (value), "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ else if (sizeof (*mem) == 4) \ - __asm __volatile (LOCK_PREFIX "addl %1, %0" \ + __asm __volatile (lock "addl %1, %0" \ : "=m" (*mem) \ - : "ir" (value), "m" (*mem)); \ + : "ir" (value), "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ else \ { \ __typeof (value) __addval = (value); \ @@ -193,11 +280,20 @@ typedef uintmax_t uatomic_max_t; __typeof (*mem) __tmpval; \ do \ __tmpval = __oldval; \ - while ((__oldval = __arch_compare_and_exchange_val_64_acq \ + while ((__oldval = pfx##_compare_and_exchange_val_64_acq \ (__memp, __oldval + __addval, __oldval)) == __tmpval); \ } \ } while (0) +#define atomic_add(mem, value) \ + __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) \ ({ unsigned char __result; \ @@ -237,20 +333,23 @@ typedef uintmax_t uatomic_max_t; __result; }) -#define atomic_increment(mem) \ +#define __arch_increment_body(lock, pfx, mem) \ do { \ if (sizeof (*mem) == 1) \ - __asm __volatile (LOCK_PREFIX "incb %b0" \ + __asm __volatile (lock "incb %b0" \ : "=m" (*mem) \ - : "m" (*mem)); \ + : "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ else if (sizeof (*mem) == 2) \ - __asm __volatile (LOCK_PREFIX "incw %w0" \ + __asm __volatile (lock "incw %w0" \ : "=m" (*mem) \ - : "m" (*mem)); \ + : "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ else if (sizeof (*mem) == 4) \ - __asm __volatile (LOCK_PREFIX "incl %0" \ + __asm __volatile (lock "incl %0" \ : "=m" (*mem) \ - : "m" (*mem)); \ + : "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ else \ { \ __typeof (mem) __memp = (mem); \ @@ -258,11 +357,19 @@ typedef uintmax_t uatomic_max_t; __typeof (*mem) __tmpval; \ do \ __tmpval = __oldval; \ - while ((__oldval = __arch_compare_and_exchange_val_64_acq \ + 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) \ ({ unsigned char __result; \ @@ -283,20 +390,23 @@ typedef uintmax_t uatomic_max_t; __result; }) -#define atomic_decrement(mem) \ +#define __arch_decrement_body(lock, pfx, mem) \ do { \ if (sizeof (*mem) == 1) \ - __asm __volatile (LOCK_PREFIX "decb %b0" \ + __asm __volatile (lock "decb %b0" \ : "=m" (*mem) \ - : "m" (*mem)); \ + : "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ else if (sizeof (*mem) == 2) \ - __asm __volatile (LOCK_PREFIX "decw %w0" \ + __asm __volatile (lock "decw %w0" \ : "=m" (*mem) \ - : "m" (*mem)); \ + : "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ else if (sizeof (*mem) == 4) \ - __asm __volatile (LOCK_PREFIX "decl %0" \ + __asm __volatile (lock "decl %0" \ : "=m" (*mem) \ - : "m" (*mem)); \ + : "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ else \ { \ __typeof (mem) __memp = (mem); \ @@ -304,11 +414,19 @@ typedef uintmax_t uatomic_max_t; __typeof (*mem) __tmpval; \ do \ __tmpval = __oldval; \ - while ((__oldval = __arch_compare_and_exchange_val_64_acq \ + 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_increment_body (__arch_decrement_cprefix, __arch_c, mem) + #define atomic_decrement_and_test(mem) \ ({ unsigned char __result; \ @@ -389,20 +507,30 @@ typedef uintmax_t uatomic_max_t; } while (0) -#define atomic_or(mem, mask) \ +#define __arch_or_body(lock, mem, mask) \ do { \ if (sizeof (*mem) == 1) \ - __asm __volatile (LOCK_PREFIX "orb %1, %b0" \ + __asm __volatile (lock "orb %1, %b0" \ : "=m" (*mem) \ - : "ir" (mask), "m" (*mem)); \ + : "ir" (mask), "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ else if (sizeof (*mem) == 2) \ - __asm __volatile (LOCK_PREFIX "orw %1, %w0" \ + __asm __volatile (lock "orw %1, %w0" \ : "=m" (*mem) \ - : "ir" (mask), "m" (*mem)); \ + : "ir" (mask), "m" (*mem), \ + "i" (offsetof (tcbhead_t, multiple_threads))); \ else if (sizeof (*mem) == 4) \ - __asm __volatile (LOCK_PREFIX "orl %1, %0" \ + __asm __volatile (lock "orl %1, %0" \ : "=m" (*mem) \ - : "ir" (mask), "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) |