Back to index

glibc  2.9
atomic.h
Go to the documentation of this file.
00001 /* Low-level functions for atomic operations. Mips version.
00002    Copyright (C) 2005 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #ifndef _MIPS_BITS_ATOMIC_H
00021 #define _MIPS_BITS_ATOMIC_H 1
00022 
00023 #include <inttypes.h>
00024 #include <sgidefs.h>
00025 
00026 typedef int32_t atomic32_t;
00027 typedef uint32_t uatomic32_t;
00028 typedef int_fast32_t atomic_fast32_t;
00029 typedef uint_fast32_t uatomic_fast32_t;
00030 
00031 typedef int64_t atomic64_t;
00032 typedef uint64_t uatomic64_t;
00033 typedef int_fast64_t atomic_fast64_t;
00034 typedef uint_fast64_t uatomic_fast64_t;
00035 
00036 typedef intptr_t atomicptr_t;
00037 typedef uintptr_t uatomicptr_t;
00038 typedef intmax_t atomic_max_t;
00039 typedef uintmax_t uatomic_max_t;
00040 
00041 #if _MIPS_SIM == _ABIO32
00042 #define MIPS_PUSH_MIPS2 ".set      mips2\n\t"
00043 #else
00044 #define MIPS_PUSH_MIPS2
00045 #endif
00046 
00047 /* See the comments in <sys/asm.h> about the use of the sync instruction.  */
00048 #ifndef MIPS_SYNC
00049 # define MIPS_SYNC   sync
00050 #endif
00051 
00052 #define MIPS_SYNC_STR_2(X) #X
00053 #define MIPS_SYNC_STR_1(X) MIPS_SYNC_STR_2(X)
00054 #define MIPS_SYNC_STR MIPS_SYNC_STR_1(MIPS_SYNC)
00055 
00056 /* Compare and exchange.  For all of the "xxx" routines, we expect a
00057    "__prev" and a "__cmp" variable to be provided by the enclosing scope,
00058    in which values are returned.  */
00059 
00060 #define __arch_compare_and_exchange_xxx_8_int(mem, newval, oldval, rel, acq) \
00061   (abort (), __prev = __cmp = 0)
00062 
00063 #define __arch_compare_and_exchange_xxx_16_int(mem, newval, oldval, rel, acq) \
00064   (abort (), __prev = __cmp = 0)
00065 
00066 #define __arch_compare_and_exchange_xxx_32_int(mem, newval, oldval, rel, acq) \
00067      __asm__ __volatile__ (                                          \
00068      ".set    push\n\t"                                              \
00069      MIPS_PUSH_MIPS2                                                 \
00070      rel      "\n"                                                   \
00071      "1:\t"                                                          \
00072      "ll      %0,%4\n\t"                                             \
00073      "move    %1,$0\n\t"                                             \
00074      "bne     %0,%2,2f\n\t"                                          \
00075      "move    %1,%3\n\t"                                             \
00076      "sc      %1,%4\n\t"                                             \
00077      "beqz    %1,1b\n"                                               \
00078      acq      "\n\t"                                                 \
00079      ".set    pop\n"                                                 \
00080      "2:\n\t"                                                        \
00081              : "=&r" (__prev), "=&r" (__cmp)                                \
00082              : "r" (oldval), "r" (newval), "m" (*mem)                       \
00083              : "memory")
00084 
00085 #if _MIPS_SIM == _ABIO32
00086 /* We can't do an atomic 64-bit operation in O32.  */
00087 #define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \
00088   (abort (), __prev = __cmp = 0)
00089 #else
00090 #define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \
00091      __asm__ __volatile__ ("\n"                                             \
00092      ".set    push\n\t"                                              \
00093      MIPS_PUSH_MIPS2                                                 \
00094      rel      "\n"                                                   \
00095      "1:\t"                                                          \
00096      "lld     %0,%4\n\t"                                             \
00097      "move    %1,$0\n\t"                                             \
00098      "bne     %0,%2,2f\n\t"                                          \
00099      "move    %1,%3\n\t"                                             \
00100      "scd     %1,%4\n\t"                                             \
00101      "beqz    %1,1b\n"                                               \
00102      acq      "\n\t"                                                 \
00103      ".set    pop\n"                                                 \
00104      "2:\n\t"                                                        \
00105              : "=&r" (__prev), "=&r" (__cmp)                                \
00106              : "r" (oldval), "r" (newval), "m" (*mem)                       \
00107              : "memory")
00108 #endif
00109 
00110 /* For all "bool" routines, we return FALSE if exchange succesful.  */
00111 
00112 #define __arch_compare_and_exchange_bool_8_int(mem, new, old, rel, acq)      \
00113 ({ typeof (*mem) __prev; int __cmp;                                   \
00114    __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq);    \
00115    !__cmp; })
00116 
00117 #define __arch_compare_and_exchange_bool_16_int(mem, new, old, rel, acq) \
00118 ({ typeof (*mem) __prev; int __cmp;                                   \
00119    __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq);   \
00120    !__cmp; })
00121 
00122 #define __arch_compare_and_exchange_bool_32_int(mem, new, old, rel, acq) \
00123 ({ typeof (*mem) __prev; int __cmp;                                   \
00124    __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq);   \
00125    !__cmp; })
00126 
00127 #define __arch_compare_and_exchange_bool_64_int(mem, new, old, rel, acq) \
00128 ({ typeof (*mem) __prev; int __cmp;                                   \
00129    __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq);   \
00130    !__cmp; })
00131 
00132 /* For all "val" routines, return the old value whether exchange
00133    successful or not.  */
00134 
00135 #define __arch_compare_and_exchange_val_8_int(mem, new, old, rel, acq)       \
00136 ({ typeof (*mem) __prev; int __cmp;                                   \
00137    __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq);    \
00138    (typeof (*mem))__prev; })
00139 
00140 #define __arch_compare_and_exchange_val_16_int(mem, new, old, rel, acq) \
00141 ({ typeof (*mem) __prev; int __cmp;                                   \
00142    __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq);   \
00143    (typeof (*mem))__prev; })
00144 
00145 #define __arch_compare_and_exchange_val_32_int(mem, new, old, rel, acq) \
00146 ({ typeof (*mem) __prev; int __cmp;                                   \
00147    __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq);   \
00148    (typeof (*mem))__prev; })
00149 
00150 #define __arch_compare_and_exchange_val_64_int(mem, new, old, rel, acq) \
00151 ({ typeof (*mem) __prev; int __cmp;                                   \
00152    __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq);   \
00153    (typeof (*mem))__prev; })
00154 
00155 /* Compare and exchange with "acquire" semantics, ie barrier after.  */
00156 
00157 #define atomic_compare_and_exchange_bool_acq(mem, new, old)    \
00158   __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
00159                       mem, new, old, "", MIPS_SYNC_STR)
00160 
00161 #define atomic_compare_and_exchange_val_acq(mem, new, old)     \
00162   __atomic_val_bysize (__arch_compare_and_exchange_val, int,   \
00163                      mem, new, old, "", MIPS_SYNC_STR)
00164 
00165 /* Compare and exchange with "release" semantics, ie barrier before.  */
00166 
00167 #define atomic_compare_and_exchange_bool_rel(mem, new, old)    \
00168   __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
00169                       mem, new, old, MIPS_SYNC_STR, "")
00170 
00171 #define atomic_compare_and_exchange_val_rel(mem, new, old)     \
00172   __atomic_val_bysize (__arch_compare_and_exchange_val, int,   \
00173                      mem, new, old, MIPS_SYNC_STR, "")
00174 
00175 
00176 
00177 /* Atomic exchange (without compare).  */
00178 
00179 #define __arch_exchange_xxx_8_int(mem, newval, rel, acq) \
00180   (abort (), 0)
00181 
00182 #define __arch_exchange_xxx_16_int(mem, newval, rel, acq) \
00183   (abort (), 0)
00184 
00185 #define __arch_exchange_xxx_32_int(mem, newval, rel, acq) \
00186 ({ typeof (*mem) __prev; int __cmp;                                         \
00187      __asm__ __volatile__ ("\n"                                             \
00188      ".set    push\n\t"                                              \
00189      MIPS_PUSH_MIPS2                                                 \
00190      rel      "\n"                                                   \
00191      "1:\t"                                                          \
00192      "ll      %0,%3\n\t"                                             \
00193      "move    %1,%2\n\t"                                             \
00194      "sc      %1,%3\n\t"                                             \
00195      "beqz    %1,1b\n"                                               \
00196      acq      "\n\t"                                                 \
00197      ".set    pop\n"                                                 \
00198      "2:\n\t"                                                        \
00199              : "=&r" (__prev), "=&r" (__cmp)                                \
00200              : "r" (newval), "m" (*mem)                              \
00201              : "memory");                                            \
00202   __prev; })
00203 
00204 #if _MIPS_SIM == _ABIO32
00205 /* We can't do an atomic 64-bit operation in O32.  */
00206 #define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \
00207   (abort (), 0)
00208 #else
00209 #define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \
00210 ({ typeof (*mem) __prev; int __cmp;                                         \
00211      __asm__ __volatile__ ("\n"                                             \
00212      ".set    push\n\t"                                              \
00213      MIPS_PUSH_MIPS2                                                 \
00214      rel      "\n"                                                   \
00215      "1:\n"                                                          \
00216      "lld     %0,%3\n\t"                                             \
00217      "move    %1,%2\n\t"                                             \
00218      "scd     %1,%3\n\t"                                             \
00219      "beqz    %1,1b\n"                                               \
00220      acq      "\n\t"                                                 \
00221      ".set    pop\n"                                                 \
00222      "2:\n\t"                                                        \
00223              : "=&r" (__prev), "=&r" (__cmp)                                \
00224              : "r" (newval), "m" (*mem)                              \
00225              : "memory");                                            \
00226   __prev; })
00227 #endif
00228 
00229 #define atomic_exchange_acq(mem, value) \
00230   __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, "", MIPS_SYNC_STR)
00231 
00232 #define atomic_exchange_rel(mem, value) \
00233   __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, MIPS_SYNC_STR, "")
00234 
00235 
00236 /* Atomically add value and return the previous (unincremented) value.  */
00237 
00238 #define __arch_exchange_and_add_8_int(mem, newval, rel, acq) \
00239   (abort (), (typeof(*mem)) 0)
00240 
00241 #define __arch_exchange_and_add_16_int(mem, newval, rel, acq) \
00242   (abort (), (typeof(*mem)) 0)
00243 
00244 #define __arch_exchange_and_add_32_int(mem, value, rel, acq) \
00245 ({ typeof (*mem) __prev; int __cmp;                                         \
00246      __asm__ __volatile__ ("\n"                                             \
00247      ".set    push\n\t"                                              \
00248      MIPS_PUSH_MIPS2                                                 \
00249      rel      "\n"                                                   \
00250      "1:\t"                                                          \
00251      "ll      %0,%3\n\t"                                             \
00252      "addu    %1,%0,%2\n\t"                                          \
00253      "sc      %1,%3\n\t"                                             \
00254      "beqz    %1,1b\n"                                               \
00255      acq      "\n\t"                                                 \
00256      ".set    pop\n"                                                 \
00257      "2:\n\t"                                                        \
00258              : "=&r" (__prev), "=&r" (__cmp)                                \
00259              : "r" (value), "m" (*mem)                                      \
00260              : "memory");                                            \
00261   __prev; })
00262 
00263 #if _MIPS_SIM == _ABIO32
00264 /* We can't do an atomic 64-bit operation in O32.  */
00265 #define __arch_exchange_and_add_64_int(mem, value, rel, acq) \
00266   (abort (), (typeof(*mem)) 0)
00267 #else
00268 #define __arch_exchange_and_add_64_int(mem, value, rel, acq) \
00269 ({ typeof (*mem) __prev; int __cmp;                                         \
00270      __asm__ __volatile__ (                                          \
00271      ".set    push\n\t"                                              \
00272      MIPS_PUSH_MIPS2                                                 \
00273      rel      "\n"                                                   \
00274      "1:\t"                                                          \
00275      "lld     %0,%3\n\t"                                             \
00276      "daddu   %1,%0,%2\n\t"                                          \
00277      "scd     %1,%3\n\t"                                             \
00278      "beqz    %1,1b\n"                                               \
00279      acq      "\n\t"                                                 \
00280      ".set    pop\n"                                                 \
00281      "2:\n\t"                                                        \
00282              : "=&r" (__prev), "=&r" (__cmp)                                \
00283              : "r" (value), "m" (*mem)                                      \
00284              : "memory");                                            \
00285   __prev; })
00286 #endif
00287 
00288 /* ??? Barrier semantics for atomic_exchange_and_add appear to be 
00289    undefined.  Use full barrier for now, as that's safe.  */
00290 #define atomic_exchange_and_add(mem, value) \
00291   __atomic_val_bysize (__arch_exchange_and_add, int, mem, value,            \
00292                      MIPS_SYNC_STR, MIPS_SYNC_STR)
00293 
00294 /* TODO: More atomic operations could be implemented efficiently; only the
00295    basic requirements are done.  */
00296 
00297 #define atomic_full_barrier() \
00298   __asm__ __volatile__ (".set push\n\t"                                     \
00299                      MIPS_PUSH_MIPS2                                        \
00300                      MIPS_SYNC_STR "\n\t"                            \
00301                      ".set pop" : : : "memory")
00302 
00303 #endif /* bits/atomic.h */