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