OSDN Git Service

Added new 'bits/atomic.h' for most of the architectures and the top-level 'include...
author"Steven J. Hill" <sjhill@realitydiluted.com>
Thu, 12 May 2005 03:27:36 +0000 (03:27 -0000)
committer"Steven J. Hill" <sjhill@realitydiluted.com>
Thu, 12 May 2005 03:27:36 +0000 (03:27 -0000)
include/atomic.h [new file with mode: 0644]
libc/sysdeps/linux/alpha/bits/atomic.h [new file with mode: 0644]
libc/sysdeps/linux/common/bits/atomic.h [new file with mode: 0644]
libc/sysdeps/linux/i386/bits/atomic.h [new file with mode: 0644]
libc/sysdeps/linux/mips/bits/atomic.h [new file with mode: 0644]
libc/sysdeps/linux/sh/bits/atomic.h [new file with mode: 0644]
libc/sysdeps/linux/x86_64/bits/atomic.h [new file with mode: 0644]

diff --git a/include/atomic.h b/include/atomic.h
new file mode 100644 (file)
index 0000000..8a23f6e
--- /dev/null
@@ -0,0 +1,261 @@
+/* Internal macros for atomic operations for GNU C Library.
+   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C 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.
+
+   The GNU C 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 the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _ATOMIC_H
+#define _ATOMIC_H      1
+
+#include <stdlib.h>
+
+#include <bits/atomic.h>
+
+/* Wrapper macros to call pre_NN_post (mem, ...) where NN is the
+   bit width of *MEM.  The calling macro puts parens around MEM
+   and following args.  */
+#define __atomic_val_bysize(pre, post, mem, ...)                             \
+  ({                                                                         \
+    __typeof (*mem) __result;                                                \
+    if (sizeof (*mem) == 1)                                                  \
+      __result = pre##_8_##post (mem, __VA_ARGS__);                          \
+    else if (sizeof (*mem) == 2)                                             \
+      __result = pre##_16_##post (mem, __VA_ARGS__);                         \
+    else if (sizeof (*mem) == 4)                                             \
+      __result = pre##_32_##post (mem, __VA_ARGS__);                         \
+    else if (sizeof (*mem) == 8)                                             \
+      __result = pre##_64_##post (mem, __VA_ARGS__);                         \
+    else                                                                     \
+      abort ();                                                                      \
+    __result;                                                                \
+  })
+#define __atomic_bool_bysize(pre, post, mem, ...)                            \
+  ({                                                                         \
+    int __result;                                                            \
+    if (sizeof (*mem) == 1)                                                  \
+      __result = pre##_8_##post (mem, __VA_ARGS__);                          \
+    else if (sizeof (*mem) == 2)                                             \
+      __result = pre##_16_##post (mem, __VA_ARGS__);                         \
+    else if (sizeof (*mem) == 4)                                             \
+      __result = pre##_32_##post (mem, __VA_ARGS__);                         \
+    else if (sizeof (*mem) == 8)                                             \
+      __result = pre##_64_##post (mem, __VA_ARGS__);                         \
+    else                                                                     \
+      abort ();                                                                      \
+    __result;                                                                \
+  })
+
+
+/* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.
+   Return the old *MEM value.  */
+#if !defined atomic_compare_and_exchange_val_acq \
+    && defined __arch_compare_and_exchange_val_32_acq
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
+  __atomic_val_bysize (__arch_compare_and_exchange_val,acq,                  \
+                      mem, newval, oldval)
+#endif
+
+
+#ifndef atomic_compare_and_exchange_val_rel
+# define atomic_compare_and_exchange_val_rel(mem, newval, oldval)            \
+  atomic_compare_and_exchange_val_acq (mem, newval, oldval)
+#endif
+
+
+/* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.
+   Return zero if *MEM was changed or non-zero if no exchange happened.  */
+#ifndef atomic_compare_and_exchange_bool_acq
+# ifdef __arch_compare_and_exchange_bool_32_acq
+#  define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
+  __atomic_bool_bysize (__arch_compare_and_exchange_bool,acq,                \
+                       mem, newval, oldval)
+#  else
+#   define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
+  ({ /* Cannot use __oldval here, because macros later in this file might     \
+       call this macro with __oldval argument.  */                           \
+     __typeof (oldval) __old = (oldval);                                     \
+     atomic_compare_and_exchange_val_acq (mem, newval, __old) != __old;              \
+  })
+# endif
+#endif
+
+
+#ifndef atomic_compare_and_exchange_bool_rel
+# define atomic_compare_and_exchange_bool_rel(mem, newval, oldval) \
+  atomic_compare_and_exchange_bool_acq (mem, newval, oldval)
+#endif
+
+
+/* Store NEWVALUE in *MEM and return the old value.  */
+#ifndef atomic_exchange_acq
+# define atomic_exchange_acq(mem, newvalue) \
+  ({ __typeof (*(mem)) __oldval;                                             \
+     __typeof (mem) __memp = (mem);                                          \
+     __typeof (*(mem)) __value = (newvalue);                                 \
+                                                                             \
+     do                                                                              \
+       __oldval = (*__memp);                                                 \
+     while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp,   \
+                                                                   __value,  \
+                                                                   __oldval),\
+                             0));                                            \
+                                                                             \
+     __oldval; })
+#endif
+
+#ifndef atomic_exchange_rel
+# define atomic_exchange_rel(mem, newvalue) atomic_exchange_acq (mem, newvalue)
+#endif
+
+
+/* Add VALUE to *MEM and return the old value of *MEM.  */
+#ifndef atomic_exchange_and_add
+# define atomic_exchange_and_add(mem, value) \
+  ({ __typeof (*(mem)) __oldval;                                             \
+     __typeof (mem) __memp = (mem);                                          \
+     __typeof (*(mem)) __value = (value);                                    \
+                                                                             \
+     do                                                                              \
+       __oldval = (*__memp);                                                 \
+     while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp,   \
+                                                                   __oldval  \
+                                                                   + __value,\
+                                                                   __oldval),\
+                             0));                                            \
+                                                                             \
+     __oldval; })
+#endif
+
+
+#ifndef atomic_add
+# define atomic_add(mem, value) (void) atomic_exchange_and_add ((mem), (value))
+#endif
+
+
+#ifndef atomic_increment
+# define atomic_increment(mem) atomic_add ((mem), 1)
+#endif
+
+
+#ifndef atomic_increment_val
+# define atomic_increment_val(mem) (atomic_exchange_and_add ((mem), 1) + 1)
+#endif
+
+
+/* Add one to *MEM and return true iff it's now zero.  */
+#ifndef atomic_increment_and_test
+# define atomic_increment_and_test(mem) \
+  (atomic_exchange_and_add ((mem), 1) + 1 == 0)
+#endif
+
+
+#ifndef atomic_decrement
+# define atomic_decrement(mem) atomic_add ((mem), -1)
+#endif
+
+
+#ifndef atomic_decrement_val
+# define atomic_decrement_val(mem) (atomic_exchange_and_add ((mem), -1) - 1)
+#endif
+
+
+/* Subtract 1 from *MEM and return true iff it's now zero.  */
+#ifndef atomic_decrement_and_test
+# define atomic_decrement_and_test(mem) \
+  (atomic_exchange_and_add ((mem), -1) == 1)
+#endif
+
+
+/* Decrement *MEM if it is > 0, and return the old value.  */
+#ifndef atomic_decrement_if_positive
+# define atomic_decrement_if_positive(mem) \
+  ({ __typeof (*(mem)) __oldval;                                             \
+     __typeof (mem) __memp = (mem);                                          \
+                                                                             \
+     do                                                                              \
+       {                                                                     \
+        __oldval = *__memp;                                                  \
+        if (__builtin_expect (__oldval <= 0, 0))                             \
+          break;                                                             \
+       }                                                                     \
+     while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp,   \
+                                                                   __oldval  \
+                                                                   - 1,      \
+                                                                   __oldval),\
+                             0));\
+     __oldval; })
+#endif
+
+
+#ifndef atomic_add_negative
+# define atomic_add_negative(mem, value)                                     \
+  ({ __typeof (value) __aan_value = (value);                                 \
+     atomic_exchange_and_add (mem, __aan_value) < -__aan_value; })
+#endif
+
+
+#ifndef atomic_add_zero
+# define atomic_add_zero(mem, value)                                         \
+  ({ __typeof (value) __aaz_value = (value);                                 \
+     atomic_exchange_and_add (mem, __aaz_value) == -__aaz_value; })
+#endif
+
+
+#ifndef atomic_bit_set
+# define atomic_bit_set(mem, bit) \
+  (void) atomic_bit_test_set(mem, bit)
+#endif
+
+
+#ifndef atomic_bit_test_set
+# define atomic_bit_test_set(mem, bit) \
+  ({ __typeof (*(mem)) __oldval;                                             \
+     __typeof (mem) __memp = (mem);                                          \
+     __typeof (*(mem)) __mask = ((__typeof (*(mem))) 1 << (bit));            \
+                                                                             \
+     do                                                                              \
+       __oldval = (*__memp);                                                 \
+     while (__builtin_expect (atomic_compare_and_exchange_bool_acq (__memp,   \
+                                                                   __oldval  \
+                                                                   | __mask, \
+                                                                   __oldval),\
+                             0));                                            \
+                                                                             \
+     __oldval & __mask; })
+#endif
+
+
+#ifndef atomic_full_barrier
+# define atomic_full_barrier() __asm ("" ::: "memory")
+#endif
+
+
+#ifndef atomic_read_barrier
+# define atomic_read_barrier() atomic_full_barrier ()
+#endif
+
+
+#ifndef atomic_write_barrier
+# define atomic_write_barrier() atomic_full_barrier ()
+#endif
+
+
+#ifndef atomic_delay
+# define atomic_delay() do { /* nothing */ } while (0)
+#endif
+
+#endif /* atomic.h */
diff --git a/libc/sysdeps/linux/alpha/bits/atomic.h b/libc/sysdeps/linux/alpha/bits/atomic.h
new file mode 100644 (file)
index 0000000..36a740c
--- /dev/null
@@ -0,0 +1,369 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C 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.
+
+   The GNU C 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 the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdint.h>
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int16_t atomic16_t;
+typedef uint16_t uatomic16_t;
+typedef int_fast16_t atomic_fast16_t;
+typedef uint_fast16_t uatomic_fast16_t;
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+
+#ifdef UP
+# define __MB          /* nothing */
+#else
+# define __MB          "       mb\n"
+#endif
+
+
+/* Compare and exchange.  For all of the "xxx" routines, we expect a
+   "__prev" and a "__cmp" variable to be provided by the enclosing scope,
+   in which values are returned.  */
+
+#define __arch_compare_and_exchange_xxx_8_int(mem, new, old, mb1, mb2) \
+({                                                                     \
+  unsigned long __tmp, __snew, __addr64;                               \
+  __asm__ __volatile__ (                                               \
+               mb1                                                     \
+       "       andnot  %[__addr8],7,%[__addr64]\n"                     \
+       "       insbl   %[__new],%[__addr8],%[__snew]\n"                \
+       "1:     ldq_l   %[__tmp],0(%[__addr64])\n"                      \
+       "       extbl   %[__tmp],%[__addr8],%[__prev]\n"                \
+       "       cmpeq   %[__prev],%[__old],%[__cmp]\n"                  \
+       "       beq     %[__cmp],2f\n"                                  \
+       "       mskbl   %[__tmp],%[__addr8],%[__tmp]\n"                 \
+       "       or      %[__snew],%[__tmp],%[__tmp]\n"                  \
+       "       stq_c   %[__tmp],0(%[__addr64])\n"                      \
+       "       beq     %[__tmp],1b\n"                                  \
+               mb2                                                     \
+       "2:"                                                            \
+       : [__prev] "=&r" (__prev),                                      \
+         [__snew] "=&r" (__snew),                                      \
+         [__tmp] "=&r" (__tmp),                                        \
+         [__cmp] "=&r" (__cmp),                                        \
+         [__addr64] "=&r" (__addr64)                                   \
+       : [__addr8] "r" (mem),                                          \
+         [__old] "Ir" ((uint64_t)(uint8_t)(uint64_t)(old)),            \
+         [__new] "r" (new)                                             \
+       : "memory");                                                    \
+})
+
+#define __arch_compare_and_exchange_xxx_16_int(mem, new, old, mb1, mb2) \
+({                                                                     \
+  unsigned long __tmp, __snew, __addr64;                               \
+  __asm__ __volatile__ (                                               \
+               mb1                                                     \
+       "       andnot  %[__addr16],7,%[__addr64]\n"                    \
+       "       inswl   %[__new],%[__addr16],%[__snew]\n"               \
+       "1:     ldq_l   %[__tmp],0(%[__addr64])\n"                      \
+       "       extwl   %[__tmp],%[__addr16],%[__prev]\n"               \
+       "       cmpeq   %[__prev],%[__old],%[__cmp]\n"                  \
+       "       beq     %[__cmp],2f\n"                                  \
+       "       mskwl   %[__tmp],%[__addr16],%[__tmp]\n"                \
+       "       or      %[__snew],%[__tmp],%[__tmp]\n"                  \
+       "       stq_c   %[__tmp],0(%[__addr64])\n"                      \
+       "       beq     %[__tmp],1b\n"                                  \
+               mb2                                                     \
+       "2:"                                                            \
+       : [__prev] "=&r" (__prev),                                      \
+         [__snew] "=&r" (__snew),                                      \
+         [__tmp] "=&r" (__tmp),                                        \
+         [__cmp] "=&r" (__cmp),                                        \
+         [__addr64] "=&r" (__addr64)                                   \
+       : [__addr16] "r" (mem),                                         \
+         [__old] "Ir" ((uint64_t)(uint16_t)(uint64_t)(old)),           \
+         [__new] "r" (new)                                             \
+       : "memory");                                                    \
+})
+
+#define __arch_compare_and_exchange_xxx_32_int(mem, new, old, mb1, mb2) \
+({                                                                     \
+  __asm__ __volatile__ (                                               \
+               mb1                                                     \
+       "1:     ldl_l   %[__prev],%[__mem]\n"                           \
+       "       cmpeq   %[__prev],%[__old],%[__cmp]\n"                  \
+       "       beq     %[__cmp],2f\n"                                  \
+       "       mov     %[__new],%[__cmp]\n"                            \
+       "       stl_c   %[__cmp],%[__mem]\n"                            \
+       "       beq     %[__cmp],1b\n"                                  \
+               mb2                                                     \
+       "2:"                                                            \
+       : [__prev] "=&r" (__prev),                                      \
+         [__cmp] "=&r" (__cmp)                                         \
+       : [__mem] "m" (*(mem)),                                         \
+         [__old] "Ir" ((uint64_t)(atomic32_t)(uint64_t)(old)),         \
+         [__new] "Ir" (new)                                            \
+       : "memory");                                                    \
+})
+
+#define __arch_compare_and_exchange_xxx_64_int(mem, new, old, mb1, mb2) \
+({                                                                     \
+  __asm__ __volatile__ (                                               \
+               mb1                                                     \
+       "1:     ldq_l   %[__prev],%[__mem]\n"                           \
+       "       cmpeq   %[__prev],%[__old],%[__cmp]\n"                  \
+       "       beq     %[__cmp],2f\n"                                  \
+       "       mov     %[__new],%[__cmp]\n"                            \
+       "       stq_c   %[__cmp],%[__mem]\n"                            \
+       "       beq     %[__cmp],1b\n"                                  \
+               mb2                                                     \
+       "2:"                                                            \
+       : [__prev] "=&r" (__prev),                                      \
+         [__cmp] "=&r" (__cmp)                                         \
+       : [__mem] "m" (*(mem)),                                         \
+         [__old] "Ir" ((uint64_t)(old)),                               \
+         [__new] "Ir" (new)                                            \
+       : "memory");                                                    \
+})
+
+/* For all "bool" routines, we return FALSE if exchange succesful.  */
+
+#define __arch_compare_and_exchange_bool_8_int(mem, new, old, mb1, mb2)        \
+({ unsigned long __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_8_int(mem, new, old, mb1, mb2);     \
+   !__cmp; })
+
+#define __arch_compare_and_exchange_bool_16_int(mem, new, old, mb1, mb2) \
+({ unsigned long __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_16_int(mem, new, old, mb1, mb2);    \
+   !__cmp; })
+
+#define __arch_compare_and_exchange_bool_32_int(mem, new, old, mb1, mb2) \
+({ unsigned long __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_32_int(mem, new, old, mb1, mb2);    \
+   !__cmp; })
+
+#define __arch_compare_and_exchange_bool_64_int(mem, new, old, mb1, mb2) \
+({ unsigned long __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_64_int(mem, new, old, mb1, mb2);    \
+   !__cmp; })
+
+/* For all "val" routines, return the old value whether exchange
+   successful or not.  */
+
+#define __arch_compare_and_exchange_val_8_int(mem, new, old, mb1, mb2) \
+({ unsigned long __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_8_int(mem, new, old, mb1, mb2);     \
+   (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_16_int(mem, new, old, mb1, mb2) \
+({ unsigned long __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_16_int(mem, new, old, mb1, mb2);    \
+   (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_32_int(mem, new, old, mb1, mb2) \
+({ unsigned long __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_32_int(mem, new, old, mb1, mb2);    \
+   (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_64_int(mem, new, old, mb1, mb2) \
+({ unsigned long __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_64_int(mem, new, old, mb1, mb2);    \
+   (typeof (*mem))__prev; })
+
+/* Compare and exchange with "acquire" semantics, ie barrier after.  */
+
+#define atomic_compare_and_exchange_bool_acq(mem, new, old)    \
+  __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
+                       mem, new, old, "", __MB)
+
+#define atomic_compare_and_exchange_val_acq(mem, new, old)     \
+  __atomic_val_bysize (__arch_compare_and_exchange_val, int,   \
+                      mem, new, old, "", __MB)
+
+/* Compare and exchange with "release" semantics, ie barrier before.  */
+
+#define atomic_compare_and_exchange_bool_rel(mem, new, old)    \
+  __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
+                       mem, new, old, __MB, "")
+
+#define atomic_compare_and_exchange_val_rel(mem, new, old)     \
+  __atomic_val_bysize (__arch_compare_and_exchange_val, int,   \
+                      mem, new, old, __MB, "")
+
+
+/* Atomically store value and return the previous value.  */
+
+#define __arch_exchange_8_int(mem, value, mb1, mb2)                    \
+({                                                                     \
+  unsigned long __ret, __tmp, __addr64, __sval;                                \
+  __asm__ __volatile__ (                                               \
+               mb1                                                     \
+       "       andnot  %[__addr8],7,%[__addr64]\n"                     \
+       "       insbl   %[__value],%[__addr8],%[__sval]\n"              \
+       "1:     ldq_l   %[__tmp],0(%[__addr64])\n"                      \
+       "       extbl   %[__tmp],%[__addr8],%[__ret]\n"                 \
+       "       mskbl   %[__tmp],%[__addr8],%[__tmp]\n"                 \
+       "       or      %[__sval],%[__tmp],%[__tmp]\n"                  \
+       "       stq_c   %[__tmp],0(%[__addr64])\n"                      \
+       "       beq     %[__tmp],1b\n"                                  \
+               mb2                                                     \
+       : [__ret] "=&r" (__ret),                                        \
+         [__sval] "=&r" (__sval),                                      \
+         [__tmp] "=&r" (__tmp),                                        \
+         [__addr64] "=&r" (__addr64)                                   \
+       : [__addr8] "r" (mem),                                          \
+         [__value] "r" (value)                                         \
+       : "memory");                                                    \
+  __ret; })
+
+#define __arch_exchange_16_int(mem, value, mb1, mb2)                   \
+({                                                                     \
+  unsigned long __ret, __tmp, __addr64, __sval;                                \
+  __asm__ __volatile__ (                                               \
+               mb1                                                     \
+       "       andnot  %[__addr16],7,%[__addr64]\n"                    \
+       "       inswl   %[__value],%[__addr16],%[__sval]\n"             \
+       "1:     ldq_l   %[__tmp],0(%[__addr64])\n"                      \
+       "       extwl   %[__tmp],%[__addr16],%[__ret]\n"                \
+       "       mskwl   %[__tmp],%[__addr16],%[__tmp]\n"                \
+       "       or      %[__sval],%[__tmp],%[__tmp]\n"                  \
+       "       stq_c   %[__tmp],0(%[__addr64])\n"                      \
+       "       beq     %[__tmp],1b\n"                                  \
+               mb2                                                     \
+       : [__ret] "=&r" (__ret),                                        \
+         [__sval] "=&r" (__sval),                                      \
+         [__tmp] "=&r" (__tmp),                                        \
+         [__addr64] "=&r" (__addr64)                                   \
+       : [__addr16] "r" (mem),                                         \
+         [__value] "r" (value)                                         \
+       : "memory");                                                    \
+  __ret; })
+
+#define __arch_exchange_32_int(mem, value, mb1, mb2)                   \
+({                                                                     \
+  signed int __ret, __tmp;                                             \
+  __asm__ __volatile__ (                                               \
+               mb1                                                     \
+       "1:     ldl_l   %[__ret],%[__mem]\n"                            \
+       "       mov     %[__val],%[__tmp]\n"                            \
+       "       stl_c   %[__tmp],%[__mem]\n"                            \
+       "       beq     %[__tmp],1b\n"                                  \
+               mb2                                                     \
+       : [__ret] "=&r" (__ret),                                        \
+         [__tmp] "=&r" (__tmp)                                         \
+       : [__mem] "m" (*(mem)),                                         \
+         [__val] "Ir" (value)                                          \
+       : "memory");                                                    \
+  __ret; })
+
+#define __arch_exchange_64_int(mem, value, mb1, mb2)                   \
+({                                                                     \
+  unsigned long __ret, __tmp;                                          \
+  __asm__ __volatile__ (                                               \
+               mb1                                                     \
+       "1:     ldq_l   %[__ret],%[__mem]\n"                            \
+       "       mov     %[__val],%[__tmp]\n"                            \
+       "       stq_c   %[__tmp],%[__mem]\n"                            \
+       "       beq     %[__tmp],1b\n"                                  \
+               mb2                                                     \
+       : [__ret] "=&r" (__ret),                                        \
+         [__tmp] "=&r" (__tmp)                                         \
+       : [__mem] "m" (*(mem)),                                         \
+         [__val] "Ir" (value)                                          \
+       : "memory");                                                    \
+  __ret; })
+
+#define atomic_exchange_acq(mem, value) \
+  __atomic_val_bysize (__arch_exchange, int, mem, value, "", __MB)
+
+#define atomic_exchange_rel(mem, value) \
+  __atomic_val_bysize (__arch_exchange, int, mem, value, __MB, "")
+
+
+/* Atomically add value and return the previous (unincremented) value.  */
+
+#define __arch_exchange_and_add_8_int(mem, value, mb1, mb2) \
+  ({ __builtin_trap (); 0; })
+
+#define __arch_exchange_and_add_16_int(mem, value, mb1, mb2) \
+  ({ __builtin_trap (); 0; })
+
+#define __arch_exchange_and_add_32_int(mem, value, mb1, mb2)           \
+({                                                                     \
+  signed int __ret, __tmp;                                             \
+  __asm__ __volatile__ (                                               \
+               mb1                                                     \
+       "1:     ldl_l   %[__ret],%[__mem]\n"                            \
+       "       addl    %[__ret],%[__val],%[__tmp]\n"                   \
+       "       stl_c   %[__tmp],%[__mem]\n"                            \
+       "       beq     %[__tmp],1b\n"                                  \
+               mb2                                                     \
+       : [__ret] "=&r" (__ret),                                        \
+         [__tmp] "=&r" (__tmp)                                         \
+       : [__mem] "m" (*(mem)),                                         \
+         [__val] "Ir" ((signed int)(value))                            \
+       : "memory");                                                    \
+  __ret; })
+
+#define __arch_exchange_and_add_64_int(mem, value, mb1, mb2)           \
+({                                                                     \
+  unsigned long __ret, __tmp;                                          \
+  __asm__ __volatile__ (                                               \
+               mb1                                                     \
+       "1:     ldq_l   %[__ret],%[__mem]\n"                            \
+       "       addq    %[__ret],%[__val],%[__tmp]\n"                   \
+       "       stq_c   %[__tmp],%[__mem]\n"                            \
+       "       beq     %[__tmp],1b\n"                                  \
+               mb2                                                     \
+       : [__ret] "=&r" (__ret),                                        \
+         [__tmp] "=&r" (__tmp)                                         \
+       : [__mem] "m" (*(mem)),                                         \
+         [__val] "Ir" ((unsigned long)(value))                         \
+       : "memory");                                                    \
+  __ret; })
+
+/* ??? Barrier semantics for atomic_exchange_and_add appear to be 
+   undefined.  Use full barrier for now, as that's safe.  */
+#define atomic_exchange_and_add(mem, value) \
+  __atomic_val_bysize (__arch_exchange_and_add, int, mem, value, __MB, __MB)
+
+
+/* ??? Blah, I'm lazy.  Implement these later.  Can do better than the
+   compare-and-exchange loop provided by generic code.
+
+#define atomic_decrement_if_positive(mem)
+#define atomic_bit_test_set(mem, bit)
+
+*/
+
+#ifndef UP
+# define atomic_full_barrier() __asm ("mb" : : : "memory");
+# define atomic_read_barrier() __asm ("mb" : : : "memory");
+# define atomic_write_barrier()        __asm ("wmb" : : : "memory");
+#endif
diff --git a/libc/sysdeps/linux/common/bits/atomic.h b/libc/sysdeps/linux/common/bits/atomic.h
new file mode 100644 (file)
index 0000000..6245130
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+
+   The GNU C 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.
+
+   The GNU C 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 the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _BITS_ATOMIC_H
+#define _BITS_ATOMIC_H 1
+
+/* We have by default no support for atomic operations.  So define
+   them non-atomic.  If this is a problem somebody will have to come
+   up with real definitions.  */
+
+/* The only basic operation needed is compare and exchange.  */
+#define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
+  ({ __typeof (mem) __gmemp = (mem);                                 \
+     __typeof (*mem) __gret = *__gmemp;                                      \
+     __typeof (*mem) __gnewval = (newval);                           \
+                                                                     \
+     if (__gret == (oldval))                                         \
+       *__gmemp = __gnewval;                                         \
+     __gret; })
+
+#define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
+  ({ __typeof (mem) __gmemp = (mem);                                 \
+     __typeof (*mem) __gnewval = (newval);                           \
+                                                                     \
+     *__gmemp == (oldval) ? (*__gmemp = __gnewval, 0) : 1; })
+
+#endif /* bits/atomic.h */
diff --git a/libc/sysdeps/linux/i386/bits/atomic.h b/libc/sysdeps/linux/i386/bits/atomic.h
new file mode 100644 (file)
index 0000000..c748761
--- /dev/null
@@ -0,0 +1,366 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C 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.
+
+   The GNU C 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 the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdint.h>
+
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int16_t atomic16_t;
+typedef uint16_t uatomic16_t;
+typedef int_fast16_t atomic_fast16_t;
+typedef uint_fast16_t uatomic_fast16_t;
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+
+#ifndef LOCK_PREFIX
+# ifdef UP
+#  define LOCK_PREFIX  /* nothing */
+# else
+#  define LOCK_PREFIX "lock;"
+# endif
+#endif
+
+
+#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \
+  ({ __typeof (*mem) ret;                                                    \
+     __asm __volatile (LOCK_PREFIX "cmpxchgb %b2, %1"                        \
+                      : "=a" (ret), "=m" (*mem)                              \
+                      : "q" (newval), "m" (*mem), "0" (oldval));             \
+     ret; })
+
+#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \
+  ({ __typeof (*mem) ret;                                                    \
+     __asm __volatile (LOCK_PREFIX "cmpxchgw %w2, %1"                        \
+                      : "=a" (ret), "=m" (*mem)                              \
+                      : "r" (newval), "m" (*mem), "0" (oldval));             \
+     ret; })
+
+#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
+  ({ __typeof (*mem) ret;                                                    \
+     __asm __volatile (LOCK_PREFIX "cmpxchgl %2, %1"                         \
+                      : "=a" (ret), "=m" (*mem)                              \
+                      : "r" (newval), "m" (*mem), "0" (oldval));             \
+     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
+   such an operation.  So don't define any code for now.  If it is
+   really going to be used the code below can be used on Intel Pentium
+   and later, but NOT on i486.  */
+#if 1
+# define __arch_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) \
+  ({ __typeof (*mem) ret;                                                    \
+     __asm __volatile ("xchgl %2, %%ebx\n\t"                                 \
+                      LOCK_PREFIX "cmpxchg8b %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));    \
+     ret; })
+# else
+#  define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
+  ({ __typeof (*mem) ret;                                                    \
+     __asm __volatile (LOCK_PREFIX "cmpxchg8b %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));    \
+     ret; })
+# endif
+#endif
+
+
+/* Note that we need no lock prefix.  */
+#define atomic_exchange_acq(mem, newvalue) \
+  ({ __typeof (*mem) result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile ("xchgb %b0, %1"                                     \
+                        : "=r" (result), "=m" (*mem)                         \
+                        : "0" (newvalue), "m" (*mem));                       \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile ("xchgw %w0, %1"                                     \
+                        : "=r" (result), "=m" (*mem)                         \
+                        : "0" (newvalue), "m" (*mem));                       \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile ("xchgl %0, %1"                                              \
+                        : "=r" (result), "=m" (*mem)                         \
+                        : "0" (newvalue), "m" (*mem));                       \
+     else                                                                    \
+       {                                                                     \
+        result = 0;                                                          \
+        abort ();                                                            \
+       }                                                                     \
+     result; })
+
+
+#define atomic_exchange_and_add(mem, value) \
+  ({ __typeof (*mem) __result;                                               \
+     __typeof (value) __addval = (value);                                    \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK_PREFIX "xaddb %b0, %1"                         \
+                        : "=r" (__result), "=m" (*mem)                       \
+                        : "0" (__addval), "m" (*mem));                       \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK_PREFIX "xaddw %w0, %1"                         \
+                        : "=r" (__result), "=m" (*mem)                       \
+                        : "0" (__addval), "m" (*mem));                       \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK_PREFIX "xaddl %0, %1"                          \
+                        : "=r" (__result), "=m" (*mem)                       \
+                        : "0" (__addval), "m" (*mem));                       \
+     else                                                                    \
+       {                                                                     \
+        __typeof (mem) __memp = (mem);                                       \
+        __typeof (*mem) __tmpval;                                            \
+        __result = *__memp;                                                  \
+        do                                                                   \
+          __tmpval = __result;                                               \
+        while ((__result = __arch_compare_and_exchange_val_64_acq            \
+                (__memp, __result + __addval, __result)) == __tmpval);       \
+       }                                                                     \
+     __result; })
+
+
+#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); \
+             }                                                               \
+           })
+
+
+#define atomic_add_negative(mem, value) \
+  ({ unsigned char __result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK_PREFIX "addb %b2, %0; sets %1"                 \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "iq" (value), "m" (*mem));                         \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK_PREFIX "addw %w2, %0; sets %1"                 \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "m" (*mem));                         \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK_PREFIX "addl %2, %0; sets %1"                  \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "m" (*mem));                         \
+     else                                                                    \
+       abort ();                                                             \
+     __result; })
+
+
+#define atomic_add_zero(mem, value) \
+  ({ unsigned char __result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK_PREFIX "addb %b2, %0; setz %1"                 \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "m" (*mem));                         \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK_PREFIX "addw %w2, %0; setz %1"                 \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "m" (*mem));                         \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK_PREFIX "addl %2, %0; setz %1"                  \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "m" (*mem));                         \
+     else                                                                    \
+       abort ();                                                             \
+     __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 atomic_increment_and_test(mem) \
+  ({ unsigned char __result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK_PREFIX "incb %0; sete %b1"                     \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "m" (*mem));                                       \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK_PREFIX "incw %0; sete %w1"                     \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "m" (*mem));                                       \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK_PREFIX "incl %0; sete %1"                              \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "m" (*mem));                                       \
+     else                                                                    \
+       abort ();                                                             \
+     __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 atomic_decrement_and_test(mem) \
+  ({ unsigned char __result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK_PREFIX "decb %b0; sete %1"                     \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "m" (*mem));                                       \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK_PREFIX "decw %w0; sete %1"                     \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "m" (*mem));                                       \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK_PREFIX "decl %0; sete %1"                              \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "m" (*mem));                                       \
+     else                                                                    \
+       abort ();                                                             \
+     __result; })
+
+
+#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 ();                                                       \
+           })
+
+
+#define atomic_bit_test_set(mem, bit) \
+  ({ unsigned char __result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK_PREFIX "btsb %3, %1; setc %0"                  \
+                        : "=q" (__result), "=m" (*mem)                       \
+                        : "m" (*mem), "ir" (bit));                           \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK_PREFIX "btsw %3, %1; setc %0"                  \
+                        : "=q" (__result), "=m" (*mem)                       \
+                        : "m" (*mem), "ir" (bit));                           \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK_PREFIX "btsl %3, %1; setc %0"                  \
+                        : "=q" (__result), "=m" (*mem)                       \
+                        : "m" (*mem), "ir" (bit));                           \
+     else                                                                    \
+       abort ();                                                             \
+     __result; })
+
+
+#define atomic_delay() asm ("rep; nop")
diff --git a/libc/sysdeps/linux/mips/bits/atomic.h b/libc/sysdeps/linux/mips/bits/atomic.h
new file mode 100644 (file)
index 0000000..167d9a5
--- /dev/null
@@ -0,0 +1,303 @@
+/* Low-level functions for atomic operations. Mips version.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C 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.
+
+   The GNU C 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 the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _MIPS_BITS_ATOMIC_H
+#define _MIPS_BITS_ATOMIC_H 1
+
+#include <inttypes.h>
+#include <sgidefs.h>
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+#if _MIPS_SIM == _ABIO32
+#define MIPS_PUSH_MIPS2 ".set  mips2\n\t"
+#else
+#define MIPS_PUSH_MIPS2
+#endif
+
+/* See the comments in <sys/asm.h> about the use of the sync instruction.  */
+#ifndef MIPS_SYNC
+# define MIPS_SYNC     sync
+#endif
+
+#define MIPS_SYNC_STR_2(X) #X
+#define MIPS_SYNC_STR_1(X) MIPS_SYNC_STR_2(X)
+#define MIPS_SYNC_STR MIPS_SYNC_STR_1(MIPS_SYNC)
+
+/* Compare and exchange.  For all of the "xxx" routines, we expect a
+   "__prev" and a "__cmp" variable to be provided by the enclosing scope,
+   in which values are returned.  */
+
+#define __arch_compare_and_exchange_xxx_8_int(mem, newval, oldval, rel, acq) \
+  (abort (), __prev = __cmp = 0)
+
+#define __arch_compare_and_exchange_xxx_16_int(mem, newval, oldval, rel, acq) \
+  (abort (), __prev = __cmp = 0)
+
+#define __arch_compare_and_exchange_xxx_32_int(mem, newval, oldval, rel, acq) \
+     __asm__ __volatile__ (                                                  \
+     ".set     push\n\t"                                                     \
+     MIPS_PUSH_MIPS2                                                         \
+     rel       "\n"                                                          \
+     "1:\t"                                                                  \
+     "ll       %0,%4\n\t"                                                    \
+     "move     %1,$0\n\t"                                                    \
+     "bne      %0,%2,2f\n\t"                                                 \
+     "move     %1,%3\n\t"                                                    \
+     "sc       %1,%4\n\t"                                                    \
+     "beqz     %1,1b\n"                                                      \
+     acq       "\n\t"                                                        \
+     ".set     pop\n"                                                        \
+     "2:\n\t"                                                                \
+             : "=&r" (__prev), "=&r" (__cmp)                                 \
+             : "r" (oldval), "r" (newval), "m" (*mem)                        \
+             : "memory")
+
+#if _MIPS_SIM == _ABIO32
+/* We can't do an atomic 64-bit operation in O32.  */
+#define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \
+  (abort (), __prev = __cmp = 0)
+#else
+#define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \
+     __asm__ __volatile__ ("\n"                                                      \
+     ".set     push\n\t"                                                     \
+     MIPS_PUSH_MIPS2                                                         \
+     rel       "\n"                                                          \
+     "1:\t"                                                                  \
+     "lld      %0,%4\n\t"                                                    \
+     "move     %1,$0\n\t"                                                    \
+     "bne      %0,%2,2f\n\t"                                                 \
+     "move     %1,%3\n\t"                                                    \
+     "scd      %1,%4\n\t"                                                    \
+     "beqz     %1,1b\n"                                                      \
+     acq       "\n\t"                                                        \
+     ".set     pop\n"                                                        \
+     "2:\n\t"                                                                \
+             : "=&r" (__prev), "=&r" (__cmp)                                 \
+             : "r" (oldval), "r" (newval), "m" (*mem)                        \
+             : "memory")
+#endif
+
+/* For all "bool" routines, we return FALSE if exchange succesful.  */
+
+#define __arch_compare_and_exchange_bool_8_int(mem, new, old, rel, acq)        \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq);     \
+   !__cmp; })
+
+#define __arch_compare_and_exchange_bool_16_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq);    \
+   !__cmp; })
+
+#define __arch_compare_and_exchange_bool_32_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq);    \
+   !__cmp; })
+
+#define __arch_compare_and_exchange_bool_64_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq);    \
+   !__cmp; })
+
+/* For all "val" routines, return the old value whether exchange
+   successful or not.  */
+
+#define __arch_compare_and_exchange_val_8_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq);     \
+   (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_16_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq);    \
+   (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_32_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq);    \
+   (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_64_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq);    \
+   (typeof (*mem))__prev; })
+
+/* Compare and exchange with "acquire" semantics, ie barrier after.  */
+
+#define atomic_compare_and_exchange_bool_acq(mem, new, old)    \
+  __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
+                       mem, new, old, "", MIPS_SYNC_STR)
+
+#define atomic_compare_and_exchange_val_acq(mem, new, old)     \
+  __atomic_val_bysize (__arch_compare_and_exchange_val, int,   \
+                      mem, new, old, "", MIPS_SYNC_STR)
+
+/* Compare and exchange with "release" semantics, ie barrier before.  */
+
+#define atomic_compare_and_exchange_bool_rel(mem, new, old)    \
+  __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
+                       mem, new, old, MIPS_SYNC_STR, "")
+
+#define atomic_compare_and_exchange_val_rel(mem, new, old)     \
+  __atomic_val_bysize (__arch_compare_and_exchange_val, int,   \
+                      mem, new, old, MIPS_SYNC_STR, "")
+
+
+
+/* Atomic exchange (without compare).  */
+
+#define __arch_exchange_xxx_8_int(mem, newval, rel, acq) \
+  (abort (), 0)
+
+#define __arch_exchange_xxx_16_int(mem, newval, rel, acq) \
+  (abort (), 0)
+
+#define __arch_exchange_xxx_32_int(mem, newval, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                          \
+     __asm__ __volatile__ ("\n"                                                      \
+     ".set     push\n\t"                                                     \
+     MIPS_PUSH_MIPS2                                                         \
+     rel       "\n"                                                          \
+     "1:\t"                                                                  \
+     "ll       %0,%3\n\t"                                                    \
+     "move     %1,%2\n\t"                                                    \
+     "sc       %1,%3\n\t"                                                    \
+     "beqz     %1,1b\n"                                                      \
+     acq       "\n\t"                                                        \
+     ".set     pop\n"                                                        \
+     "2:\n\t"                                                                \
+             : "=&r" (__prev), "=&r" (__cmp)                                 \
+             : "r" (newval), "m" (*mem)                                      \
+             : "memory");                                                    \
+  __prev; })
+
+#if _MIPS_SIM == _ABIO32
+/* We can't do an atomic 64-bit operation in O32.  */
+#define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \
+  (abort (), 0)
+#else
+#define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                          \
+     __asm__ __volatile__ ("\n"                                                      \
+     ".set     push\n\t"                                                     \
+     MIPS_PUSH_MIPS2                                                         \
+     rel       "\n"                                                          \
+     "1:\n"                                                                  \
+     "lld      %0,%3\n\t"                                                    \
+     "move     %1,%2\n\t"                                                    \
+     "scd      %1,%3\n\t"                                                    \
+     "beqz     %1,1b\n"                                                      \
+     acq       "\n\t"                                                        \
+     ".set     pop\n"                                                        \
+     "2:\n\t"                                                                \
+             : "=&r" (__prev), "=&r" (__cmp)                                 \
+             : "r" (newval), "m" (*mem)                                      \
+             : "memory");                                                    \
+  __prev; })
+#endif
+
+#define atomic_exchange_acq(mem, value) \
+  __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, "", MIPS_SYNC_STR)
+
+#define atomic_exchange_rel(mem, value) \
+  __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, MIPS_SYNC_STR, "")
+
+
+/* Atomically add value and return the previous (unincremented) value.  */
+
+#define __arch_exchange_and_add_8_int(mem, newval, rel, acq) \
+  (abort (), (typeof(*mem)) 0)
+
+#define __arch_exchange_and_add_16_int(mem, newval, rel, acq) \
+  (abort (), (typeof(*mem)) 0)
+
+#define __arch_exchange_and_add_32_int(mem, value, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                          \
+     __asm__ __volatile__ ("\n"                                                      \
+     ".set     push\n\t"                                                     \
+     MIPS_PUSH_MIPS2                                                         \
+     rel       "\n"                                                          \
+     "1:\t"                                                                  \
+     "ll       %0,%3\n\t"                                                    \
+     "addu     %1,%0,%2\n\t"                                                 \
+     "sc       %1,%3\n\t"                                                    \
+     "beqz     %1,1b\n"                                                      \
+     acq       "\n\t"                                                        \
+     ".set     pop\n"                                                        \
+     "2:\n\t"                                                                \
+             : "=&r" (__prev), "=&r" (__cmp)                                 \
+             : "r" (value), "m" (*mem)                                       \
+             : "memory");                                                    \
+  __prev; })
+
+#if _MIPS_SIM == _ABIO32
+/* We can't do an atomic 64-bit operation in O32.  */
+#define __arch_exchange_and_add_64_int(mem, value, rel, acq) \
+  (abort (), (typeof(*mem)) 0)
+#else
+#define __arch_exchange_and_add_64_int(mem, value, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                          \
+     __asm__ __volatile__ (                                                  \
+     ".set     push\n\t"                                                     \
+     MIPS_PUSH_MIPS2                                                         \
+     rel       "\n"                                                          \
+     "1:\t"                                                                  \
+     "lld      %0,%3\n\t"                                                    \
+     "daddu    %1,%0,%2\n\t"                                                 \
+     "scd      %1,%3\n\t"                                                    \
+     "beqz     %1,1b\n"                                                      \
+     acq       "\n\t"                                                        \
+     ".set     pop\n"                                                        \
+     "2:\n\t"                                                                \
+             : "=&r" (__prev), "=&r" (__cmp)                                 \
+             : "r" (value), "m" (*mem)                                       \
+             : "memory");                                                    \
+  __prev; })
+#endif
+
+/* ??? Barrier semantics for atomic_exchange_and_add appear to be 
+   undefined.  Use full barrier for now, as that's safe.  */
+#define atomic_exchange_and_add(mem, value) \
+  __atomic_val_bysize (__arch_exchange_and_add, int, mem, value,             \
+                      MIPS_SYNC_STR, MIPS_SYNC_STR)
+
+/* TODO: More atomic operations could be implemented efficiently; only the
+   basic requirements are done.  */
+
+#define atomic_full_barrier() \
+  __asm__ __volatile__ (".set push\n\t"                                              \
+                       MIPS_PUSH_MIPS2                                       \
+                       MIPS_SYNC_STR "\n\t"                                  \
+                       ".set pop" : : : "memory")
+
+#endif /* bits/atomic.h */
diff --git a/libc/sysdeps/linux/sh/bits/atomic.h b/libc/sysdeps/linux/sh/bits/atomic.h
new file mode 100644 (file)
index 0000000..a0e5918
--- /dev/null
@@ -0,0 +1,419 @@
+/* Atomic operations used inside libc.  Linux/SH version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C 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.
+
+   The GNU C 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 the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdint.h>
+
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int16_t atomic16_t;
+typedef uint16_t uatomic16_t;
+typedef int_fast16_t atomic_fast16_t;
+typedef uint_fast16_t uatomic_fast16_t;
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+/* SH kernel has implemented a gUSA ("g" User Space Atomicity) support
+   for the user space atomicity. The atomicity macros use this scheme.
+
+  Reference:
+    Niibe Yutaka, "gUSA: Simple and Efficient User Space Atomicity
+    Emulation with Little Kernel Modification", Linux Conference 2002,
+    Japan. http://lc.linux.or.jp/lc2002/papers/niibe0919h.pdf (in
+    Japanese).
+
+    B.N. Bershad, D. Redell, and J. Ellis, "Fast Mutual Exclusion for
+    Uniprocessors",  Proceedings of the Fifth Architectural Support for
+    Programming Languages and Operating Systems (ASPLOS), pp. 223-233,
+    October 1992. http://www.cs.washington.edu/homes/bershad/Papers/Rcs.ps
+
+  SuperH ABI:
+      r15:    -(size of atomic instruction sequence) < 0
+      r0:     end point
+      r1:     saved stack pointer
+*/
+
+#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \
+  ({ __typeof (*(mem)) __result; \
+     __asm __volatile ("\
+       .align 2\n\
+       mova 1f,r0\n\
+       nop\n\
+       mov r15,r1\n\
+       mov #-8,r15\n\
+     0: mov.b @%1,%0\n\
+       cmp/eq %0,%3\n\
+       bf 1f\n\
+       mov.b %2,@%1\n\
+     1: mov r1,r15"\
+       : "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \
+       : "r0", "r1", "t", "memory"); \
+     __result; })
+
+#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \
+  ({ __typeof (*(mem)) __result; \
+     __asm __volatile ("\
+       .align 2\n\
+       mova 1f,r0\n\
+       nop\n\
+       mov r15,r1\n\
+       mov #-8,r15\n\
+     0: mov.w @%1,%0\n\
+       cmp/eq %0,%3\n\
+       bf 1f\n\
+       mov.w %2,@%1\n\
+     1: mov r1,r15"\
+       : "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \
+       : "r0", "r1", "t", "memory"); \
+     __result; })
+
+#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
+  ({ __typeof (*(mem)) __result; \
+     __asm __volatile ("\
+       .align 2\n\
+       mova 1f,r0\n\
+       nop\n\
+       mov r15,r1\n\
+       mov #-8,r15\n\
+     0: mov.l @%1,%0\n\
+       cmp/eq %0,%3\n\
+       bf 1f\n\
+       mov.l %2,@%1\n\
+     1: mov r1,r15"\
+       : "=&r" (__result) : "r" (mem), "r" (newval), "r" (oldval) \
+       : "r0", "r1", "t", "memory"); \
+     __result; })
+
+/* 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
+   such an operation.  So don't define any code for now.  */
+
+# define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
+  (abort (), (__typeof (*mem)) 0)
+
+#define atomic_exchange_and_add(mem, value) \
+  ({ __typeof (*(mem)) __result, __tmp, __value = (value); \
+     if (sizeof (*(mem)) == 1) \
+       __asm __volatile ("\
+         .align 2\n\
+         mova 1f,r0\n\
+         mov r15,r1\n\
+         mov #-6,r15\n\
+       0: mov.b @%2,%0\n\
+         add %0,%1\n\
+         mov.b %1,@%2\n\
+       1: mov r1,r15"\
+       : "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+       : "r0", "r1", "memory"); \
+     else if (sizeof (*(mem)) == 2) \
+       __asm __volatile ("\
+         .align 2\n\
+         mova 1f,r0\n\
+         mov r15,r1\n\
+         mov #-6,r15\n\
+       0: mov.w @%2,%0\n\
+         add %0,%1\n\
+         mov.w %1,@%2\n\
+       1: mov r1,r15"\
+       : "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+       : "r0", "r1", "memory"); \
+     else if (sizeof (*(mem)) == 4) \
+       __asm __volatile ("\
+         .align 2\n\
+         mova 1f,r0\n\
+         mov r15,r1\n\
+         mov #-6,r15\n\
+       0: mov.l @%2,%0\n\
+         add %0,%1\n\
+         mov.l %1,@%2\n\
+       1: mov r1,r15"\
+       : "=&r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+       : "r0", "r1", "memory"); \
+     else \
+       { \
+        __typeof (mem) memp = (mem); \
+        do \
+          __result = *memp; \
+        while (__arch_compare_and_exchange_val_64_acq \
+                (memp, __result + __value, __result) == __result); \
+        (void) __value; \
+       } \
+     __result; })
+
+#define atomic_add(mem, value) \
+  (void) ({ __typeof (*(mem)) __tmp, __value = (value); \
+           if (sizeof (*(mem)) == 1) \
+             __asm __volatile ("\
+               .align 2\n\
+               mova 1f,r0\n\
+               mov r15,r1\n\
+               mov #-6,r15\n\
+            0: mov.b @%1,r2\n\
+               add r2,%0\n\
+               mov.b %0,@%1\n\
+            1: mov r1,r15"\
+               : "=&r" (__tmp) : "r" (mem), "0" (__value) \
+               : "r0", "r1", "r2", "memory"); \
+           else if (sizeof (*(mem)) == 2) \
+             __asm __volatile ("\
+               .align 2\n\
+               mova 1f,r0\n\
+               mov r15,r1\n\
+               mov #-6,r15\n\
+            0: mov.w @%1,r2\n\
+               add r2,%0\n\
+               mov.w %0,@%1\n\
+            1: mov r1,r15"\
+               : "=&r" (__tmp) : "r" (mem), "0" (__value) \
+               : "r0", "r1", "r2", "memory"); \
+           else if (sizeof (*(mem)) == 4) \
+             __asm __volatile ("\
+               .align 2\n\
+               mova 1f,r0\n\
+               mov r15,r1\n\
+               mov #-6,r15\n\
+            0: mov.l @%1,r2\n\
+               add r2,%0\n\
+               mov.l %0,@%1\n\
+            1: mov r1,r15"\
+               : "=&r" (__tmp) : "r" (mem), "0" (__value) \
+               : "r0", "r1", "r2", "memory"); \
+           else \
+             { \
+               __typeof (*(mem)) oldval; \
+               __typeof (mem) memp = (mem); \
+               do \
+                 oldval = *memp; \
+               while (__arch_compare_and_exchange_val_64_acq \
+                       (memp, oldval + __value, oldval) == oldval); \
+               (void) __value; \
+             } \
+           })
+
+#define atomic_add_negative(mem, value) \
+  ({ unsigned char __result; \
+     __typeof (*(mem)) __tmp, __value = (value); \
+     if (sizeof (*(mem)) == 1) \
+       __asm __volatile ("\
+         .align 2\n\
+         mova 1f,r0\n\
+         mov r15,r1\n\
+         mov #-6,r15\n\
+       0: mov.b @%2,r2\n\
+         add r2,%1\n\
+         mov.b %1,@%2\n\
+       1: mov r1,r15\n\
+         shal %1\n\
+         movt %0"\
+       : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+       : "r0", "r1", "r2", "t", "memory"); \
+     else if (sizeof (*(mem)) == 2) \
+       __asm __volatile ("\
+         .align 2\n\
+         mova 1f,r0\n\
+         mov r15,r1\n\
+         mov #-6,r15\n\
+       0: mov.w @%2,r2\n\
+         add r2,%1\n\
+         mov.w %1,@%2\n\
+       1: mov r1,r15\n\
+         shal %1\n\
+         movt %0"\
+       : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+       : "r0", "r1", "r2", "t", "memory"); \
+     else if (sizeof (*(mem)) == 4) \
+       __asm __volatile ("\
+         .align 2\n\
+         mova 1f,r0\n\
+         mov r15,r1\n\
+         mov #-6,r15\n\
+       0: mov.l @%2,r2\n\
+         add r2,%1\n\
+         mov.l %1,@%2\n\
+       1: mov r1,r15\n\
+         shal %1\n\
+         movt %0"\
+       : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+       : "r0", "r1", "r2", "t", "memory"); \
+     else \
+       abort (); \
+     __result; })
+
+#define atomic_add_zero(mem, value) \
+  ({ unsigned char __result; \
+     __typeof (*(mem)) __tmp, __value = (value); \
+     if (sizeof (*(mem)) == 1) \
+       __asm __volatile ("\
+         .align 2\n\
+         mova 1f,r0\n\
+         mov r15,r1\n\
+         mov #-6,r15\n\
+       0: mov.b @%2,r2\n\
+         add r2,%1\n\
+         mov.b %1,@%2\n\
+       1: mov r1,r15\n\
+         tst %1,%1\n\
+         movt %0"\
+       : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+       : "r0", "r1", "r2", "t", "memory"); \
+     else if (sizeof (*(mem)) == 2) \
+       __asm __volatile ("\
+         .align 2\n\
+         mova 1f,r0\n\
+         mov r15,r1\n\
+         mov #-6,r15\n\
+       0: mov.w @%2,r2\n\
+         add r2,%1\n\
+         mov.w %1,@%2\n\
+       1: mov r1,r15\n\
+         tst %1,%1\n\
+         movt %0"\
+       : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+       : "r0", "r1", "r2", "t", "memory"); \
+     else if (sizeof (*(mem)) == 4) \
+       __asm __volatile ("\
+         .align 2\n\
+         mova 1f,r0\n\
+         mov r15,r1\n\
+         mov #-6,r15\n\
+       0: mov.l @%2,r2\n\
+         add r2,%1\n\
+         mov.l %1,@%2\n\
+       1: mov r1,r15\n\
+         tst %1,%1\n\
+         movt %0"\
+       : "=r" (__result), "=&r" (__tmp) : "r" (mem), "1" (__value) \
+       : "r0", "r1", "r2", "t", "memory"); \
+     else \
+       abort (); \
+     __result; })
+
+#define atomic_increment_and_test(mem) atomic_add_zero((mem), 1)
+#define atomic_decrement_and_test(mem) atomic_add_zero((mem), -1)
+
+#define atomic_bit_set(mem, bit) \
+  (void) ({ unsigned int __mask = 1 << (bit); \
+           if (sizeof (*(mem)) == 1) \
+             __asm __volatile ("\
+               .align 2\n\
+               mova 1f,r0\n\
+               mov r15,r1\n\
+               mov #-6,r15\n\
+            0: mov.b @%0,r2\n\
+               or %1,r2\n\
+               mov.b r2,@%0\n\
+            1: mov r1,r15"\
+               : : "r" (mem), "r" (__mask) \
+               : "r0", "r1", "r2", "memory"); \
+           else if (sizeof (*(mem)) == 2) \
+             __asm __volatile ("\
+               .align 2\n\
+               mova 1f,r0\n\
+               mov r15,r1\n\
+               mov #-6,r15\n\
+            0: mov.w @%0,r2\n\
+               or %1,r2\n\
+               mov.w r2,@%0\n\
+            1: mov r1,r15"\
+               : : "r" (mem), "r" (__mask) \
+               : "r0", "r1", "r2", "memory"); \
+           else if (sizeof (*(mem)) == 4) \
+             __asm __volatile ("\
+               .align 2\n\
+               mova 1f,r0\n\
+               mov r15,r1\n\
+               mov #-6,r15\n\
+            0: mov.l @%0,r2\n\
+               or %1,r2\n\
+               mov.l r2,@%0\n\
+            1: mov r1,r15"\
+               : : "r" (mem), "r" (__mask) \
+               : "r0", "r1", "r2", "memory"); \
+           else \
+             abort (); \
+           })
+
+#define atomic_bit_test_set(mem, bit) \
+  ({ unsigned int __mask = 1 << (bit); \
+     unsigned int __result = __mask; \
+     if (sizeof (*(mem)) == 1) \
+       __asm __volatile ("\
+         .align 2\n\
+         mova 1f,r0\n\
+         nop\n\
+         mov r15,r1\n\
+         mov #-8,r15\n\
+       0: mov.b @%2,r2\n\
+         or r2,%1\n\
+         and r2,%0\n\
+         mov.b %1,@%2\n\
+       1: mov r1,r15"\
+       : "=&r" (__result), "=&r" (__mask) \
+       : "r" (mem), "0" (__result), "1" (__mask) \
+       : "r0", "r1", "r2", "memory"); \
+     else if (sizeof (*(mem)) == 2) \
+       __asm __volatile ("\
+         .align 2\n\
+         mova 1f,r0\n\
+         nop\n\
+         mov r15,r1\n\
+         mov #-8,r15\n\
+       0: mov.w @%2,r2\n\
+         or r2,%1\n\
+         and r2,%0\n\
+         mov.w %1,@%2\n\
+       1: mov r1,r15"\
+       : "=&r" (__result), "=&r" (__mask) \
+       : "r" (mem), "0" (__result), "1" (__mask) \
+       : "r0", "r1", "r2", "memory"); \
+     else if (sizeof (*(mem)) == 4) \
+       __asm __volatile ("\
+         .align 2\n\
+         mova 1f,r0\n\
+         nop\n\
+         mov r15,r1\n\
+         mov #-8,r15\n\
+       0: mov.l @%2,r2\n\
+         or r2,%1\n\
+         and r2,%0\n\
+         mov.l %1,@%2\n\
+       1: mov r1,r15"\
+       : "=&r" (__result), "=&r" (__mask) \
+       : "r" (mem), "0" (__result), "1" (__mask) \
+       : "r0", "r1", "r2", "memory"); \
+     else \
+       abort (); \
+     __result; })
diff --git a/libc/sysdeps/linux/x86_64/bits/atomic.h b/libc/sysdeps/linux/x86_64/bits/atomic.h
new file mode 100644 (file)
index 0000000..133a68d
--- /dev/null
@@ -0,0 +1,324 @@
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C 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.
+
+   The GNU C 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 the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdint.h>
+
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int16_t atomic16_t;
+typedef uint16_t uatomic16_t;
+typedef int_fast16_t atomic_fast16_t;
+typedef uint_fast16_t uatomic_fast16_t;
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+
+#ifndef LOCK_PREFIX
+# ifdef UP
+#  define LOCK_PREFIX  /* nothing */
+# else
+#  define LOCK_PREFIX "lock;"
+# endif
+#endif
+
+
+#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \
+  ({ __typeof (*mem) ret;                                                    \
+     __asm __volatile (LOCK_PREFIX "cmpxchgb %b2, %1"                        \
+                      : "=a" (ret), "=m" (*mem)                              \
+                      : "q" (newval), "m" (*mem), "0" (oldval));             \
+     ret; })
+
+#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \
+  ({ __typeof (*mem) ret;                                                    \
+     __asm __volatile (LOCK_PREFIX "cmpxchgw %w2, %1"                        \
+                      : "=a" (ret), "=m" (*mem)                              \
+                      : "r" (newval), "m" (*mem), "0" (oldval));             \
+     ret; })
+
+#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
+  ({ __typeof (*mem) ret;                                                    \
+     __asm __volatile (LOCK_PREFIX "cmpxchgl %2, %1"                         \
+                      : "=a" (ret), "=m" (*mem)                              \
+                      : "r" (newval), "m" (*mem), "0" (oldval));             \
+     ret; })
+
+#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
+  ({ __typeof (*mem) ret;                                                    \
+     __asm __volatile (LOCK_PREFIX "cmpxchgq %q2, %1"                        \
+                      : "=a" (ret), "=m" (*mem)                              \
+                      : "r" ((long) (newval)), "m" (*mem),                   \
+                        "0" ((long) (oldval)));                              \
+     ret; })
+
+
+/* Note that we need no lock prefix.  */
+#define atomic_exchange_acq(mem, newvalue) \
+  ({ __typeof (*mem) result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile ("xchgb %b0, %1"                                     \
+                        : "=r" (result), "=m" (*mem)                         \
+                        : "0" (newvalue), "m" (*mem));                       \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile ("xchgw %w0, %1"                                     \
+                        : "=r" (result), "=m" (*mem)                         \
+                        : "0" (newvalue), "m" (*mem));                       \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile ("xchgl %0, %1"                                              \
+                        : "=r" (result), "=m" (*mem)                         \
+                        : "0" (newvalue), "m" (*mem));                       \
+     else                                                                    \
+       __asm __volatile ("xchgq %q0, %1"                                     \
+                        : "=r" (result), "=m" (*mem)                         \
+                        : "0" ((long) (newvalue)), "m" (*mem));              \
+     result; })
+
+
+#define atomic_exchange_and_add(mem, value) \
+  ({ __typeof (*mem) result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK_PREFIX "xaddb %b0, %1"                         \
+                        : "=r" (result), "=m" (*mem)                         \
+                        : "0" (value), "m" (*mem));                          \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK_PREFIX "xaddw %w0, %1"                         \
+                        : "=r" (result), "=m" (*mem)                         \
+                        : "0" (value), "m" (*mem));                          \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK_PREFIX "xaddl %0, %1"                          \
+                        : "=r" (result), "=m" (*mem)                         \
+                        : "0" (value), "m" (*mem));                          \
+     else                                                                    \
+       __asm __volatile (LOCK_PREFIX "xaddq %q0, %1"                         \
+                        : "=r" (result), "=m" (*mem)                         \
+                        : "0" ((long) (value)), "m" (*mem));                 \
+     result; })
+
+
+#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                                                              \
+             __asm __volatile (LOCK_PREFIX "addq %q1, %0"                    \
+                               : "=m" (*mem)                                 \
+                               : "ir" ((long) (value)), "m" (*mem));         \
+           })
+
+
+#define atomic_add_negative(mem, value) \
+  ({ unsigned char __result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK_PREFIX "addb %b2, %0; sets %1"                 \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "m" (*mem));                         \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK_PREFIX "addw %w2, %0; sets %1"                 \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "m" (*mem));                         \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK_PREFIX "addl %2, %0; sets %1"                  \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "m" (*mem));                         \
+     else                                                                    \
+       __asm __volatile (LOCK_PREFIX "addq %q2, %0; sets %1"                 \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" ((long) (value)), "m" (*mem));                \
+     __result; })
+
+
+#define atomic_add_zero(mem, value) \
+  ({ unsigned char __result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK_PREFIX "addb %b2, %0; setz %1"                 \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "m" (*mem));                         \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK_PREFIX "addw %w2, %0; setz %1"                 \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "m" (*mem));                         \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK_PREFIX "addl %2, %0; setz %1"                  \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" (value), "m" (*mem));                         \
+     else                                                                    \
+       __asm __volatile (LOCK_PREFIX "addq %q2, %0; setz %1"                 \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "ir" ((long) (value)), "m" (*mem));                \
+     __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                                                              \
+             __asm __volatile (LOCK_PREFIX "incq %q0"                        \
+                               : "=m" (*mem)                                 \
+                               : "m" (*mem));                                \
+           })
+
+
+#define atomic_increment_and_test(mem) \
+  ({ unsigned char __result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK_PREFIX "incb %b0; sete %1"                     \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "m" (*mem));                                       \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK_PREFIX "incw %w0; sete %1"                     \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "m" (*mem));                                       \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK_PREFIX "incl %0; sete %1"                              \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "m" (*mem));                                       \
+     else                                                                    \
+       __asm __volatile (LOCK_PREFIX "incq %q0; sete %1"                     \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "m" (*mem));                                       \
+     __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                                                              \
+             __asm __volatile (LOCK_PREFIX "decq %q0"                        \
+                               : "=m" (*mem)                                 \
+                               : "m" (*mem));                                \
+           })
+
+
+#define atomic_decrement_and_test(mem) \
+  ({ unsigned char __result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK_PREFIX "decb %b0; sete %1"                     \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "m" (*mem));                                       \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK_PREFIX "decw %w0; sete %1"                     \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "m" (*mem));                                       \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK_PREFIX "decl %0; sete %1"                              \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "m" (*mem));                                       \
+     else                                                                    \
+       __asm __volatile (LOCK_PREFIX "decq %q0; sete %1"                     \
+                        : "=m" (*mem), "=qm" (__result)                      \
+                        : "m" (*mem));                                       \
+     __result; })
+
+
+#define atomic_bit_set(mem, bit) \
+  (void) ({ if (sizeof (*mem) == 1)                                          \
+             __asm __volatile (LOCK_PREFIX "orb %b2, %0"                     \
+                               : "=m" (*mem)                                 \
+                               : "m" (*mem), "ir" (1L << (bit)));            \
+           else if (sizeof (*mem) == 2)                                      \
+             __asm __volatile (LOCK_PREFIX "orw %w2, %0"                     \
+                               : "=m" (*mem)                                 \
+                               : "m" (*mem), "ir" (1L << (bit)));            \
+           else if (sizeof (*mem) == 4)                                      \
+             __asm __volatile (LOCK_PREFIX "orl %2, %0"                      \
+                               : "=m" (*mem)                                 \
+                               : "m" (*mem), "ir" (1L << (bit)));            \
+           else if (__builtin_constant_p (bit) && (bit) < 32)                \
+             __asm __volatile (LOCK_PREFIX "orq %2, %0"                      \
+                               : "=m" (*mem)                                 \
+                               : "m" (*mem), "i" (1L << (bit)));             \
+           else                                                              \
+             __asm __volatile (LOCK_PREFIX "orq %q2, %0"                     \
+                               : "=m" (*mem)                                 \
+                               : "m" (*mem), "r" (1UL << (bit)));            \
+           })
+
+
+#define atomic_bit_test_set(mem, bit) \
+  ({ unsigned char __result;                                                 \
+     if (sizeof (*mem) == 1)                                                 \
+       __asm __volatile (LOCK_PREFIX "btsb %3, %1; setc %0"                  \
+                        : "=q" (__result), "=m" (*mem)                       \
+                        : "m" (*mem), "ir" (bit));                           \
+     else if (sizeof (*mem) == 2)                                            \
+       __asm __volatile (LOCK_PREFIX "btsw %3, %1; setc %0"                  \
+                        : "=q" (__result), "=m" (*mem)                       \
+                        : "m" (*mem), "ir" (bit));                           \
+     else if (sizeof (*mem) == 4)                                            \
+       __asm __volatile (LOCK_PREFIX "btsl %3, %1; setc %0"                  \
+                        : "=q" (__result), "=m" (*mem)                       \
+                        : "m" (*mem), "ir" (bit));                           \
+     else                                                                    \
+       __asm __volatile (LOCK_PREFIX "btsq %3, %1; setc %0"                  \
+                        : "=q" (__result), "=m" (*mem)                       \
+                        : "m" (*mem), "ir" (bit));                           \
+     __result; })
+
+
+#define atomic_delay() asm ("rep; nop")