P99
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
p99_atomic_arm.h
Go to the documentation of this file.
00001 /* This may look like nonsense, but it really is -*- mode: C -*-              */
00002 /*                                                                            */
00003 /* Except for parts copied from previous work and as explicitly stated below, */
00004 /* the authors and copyright holders for this work are as follows:            */
00005 /* (C) copyright  2012 Jens Gustedt, INRIA, France                            */
00006 /* (C) copyright  2012 William Morris                                         */
00007 /*                                                                            */
00008 /* This file is free software; it is part of the P99 project.                 */
00009 /* You can redistribute it and/or modify it under the terms of the QPL as     */
00010 /* given in the file LICENSE. It is distributed without any warranty;         */
00011 /* without even the implied warranty of merchantability or fitness for a      */
00012 /* particular purpose.                                                        */
00013 /*                                                                            */
00014 #ifndef P99_ATOMIC_ARM_H
00015 #define P99_ATOMIC_ARM_H 1
00016 
00017 #ifndef P99_ATOMIC_H
00018 # warning "never include this file directly, use p99_atomic.h, instead"
00019 #endif
00020 
00021 #if !defined(__thumb__) && !defined(__thumb2__)
00022 /* When in arm mode we can't do addressing with offset, here, so use
00023    direct addressing. */
00024 p99_inline
00025 uint8_t p00_arm_ldrexb(uint8_t volatile*p00_ptr) {
00026   uint8_t p00_ret;
00027   __asm__ volatile ("ldrexb %0,[%1]\t@ load exclusive\n"
00028                     : "=&r" (p00_ret)
00029                     : "r" (p00_ptr)
00030                     : "cc", "memory"
00031                    );
00032   return p00_ret;
00033 }
00034 
00035 p99_inline
00036 _Bool p00_arm_strexb(uint8_t volatile*p00_ptr, uint8_t p00_val) {
00037   uint32_t p00_ret;
00038   __asm__ volatile ("strexb %0,%1,[%2]\t@ store exclusive\n"
00039                     : "=&r" (p00_ret)
00040                     : "r" (p00_val), "r" (p00_ptr)
00041                     : "cc", "memory"
00042                    );
00043   return p00_ret;
00044 }
00045 p99_inline
00046 uint16_t p00_arm_ldrexh(uint16_t volatile*p00_ptr) {
00047   uint16_t p00_ret;
00048   __asm__ volatile ("ldrexh %0,[%1]\t@ load exclusive\n"
00049                     : "=&r" (p00_ret)
00050                     : "r" (p00_ptr)
00051                     : "cc", "memory"
00052                    );
00053   return p00_ret;
00054 }
00055 
00056 p99_inline
00057 _Bool p00_arm_strexh(uint16_t volatile*p00_ptr, uint16_t p00_val) {
00058   uint32_t p00_ret;
00059   __asm__ volatile ("strexh %0,%1,[%2]\t@ store exclusive\n"
00060                     : "=&r" (p00_ret)
00061                     : "r" (p00_val), "r" (p00_ptr)
00062                     : "cc", "memory"
00063                    );
00064   return p00_ret;
00065 }
00066 p99_inline
00067 uint32_t p00_arm_ldrex(uint32_t volatile*p00_ptr) {
00068   uint32_t p00_ret;
00069   __asm__ volatile ("ldrex %0,[%1]\t@ load exclusive\n"
00070                     : "=&r" (p00_ret)
00071                     : "r" (p00_ptr)
00072                     : "cc", "memory"
00073                    );
00074   return p00_ret;
00075 }
00076 
00077 p99_inline
00078 _Bool p00_arm_strex(uint32_t volatile*p00_ptr, uint32_t p00_val) {
00079   uint32_t p00_ret;
00080   __asm__ volatile ("strex %0,%1,[%2]\t@ store exclusive\n"
00081                     : "=&r" (p00_ret)
00082                     : "r" (p00_val), "r" (p00_ptr)
00083                     : "cc", "memory"
00084                    );
00085   return p00_ret;
00086 }
00087 # if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
00088 p99_inline
00089 uint64_t p00_arm_ldrexd(uint64_t volatile*p00_ptr) {
00090   uint64_t p00_ret;
00091   __asm__ volatile ("ldrexd %0, %H0, [%1]\t@ load exclusive\n"
00092                     : "=&r" (p00_ret)
00093                     : "r" (p00_ptr)
00094                     : "cc", "memory"
00095                    );
00096   return p00_ret;
00097 }
00098 
00099 p99_inline
00100 _Bool p00_arm_strex(uint64_t volatile*p00_ptr, uint64_t p00_val) {
00101   uint32_t p00_ret;
00102   __asm__ volatile ("strex %0, %1, %H1, [%2]\t@ store exclusive\n"
00103                     : "=&r" (p00_ret)
00104                     : "r" (p00_val), "r" (p00_ptr)
00105                     : "cc", "memory"
00106                    );
00107   return p00_ret;
00108 }
00109 # endif
00110 #else
00111 /* When in thumb mode we can do addressing with offset, here, so use
00112    the "m" constraint to the assembler. */
00113 p99_inline
00114 uint8_t p00_arm_ldrexb(uint8_t volatile*p00_ptr) {
00115   uint8_t p00_ret;
00116   __asm__ volatile ("ldrexb %0,%1\t@ load exclusive\n"
00117                     : "=&r" (p00_ret)
00118                     : "m" (p00_ptr)
00119                     : "cc", "memory"
00120                    );
00121   return p00_ret;
00122 }
00123 
00124 p99_inline
00125 _Bool p00_arm_strexb(uint8_t volatile*p00_ptr, uint8_t p00_val) {
00126   uint32_t p00_ret;
00127   __asm__ volatile ("strexb %0,%1,%2\t@ store exclusive\n"
00128                     : "=&r" (p00_ret)
00129                     : "r" (p00_val), "m" (p00_ptr)
00130                     : "cc", "memory"
00131                    );
00132   return p00_ret;
00133 }
00134 p99_inline
00135 uint16_t p00_arm_ldrexh(uint16_t volatile*p00_ptr) {
00136   uint16_t p00_ret;
00137   __asm__ volatile ("ldrexh %0,%1\t@ load exclusive\n"
00138                     : "=&r" (p00_ret)
00139                     : "m" (p00_ptr)
00140                     : "cc", "memory"
00141                    );
00142   return p00_ret;
00143 }
00144 
00145 p99_inline
00146 _Bool p00_arm_strexh(uint16_t volatile*p00_ptr, uint16_t p00_val) {
00147   uint32_t p00_ret;
00148   __asm__ volatile ("strexh %0,%1,%2\t@ store exclusive\n"
00149                     : "=&r" (p00_ret)
00150                     : "r" (p00_val), "m" (p00_ptr)
00151                     : "cc", "memory"
00152                    );
00153   return p00_ret;
00154 }
00155 p99_inline
00156 uint32_t p00_arm_ldrex(uint32_t volatile*p00_ptr) {
00157   uint32_t p00_ret;
00158   __asm__ volatile ("ldrex %0,%1\t@ load exclusive\n"
00159                     : "=&r" (p00_ret)
00160                     : "m" (p00_ptr)
00161                     : "cc", "memory"
00162                    );
00163   return p00_ret;
00164 }
00165 
00166 p99_inline
00167 _Bool p00_arm_strex(uint32_t volatile*p00_ptr, uint32_t p00_val) {
00168   uint32_t p00_ret;
00169   __asm__ volatile ("strex %0,%1,%2\t@ store exclusive\n"
00170                     : "=&r" (p00_ret)
00171                     : "r" (p00_val), "m" (p00_ptr)
00172                     : "cc", "memory"
00173                    );
00174   return p00_ret;
00175 }
00176 # if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
00177 p99_inline
00178 uint64_t p00_arm_ldrexd(uint64_t volatile*p00_ptr) {
00179   uint64_t p00_ret;
00180   __asm__ volatile ("ldrexd %0, %H0, %1\t@ load exclusive\n"
00181                     : "=&r" (p00_ret)
00182                     : "m" (p00_ptr)
00183                     : "cc", "memory"
00184                    );
00185   return p00_ret;
00186 }
00187 
00188 p99_inline
00189 _Bool p00_arm_strexd(uint64_t volatile*p00_ptr, uint64_t p00_val) {
00190   uint32_t p00_ret;
00191   __asm__ volatile ("strexd %0, %1, %H1, %2\t@ store exclusive\n"
00192                     : "=&r" (p00_ret)
00193                     : "r" (p00_val), "m" (p00_ptr)
00194                     : "cc", "memory"
00195                    );
00196   return p00_ret;
00197 }
00198 # endif
00199 #endif
00200 
00201 p99_inline
00202 uint8_t p00_atomic_exchange_1(uint8_t volatile* p00_objp, uint8_t p00_des) {
00203   for (;;) {
00204     uint8_t p00_ret = p00_arm_ldrexb(object);
00205     if (!p00_arm_strexb(object, p00_des)) return p00_ret;
00206   }
00207 }
00208 
00209 p99_inline
00210 uint16_t p00_atomic_exchange_2(uint16_t volatile* p00_objp, uint16_t p00_des) {
00211   for (;;) {
00212     uint16_t p00_ret = p00_arm_ldrexh(object);
00213     if (!p00_arm_strexh(object, p00_des)) return p00_ret;
00214   }
00215 }
00216 
00217 p99_inline
00218 uint32_t p00_atomic_exchange_4(uint32_t volatile* p00_objp, uint32_t p00_des) {
00219   for (;;) {
00220     uint32_t p00_ret = p00_arm_ldrex(object);
00221     if (!p00_arm_strex(object, p00_des)) return p00_ret;
00222   }
00223 }
00224 
00225 #if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || defined(P00_DOXYGEN)
00226 p99_inline
00227 uint64_t p00_atomic_exchange_8(uint64_t volatile* p00_objp, uint64_t p00_des) {
00228   for (;;) {
00229     uint64_t p00_ret = p00_arm_ldrexd(object);
00230     if (!p00_arm_strexd(object, p00_des)) return p00_ret;
00231   }
00232 }
00233 #endif
00234 
00235 #if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) && !defined(P00_DOXYGEN)
00236 
00237 p99_inline
00238 uint32_t p00_sync_lock_test_and_set(uint32_t volatile *p00_objp) {
00239   return __sync_lock_test_and_set(p00_objp, 1);
00240 }
00241 
00242 p99_inline
00243 void p00_sync_lock_release(uint32_t volatile *p00_objp) {
00244   __sync_lock_release(p00_objp);
00245 }
00246 
00247 p99_inline
00248 void p00_mfence(void) {
00249   __sync_synchronize();
00250 }
00251 
00252 
00253 #else
00254 
00281 p99_inline
00282 uint32_t p00_sync_lock_test_and_set(uint32_t volatile *object) {
00283   for (;;) {
00284     uint32_t p00_ret = p00_arm_ldrex(object);
00285     /* Even if the result has been a 1 in p00_ret, We must imperatively
00286        put a strex after the ldex since otherwise we would block other
00287        threads when they try to access this. On the other hand even if
00288        the strex doesn't succeed but p00_ret is already set, we are also
00289        done. */
00290     if (!p00_arm_strex(object, 1) || p00_ret) return p00_ret;
00291   }
00292 }
00293 
00294 p99_inline
00295 void p00_sync_lock_release(uint32_t volatile *object) {
00296   __sync_lock_release(object);
00297 }
00298 
00299 p99_inline
00300 void p00_mfence(void) {
00301   __asm__ __volatile__("dmb":::"memory");
00302 }
00303 
00304 p99_inline
00305 uint32_t __sync_val_compare_and_swap_4(uint32_t volatile *object, uint32_t p00_pre, uint32_t p00_des) {
00306   uint32_t p00_ret = 0;
00307   for (;;) {
00308     p00_ret = p00_arm_ldrex(object);
00309     if (p00_pre != p00_ret) {
00310       /* wrong value, cancel */
00311       p00_arm_strex(object, p00_ret);
00312       break;
00313     } else {
00314       if (!p00_arm_strex(object, p00_des)) break;
00315       /* somebody else touched it, continue */
00316     }
00317   }
00318   return p00_ret;
00319 }
00320 
00321 p99_inline
00322 uint32_t __sync_fetch_and_add_4(uint32_t volatile *object, uint32_t p00_val) {
00323   uint32_t p00_ret = 0;
00324   for (;;) {
00325     p00_ret = p00_arm_ldrex(object);
00326     uint32_t p00_des = p00_ret + p00_val;
00327     if (!p00_arm_strex(object, p00_des)) break;
00328     /* somebody else touched it, continue */
00329   }
00330   return p00_ret;
00331 }
00332 
00333 p99_inline
00334 uint32_t __sync_fetch_and_sub_4(uint32_t volatile *object, uint32_t p00_val) {
00335   uint32_t p00_ret = 0;
00336   for (;;) {
00337     p00_ret = p00_arm_ldrex(object);
00338     uint32_t p00_des = p00_ret - p00_val;
00339     if (!p00_arm_strex(object, p00_des)) break;
00340     /* somebody else touched it, continue */
00341   }
00342   return p00_ret;
00343 }
00344 
00345 p99_inline
00346 uint32_t __sync_fetch_and_or_4(uint32_t volatile *object, uint32_t p00_val) {
00347   uint32_t p00_ret = 0;
00348   for (;;) {
00349     p00_ret = p00_arm_ldrex(object);
00350     uint32_t p00_des = p00_ret | p00_val;
00351     if (!p00_arm_strex(object, p00_des)) break;
00352     /* somebody else touched it, continue */
00353   }
00354   return p00_ret;
00355 }
00356 
00357 p99_inline
00358 uint32_t __sync_fetch_and_and_4(uint32_t volatile *object, uint32_t p00_val) {
00359   uint32_t p00_ret = 0;
00360   for (;;) {
00361     p00_ret = p00_arm_ldrex(object);
00362     uint32_t p00_des = p00_ret & p00_val;
00363     if (!p00_arm_strex(object, p00_des)) break;
00364     /* somebody else touched it, continue */
00365   }
00366   return p00_ret;
00367 }
00368 
00369 p99_inline
00370 uint32_t __sync_fetch_and_xor_4(uint32_t volatile *object, uint32_t p00_val) {
00371   uint32_t p00_ret = 0;
00372   for (;;) {
00373     p00_ret = p00_arm_ldrex(object);
00374     uint32_t p00_des = p00_ret ^ p00_val;
00375     if (!p00_arm_strex(object, p00_des)) break;
00376     /* somebody else touched it, continue */
00377   }
00378   return p00_ret;
00379 }
00380 
00381 #undef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
00382 #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
00383 
00384 
00389 # endif
00390 
00391 #endif
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines