atomic.cc revision 5ea047b386c5dac78eda62305d14dedf7b5611a8
15ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes/*
25ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * Copyright (C) 2010 The Android Open Source Project
35ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes *
45ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
55ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * you may not use this file except in compliance with the License.
65ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * You may obtain a copy of the License at
75ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes *
85ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
95ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes *
105ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * Unless required by applicable law or agreed to in writing, software
115ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
125ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * See the License for the specific language governing permissions and
145ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * limitations under the License.
155ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes */
165ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
175ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#include "atomic.h"
185ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
195ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#include <sched.h>
205ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
215ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesnamespace art {
225ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
235ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes/*
245ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * Quasi-atomic 64-bit operations, for platforms that lack the real thing.
255ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes *
265ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * TODO: unify ARMv6/x86/sh implementations using the to-be-written
275ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * spin lock implementation.  We don't want to rely on mutex innards,
285ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * and it would be great if all platforms were running the same code.
295ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes */
305ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
315ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#if defined(HAVE_MACOSX_IPC)
325ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
335ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#include <libkern/OSAtomic.h>
345ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
355ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#if defined(__ppc__)        \
365ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    || defined(__PPC__)     \
375ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    || defined(__powerpc__) \
385ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    || defined(__powerpc)   \
395ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    || defined(__POWERPC__) \
405ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    || defined(_M_PPC)      \
415ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    || defined(__PPC)
425ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#define NEED_QUASIATOMICS 1
435ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#else
445ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
455ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint QuasiAtomicCas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
465ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return OSAtomicCompareAndSwap64Barrier(old_value, new_value, (int64_t*)addr) == 0;
475ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
485ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
495ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint64_t QuasiAtomicSwap64(int64_t value, volatile int64_t* addr) {
505ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int64_t oldValue;
515ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  do {
525ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    oldValue = *addr;
535ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  } while (QuasiAtomicCas64(oldValue, value, addr));
545ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return oldValue;
555ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
565ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
575ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint64_t QuasiAtomicRead64(volatile const int64_t* addr) {
585ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return OSAtomicAdd64Barrier(0, addr);
595ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
605ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#endif
615ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
625ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#elif defined(__i386__) || defined(__x86_64__)
635ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#define NEED_QUASIATOMICS 1
645ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
655ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#elif __arm__
665ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#include <machine/cpu-features.h>
675ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
685ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#ifdef __ARM_HAVE_LDREXD
695ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint64_t QuasiAtomicSwap64(int64_t new_value, volatile int64_t* addr) {
705ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int64_t prev;
715ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int status;
725ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  do {
735ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    __asm__ __volatile__ ("@ QuasiAtomicSwap64\n"
745ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        "ldrexd     %0, %H0, [%3]\n"
755ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        "strexd     %1, %4, %H4, [%3]"
765ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        : "=&r" (prev), "=&r" (status), "+m"(*addr)
775ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        : "r" (addr), "r" (new_value)
785ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        : "cc");
795ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  } while (__builtin_expect(status != 0, 0));
805ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return prev;
815ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
825ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
835ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint QuasiAtomicCas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
845ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int64_t prev;
855ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int status;
865ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  do {
875ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    __asm__ __volatile__ ("@ QuasiAtomicCas64\n"
885ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        "ldrexd     %0, %H0, [%3]\n"
895ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        "mov        %1, #0\n"
905ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        "teq        %0, %4\n"
915ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        "teqeq      %H0, %H4\n"
925ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        "strexdeq   %1, %5, %H5, [%3]"
935ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        : "=&r" (prev), "=&r" (status), "+m"(*addr)
945ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        : "r" (addr), "Ir" (old_value), "r" (new_value)
955ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        : "cc");
965ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  } while (__builtin_expect(status != 0, 0));
975ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return prev != old_value;
985ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
995ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1005ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint64_t QuasiAtomicRead64(volatile const int64_t* addr) {
1015ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int64_t value;
1025ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  __asm__ __volatile__ ("@ QuasiAtomicRead64\n"
1035ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes      "ldrexd     %0, %H0, [%1]"
1045ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes      : "=&r" (value)
1055ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes      : "r" (addr));
1065ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return value;
1075ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
1085ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1095ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#else
1105ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1115ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// on the device, we implement the 64-bit atomic operations through
1125ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// mutex locking. normally, this is bad because we must initialize
1135ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// a pthread_mutex_t before being able to use it, and this means
1145ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// having to do an initialization check on each function call, and
1155ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// that's where really ugly things begin...
1165ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes//
1175ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// BUT, as a special twist, we take advantage of the fact that in our
1185ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// pthread library, a mutex is simply a volatile word whose value is always
1195ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// initialized to 0. In other words, simply declaring a static mutex
1205ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// object initializes it !
1215ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes//
1225ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// another twist is that we use a small array of mutexes to dispatch
1235ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// the contention locks from different memory addresses
1245ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes//
1255ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1265ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#include <pthread.h>
1275ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1285ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#define  SWAP_LOCK_COUNT  32U
1295ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesstatic pthread_mutex_t  _swap_locks[SWAP_LOCK_COUNT];
1305ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1315ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#define  SWAP_LOCK(addr) &_swap_locks[((unsigned)(void*)(addr) >> 3U) % SWAP_LOCK_COUNT]
1325ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1335ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint64_t QuasiAtomicSwap64(int64_t value, volatile int64_t* addr) {
1345ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_t*  lock = SWAP_LOCK(addr);
1355ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1365ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_lock(lock);
1375ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1385ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int64_t oldValue = *addr;
1395ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  *addr = value;
1405ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1415ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_unlock(lock);
1425ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return oldValue;
1435ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
1445ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1455ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint QuasiAtomicCas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
1465ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int result;
1475ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_t*  lock = SWAP_LOCK(addr);
1485ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1495ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_lock(lock);
1505ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1515ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  if (*addr == old_value) {
1525ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    *addr  = new_value;
1535ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    result = 0;
1545ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  } else {
1555ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    result = 1;
1565ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  }
1575ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_unlock(lock);
1585ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return result;
1595ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
1605ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1615ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint64_t QuasiAtomicRead64(volatile const int64_t* addr) {
1625ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int64_t result;
1635ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_t*  lock = SWAP_LOCK(addr);
1645ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1655ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_lock(lock);
1665ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  result = *addr;
1675ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_unlock(lock);
1685ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return result;
1695ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
1705ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1715ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#endif /*__ARM_HAVE_LDREXD*/
1725ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1735ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes/*****************************************************************************/
1745ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#elif __sh__
1755ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#define NEED_QUASIATOMICS 1
1765ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1775ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#else
1785ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#error "Unsupported atomic operations for this platform"
1795ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#endif
1805ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1815ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1825ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#if NEED_QUASIATOMICS
1835ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1845ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes/* Note that a spinlock is *not* a good idea in general
1855ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * since they can introduce subtle issues. For example,
1865ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * a real-time thread trying to acquire a spinlock already
1875ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * acquired by another thread will never yeld, making the
1885ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * CPU loop endlessly!
1895ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes *
1905ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * However, this code is only used on the Linux simulator
1915ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * so it's probably ok for us.
1925ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes *
1935ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * The alternative is to use a pthread mutex, but
1945ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * these must be initialized before being used, and
1955ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * then you have the problem of lazily initializing
1965ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * a mutex without any other synchronization primitive.
1975ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes *
1985ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * TODO: these currently use sched_yield(), which is not guaranteed to
1995ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * do anything at all.  We need to use dvmIterativeSleep or a wait /
2005ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * notify mechanism if the initial attempt fails.
2015ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes */
2025ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2035ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes/* global spinlock for all 64-bit quasiatomic operations */
2045ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesstatic int32_t quasiatomic_spinlock = 0;
2055ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2065ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint QuasiAtomicCas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
2075ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int result;
2085ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2095ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
2105ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#ifdef HAVE_WIN32_THREADS
2115ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    Sleep(0);
2125ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#else
2135ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    sched_yield();
2145ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#endif
2155ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  }
2165ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2175ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  if (*addr == old_value) {
2185ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    *addr = new_value;
2195ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    result = 0;
2205ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  } else {
2215ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    result = 1;
2225ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  }
2235ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2245ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  android_atomic_release_store(0, &quasiatomic_spinlock);
2255ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2265ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return result;
2275ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
2285ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2295ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint64_t QuasiAtomicRead64(volatile const int64_t* addr) {
2305ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int64_t result;
2315ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2325ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
2335ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#ifdef HAVE_WIN32_THREADS
2345ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    Sleep(0);
2355ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#else
2365ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    sched_yield();
2375ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#endif
2385ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  }
2395ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2405ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  result = *addr;
2415ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  android_atomic_release_store(0, &quasiatomic_spinlock);
2425ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2435ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return result;
2445ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
2455ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2465ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint64_t QuasiAtomicSwap64(int64_t value, volatile int64_t* addr) {
2475ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int64_t result;
2485ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2495ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
2505ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#ifdef HAVE_WIN32_THREADS
2515ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    Sleep(0);
2525ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#else
2535ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    sched_yield();
2545ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#endif
2555ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  }
2565ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2575ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  result = *addr;
2585ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  *addr = value;
2595ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  android_atomic_release_store(0, &quasiatomic_spinlock);
2605ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2615ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return result;
2625ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
2635ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2645ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#endif /*NEED_QUASIATOMICS*/
2655ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2665ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}  // namespace art
267