atomic.cc revision 557e027f86d86f801e1b48055f8116f2d83d3d5c
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
49557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughesstatic inline int64_t QuasiAtomicSwap64Impl(int64_t value, volatile int64_t* addr) {
50557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  int64_t old_value;
515ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  do {
52557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes    old_value = *addr;
53557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  } while (QuasiAtomicCas64(old_value, value, addr));
54557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  return old_value;
55557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes}
56557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes
57557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughesint64_t QuasiAtomicSwap64(int64_t value, volatile int64_t* addr) {
58557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  return QuasiAtomicSwap64Impl(value, addr);
59557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes}
60557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes
61557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughesint64_t QuasiAtomicSwap64Sync(int64_t value, volatile int64_t* addr) {
62557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  ANDROID_MEMBAR_STORE();
63557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  int64_t old_value = QuasiAtomicSwap64Impl(value, addr);
64557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  /* TUNING: barriers can be avoided on some architectures */
65557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  ANDROID_MEMBAR_FULL();
66557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  return old_value;
675ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
685ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
695ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint64_t QuasiAtomicRead64(volatile const int64_t* addr) {
705ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return OSAtomicAdd64Barrier(0, addr);
715ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
725ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#endif
735ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
745ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#elif defined(__i386__) || defined(__x86_64__)
755ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#define NEED_QUASIATOMICS 1
765ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
775ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#elif __arm__
785ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#include <machine/cpu-features.h>
795ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
805ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#ifdef __ARM_HAVE_LDREXD
81557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughesstatic inline int64_t QuasiAtomicSwap64Impl(int64_t new_value, volatile int64_t* addr) {
825ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int64_t prev;
835ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int status;
845ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  do {
855ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    __asm__ __volatile__ ("@ QuasiAtomicSwap64\n"
865ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        "ldrexd     %0, %H0, [%3]\n"
875ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        "strexd     %1, %4, %H4, [%3]"
885ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        : "=&r" (prev), "=&r" (status), "+m"(*addr)
895ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        : "r" (addr), "r" (new_value)
905ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        : "cc");
915ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  } while (__builtin_expect(status != 0, 0));
925ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return prev;
935ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
945ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
95557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughesint64_t QuasiAtomicSwap64(int64_t new_value, volatile int64_t* addr) {
96557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  return QuasiAtomicSwap64Impl(new_value, addr);
97557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes}
98557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes
99557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughesint64_t QuasiAtomicSwap64Sync(int64_t new_value, volatile int64_t* addr) {
100557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  ANDROID_MEMBAR_STORE();
101557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  int64_t old_value = QuasiAtomicSwap64Impl(new_value, addr);
102557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  ANDROID_MEMBAR_FULL();
103557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  return old_value;
104557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes}
105557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes
1065ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint QuasiAtomicCas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
1075ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int64_t prev;
1085ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int status;
1095ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  do {
1105ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    __asm__ __volatile__ ("@ QuasiAtomicCas64\n"
1115ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        "ldrexd     %0, %H0, [%3]\n"
1125ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        "mov        %1, #0\n"
1135ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        "teq        %0, %4\n"
1145ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        "teqeq      %H0, %H4\n"
1155ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        "strexdeq   %1, %5, %H5, [%3]"
1165ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        : "=&r" (prev), "=&r" (status), "+m"(*addr)
1175ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        : "r" (addr), "Ir" (old_value), "r" (new_value)
1185ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes        : "cc");
1195ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  } while (__builtin_expect(status != 0, 0));
1205ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return prev != old_value;
1215ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
1225ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1235ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint64_t QuasiAtomicRead64(volatile const int64_t* addr) {
1245ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int64_t value;
1255ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  __asm__ __volatile__ ("@ QuasiAtomicRead64\n"
1265ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes      "ldrexd     %0, %H0, [%1]"
1275ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes      : "=&r" (value)
1285ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes      : "r" (addr));
1295ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return value;
1305ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
1315ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1325ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#else
1335ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1345ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// on the device, we implement the 64-bit atomic operations through
1355ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// mutex locking. normally, this is bad because we must initialize
1365ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// a pthread_mutex_t before being able to use it, and this means
1375ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// having to do an initialization check on each function call, and
1385ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// that's where really ugly things begin...
1395ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes//
1405ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// BUT, as a special twist, we take advantage of the fact that in our
1415ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// pthread library, a mutex is simply a volatile word whose value is always
1425ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// initialized to 0. In other words, simply declaring a static mutex
1435ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// object initializes it !
1445ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes//
1455ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// another twist is that we use a small array of mutexes to dispatch
1465ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes// the contention locks from different memory addresses
1475ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes//
1485ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1495ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#include <pthread.h>
1505ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1515ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#define  SWAP_LOCK_COUNT  32U
1525ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesstatic pthread_mutex_t  _swap_locks[SWAP_LOCK_COUNT];
1535ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1545ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#define  SWAP_LOCK(addr) &_swap_locks[((unsigned)(void*)(addr) >> 3U) % SWAP_LOCK_COUNT]
1555ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1565ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint64_t QuasiAtomicSwap64(int64_t value, volatile int64_t* addr) {
1575ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_t*  lock = SWAP_LOCK(addr);
1585ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1595ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_lock(lock);
1605ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
161557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  int64_t old_value = *addr;
1625ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  *addr = value;
1635ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1645ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_unlock(lock);
165557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  return old_value;
166557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes}
167557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes
168557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughesint64_t QuasiAtomicSwap64Sync(int64_t value, volatile int64_t* addr) {
169557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  // Same as QuasiAtomicSwap64 - mutex handles barrier.
170557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  return QuasiAtomicSwap64(value, addr);
1715ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
1725ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1735ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint QuasiAtomicCas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
1745ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int result;
1755ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_t*  lock = SWAP_LOCK(addr);
1765ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1775ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_lock(lock);
1785ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1795ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  if (*addr == old_value) {
1805ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    *addr  = new_value;
1815ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    result = 0;
1825ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  } else {
1835ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    result = 1;
1845ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  }
1855ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_unlock(lock);
1865ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return result;
1875ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
1885ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1895ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint64_t QuasiAtomicRead64(volatile const int64_t* addr) {
1905ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int64_t result;
1915ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_t*  lock = SWAP_LOCK(addr);
1925ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1935ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_lock(lock);
1945ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  result = *addr;
1955ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  pthread_mutex_unlock(lock);
1965ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return result;
1975ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
1985ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
1995ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#endif /*__ARM_HAVE_LDREXD*/
2005ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2015ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes/*****************************************************************************/
2025ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#elif __sh__
2035ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#define NEED_QUASIATOMICS 1
2045ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2055ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#else
2065ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#error "Unsupported atomic operations for this platform"
2075ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#endif
2085ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2095ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2105ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#if NEED_QUASIATOMICS
2115ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2125ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes/* Note that a spinlock is *not* a good idea in general
2135ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * since they can introduce subtle issues. For example,
2145ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * a real-time thread trying to acquire a spinlock already
2155ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * acquired by another thread will never yeld, making the
2165ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * CPU loop endlessly!
2175ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes *
2185ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * However, this code is only used on the Linux simulator
2195ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * so it's probably ok for us.
2205ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes *
2215ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * The alternative is to use a pthread mutex, but
2225ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * these must be initialized before being used, and
2235ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * then you have the problem of lazily initializing
2245ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * a mutex without any other synchronization primitive.
2255ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes *
2265ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * TODO: these currently use sched_yield(), which is not guaranteed to
2275ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * do anything at all.  We need to use dvmIterativeSleep or a wait /
2285ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes * notify mechanism if the initial attempt fails.
2295ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes */
2305ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2315ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes/* global spinlock for all 64-bit quasiatomic operations */
2325ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesstatic int32_t quasiatomic_spinlock = 0;
2335ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2345ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint QuasiAtomicCas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
2355ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int result;
2365ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2375ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
2385ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#ifdef HAVE_WIN32_THREADS
2395ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    Sleep(0);
2405ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#else
2415ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    sched_yield();
2425ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#endif
2435ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  }
2445ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2455ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  if (*addr == old_value) {
2465ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    *addr = new_value;
2475ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    result = 0;
2485ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  } else {
2495ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    result = 1;
2505ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  }
2515ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2525ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  android_atomic_release_store(0, &quasiatomic_spinlock);
2535ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2545ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return result;
2555ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
2565ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2575ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint64_t QuasiAtomicRead64(volatile const int64_t* addr) {
2585ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int64_t result;
2595ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2605ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
2615ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#ifdef HAVE_WIN32_THREADS
2625ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    Sleep(0);
2635ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#else
2645ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    sched_yield();
2655ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#endif
2665ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  }
2675ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2685ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  result = *addr;
2695ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  android_atomic_release_store(0, &quasiatomic_spinlock);
2705ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2715ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return result;
2725ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
2735ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2745ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughesint64_t QuasiAtomicSwap64(int64_t value, volatile int64_t* addr) {
2755ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  int64_t result;
2765ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2775ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  while (android_atomic_acquire_cas(0, 1, &quasiatomic_spinlock)) {
2785ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#ifdef HAVE_WIN32_THREADS
2795ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    Sleep(0);
2805ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#else
2815ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes    sched_yield();
2825ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#endif
2835ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  }
2845ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2855ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  result = *addr;
2865ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  *addr = value;
2875ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  android_atomic_release_store(0, &quasiatomic_spinlock);
2885ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2895ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes  return result;
2905ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}
2915ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
292557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughesint64_t QuasiAtomicSwap64Sync(int64_t value, volatile int64_t* addr) {
293557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  // Same as QuasiAtomicSwap64 - syscall handles barrier.
294557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes  return QuasiAtomicSwap64(value, addr);
295557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes}
296557e027f86d86f801e1b48055f8116f2d83d3d5cElliott Hughes
2975ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes#endif /*NEED_QUASIATOMICS*/
2985ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes
2995ea047b386c5dac78eda62305d14dedf7b5611a8Elliott Hughes}  // namespace art
300