Home | History | Annotate | Download | only in cutils
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef ANDROID_CUTILS_ATOMIC_ARM_H
     18 #define ANDROID_CUTILS_ATOMIC_ARM_H
     19 
     20 #include <stdint.h>
     21 
     22 #ifndef ANDROID_ATOMIC_INLINE
     23 #define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
     24 #endif
     25 
     26 extern ANDROID_ATOMIC_INLINE void android_compiler_barrier()
     27 {
     28     __asm__ __volatile__ ("" : : : "memory");
     29 }
     30 
     31 extern ANDROID_ATOMIC_INLINE void android_memory_barrier()
     32 {
     33 #if ANDROID_SMP == 0
     34     android_compiler_barrier();
     35 #else
     36     __asm__ __volatile__ ("dmb" : : : "memory");
     37 #endif
     38 }
     39 
     40 extern ANDROID_ATOMIC_INLINE
     41 int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
     42 {
     43     int32_t value = *ptr;
     44     android_memory_barrier();
     45     return value;
     46 }
     47 
     48 extern ANDROID_ATOMIC_INLINE
     49 int32_t android_atomic_release_load(volatile const int32_t *ptr)
     50 {
     51     android_memory_barrier();
     52     return *ptr;
     53 }
     54 
     55 extern ANDROID_ATOMIC_INLINE
     56 void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
     57 {
     58     *ptr = value;
     59     android_memory_barrier();
     60 }
     61 
     62 extern ANDROID_ATOMIC_INLINE
     63 void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
     64 {
     65     android_memory_barrier();
     66     *ptr = value;
     67 }
     68 
     69 extern ANDROID_ATOMIC_INLINE
     70 int android_atomic_cas(int32_t old_value, int32_t new_value,
     71                        volatile int32_t *ptr)
     72 {
     73     int32_t prev, status;
     74     do {
     75         __asm__ __volatile__ ("ldrex %0, [%3]\n"
     76                               "mov %1, #0\n"
     77                               "teq %0, %4\n"
     78 #ifdef __thumb2__
     79                               "it eq\n"
     80 #endif
     81                               "strexeq %1, %5, [%3]"
     82                               : "=&r" (prev), "=&r" (status), "+m"(*ptr)
     83                               : "r" (ptr), "Ir" (old_value), "r" (new_value)
     84                               : "cc");
     85     } while (__builtin_expect(status != 0, 0));
     86     return prev != old_value;
     87 }
     88 
     89 extern ANDROID_ATOMIC_INLINE
     90 int android_atomic_acquire_cas(int32_t old_value, int32_t new_value,
     91                                volatile int32_t *ptr)
     92 {
     93     int status = android_atomic_cas(old_value, new_value, ptr);
     94     android_memory_barrier();
     95     return status;
     96 }
     97 
     98 extern ANDROID_ATOMIC_INLINE
     99 int android_atomic_release_cas(int32_t old_value, int32_t new_value,
    100                                volatile int32_t *ptr)
    101 {
    102     android_memory_barrier();
    103     return android_atomic_cas(old_value, new_value, ptr);
    104 }
    105 
    106 extern ANDROID_ATOMIC_INLINE
    107 int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
    108 {
    109     int32_t prev, tmp, status;
    110     android_memory_barrier();
    111     do {
    112         __asm__ __volatile__ ("ldrex %0, [%4]\n"
    113                               "add %1, %0, %5\n"
    114                               "strex %2, %1, [%4]"
    115                               : "=&r" (prev), "=&r" (tmp),
    116                                 "=&r" (status), "+m" (*ptr)
    117                               : "r" (ptr), "Ir" (increment)
    118                               : "cc");
    119     } while (__builtin_expect(status != 0, 0));
    120     return prev;
    121 }
    122 
    123 extern ANDROID_ATOMIC_INLINE int32_t android_atomic_inc(volatile int32_t *addr)
    124 {
    125     return android_atomic_add(1, addr);
    126 }
    127 
    128 extern ANDROID_ATOMIC_INLINE int32_t android_atomic_dec(volatile int32_t *addr)
    129 {
    130     return android_atomic_add(-1, addr);
    131 }
    132 
    133 extern ANDROID_ATOMIC_INLINE
    134 int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
    135 {
    136     int32_t prev, tmp, status;
    137     android_memory_barrier();
    138     do {
    139         __asm__ __volatile__ ("ldrex %0, [%4]\n"
    140                               "and %1, %0, %5\n"
    141                               "strex %2, %1, [%4]"
    142                               : "=&r" (prev), "=&r" (tmp),
    143                                 "=&r" (status), "+m" (*ptr)
    144                               : "r" (ptr), "Ir" (value)
    145                               : "cc");
    146     } while (__builtin_expect(status != 0, 0));
    147     return prev;
    148 }
    149 
    150 extern ANDROID_ATOMIC_INLINE
    151 int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
    152 {
    153     int32_t prev, tmp, status;
    154     android_memory_barrier();
    155     do {
    156         __asm__ __volatile__ ("ldrex %0, [%4]\n"
    157                               "orr %1, %0, %5\n"
    158                               "strex %2, %1, [%4]"
    159                               : "=&r" (prev), "=&r" (tmp),
    160                                 "=&r" (status), "+m" (*ptr)
    161                               : "r" (ptr), "Ir" (value)
    162                               : "cc");
    163     } while (__builtin_expect(status != 0, 0));
    164     return prev;
    165 }
    166 
    167 #endif /* ANDROID_CUTILS_ATOMIC_ARM_H */
    168