1e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner/*
2e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner * Copyright (C) 2011 The Android Open Source Project
3e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner *
4e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner * Licensed under the Apache License, Version 2.0 (the "License");
5e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner * you may not use this file except in compliance with the License.
6e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner * You may obtain a copy of the License at
7e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner *
8e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner *      http://www.apache.org/licenses/LICENSE-2.0
9e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner *
10e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner * Unless required by applicable law or agreed to in writing, software
11e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner * distributed under the License is distributed on an "AS IS" BASIS,
12e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner * See the License for the specific language governing permissions and
14e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner * limitations under the License.
15e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner */
16e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner#ifndef BIONIC_ATOMIC_ARM_H
17e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner#define BIONIC_ATOMIC_ARM_H
18e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner
19845c778fa6ebb3ff3feaac0c268d93f4017c0cdaSerban Constantinescu__ATOMIC_INLINE__ void __bionic_memory_barrier() {
202b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes#if defined(ANDROID_SMP) && ANDROID_SMP == 1
21845c778fa6ebb3ff3feaac0c268d93f4017c0cdaSerban Constantinescu  __asm__ __volatile__ ( "dmb ish" : : : "memory" );
22e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner#else
232b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes  /* A simple compiler barrier. */
242b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes  __asm__ __volatile__ ( "" : : : "memory" );
25e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner#endif
26e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner}
27e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner
284c186ffb837a2bd852e7983f217a945d415cefbcElliott Hughes/* Compare-and-swap, without any explicit barriers. Note that this function
29e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner * returns 0 on success, and 1 on failure. The opposite convention is typically
30e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner * used on other platforms.
31e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner */
322b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes__ATOMIC_INLINE__ int __bionic_cmpxchg(int32_t old_value, int32_t new_value, volatile int32_t* ptr) {
332b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes  int32_t prev, status;
342b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes  do {
352b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes    __asm__ __volatile__ (
362b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          "ldrex %0, [%3]\n"
372b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          "mov %1, #0\n"
382b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          "teq %0, %4\n"
39e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner#ifdef __thumb2__
402b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          "it eq\n"
41e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner#endif
422b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          "strexeq %1, %5, [%3]"
432b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          : "=&r" (prev), "=&r" (status), "+m"(*ptr)
442b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          : "r" (ptr), "Ir" (old_value), "r" (new_value)
452b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          : "cc");
462b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes  } while (__builtin_expect(status != 0, 0));
472b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes  return prev != old_value;
48e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner}
49e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner
502b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes/* Swap, without any explicit barriers. */
512b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes__ATOMIC_INLINE__ int32_t __bionic_swap(int32_t new_value, volatile int32_t* ptr) {
522b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes  int32_t prev, status;
532b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes  do {
542b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes    __asm__ __volatile__ (
552b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          "ldrex %0, [%3]\n"
562b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          "strex %1, %4, [%3]"
572b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          : "=&r" (prev), "=&r" (status), "+m" (*ptr)
582b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          : "r" (ptr), "r" (new_value)
592b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          : "cc");
602b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes  } while (__builtin_expect(status != 0, 0));
612b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes  return prev;
62e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner}
63e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner
642b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes/* Atomic decrement, without explicit barriers. */
652b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes__ATOMIC_INLINE__ int32_t __bionic_atomic_dec(volatile int32_t* ptr) {
662b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes  int32_t prev, tmp, status;
672b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes  do {
682b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes    __asm__ __volatile__ (
692b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          "ldrex %0, [%4]\n"
702b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          "sub %1, %0, #1\n"
712b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          "strex %2, %1, [%4]"
722b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          : "=&r" (prev), "=&r" (tmp), "=&r" (status), "+m"(*ptr)
732b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          : "r" (ptr)
742b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes          : "cc");
752b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes  } while (__builtin_expect(status != 0, 0));
762b333b97a241eec63d531874e28f2a894bc06aa0Elliott Hughes  return prev;
77e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner}
78e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner
79e31bfae2baa96742f998155ee26e56c826a8ce3aDavid 'Digit' Turner#endif /* SYS_ATOMICS_ARM_H */
80