1 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. See the AUTHORS file for names of contributors.
5 // AtomicPointer provides storage for a lock-free pointer.
6 // Platform-dependent implementation of AtomicPointer:
7 // - If the platform provides a cheap barrier, we use it with raw pointers
8 // - If <atomic> is present (on newer versions of gcc, it is), we use
9 // a <atomic>-based AtomicPointer. However we prefer the memory
10 // barrier based version, because at least on a gcc 4.4 32-bit build
11 // on linux, we have encountered a buggy <atomic> implementation.
12 // Also, some <atomic> implementations are much slower than a memory-barrier
13 // based implementation (~16ns for <atomic> based acquire-load vs. ~1ns for
14 // a barrier based acquire-load).
15 // This code is based on atomicops-internals-* in Google's perftools:
16 // http://code.google.com/p/google-perftools/source/browse/#svn%2Ftrunk%2Fsrc%2Fbase
18 #ifndef PORT_ATOMIC_POINTER_H_
19 #define PORT_ATOMIC_POINTER_H_
22 #ifdef LEVELDB_ATOMIC_PRESENT
29 #include <libkern/OSAtomic.h>
32 #if defined(_M_X64) || defined(__x86_64__)
33 #define ARCH_CPU_X86_FAMILY 1
34 #elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
35 #define ARCH_CPU_X86_FAMILY 1
36 #elif defined(__ARMEL__)
37 #define ARCH_CPU_ARM_FAMILY 1
38 #elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__)
39 #define ARCH_CPU_PPC_FAMILY 1
45 // Define MemoryBarrier() if available
47 #if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY)
48 // windows.h already provides a MemoryBarrier(void) macro
49 // http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx
50 #define LEVELDB_HAVE_MEMORY_BARRIER
53 #elif defined(OS_MACOSX)
54 inline void MemoryBarrier() {
57 #define LEVELDB_HAVE_MEMORY_BARRIER
60 #elif defined(ARCH_CPU_X86_FAMILY) && defined(__GNUC__)
61 inline void MemoryBarrier() {
62 // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on
63 // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering.
64 __asm__ __volatile__("" : : : "memory");
66 #define LEVELDB_HAVE_MEMORY_BARRIER
69 #elif defined(ARCH_CPU_X86_FAMILY) && defined(__SUNPRO_CC)
70 inline void MemoryBarrier() {
71 // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on
72 // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering.
73 asm volatile("" : : : "memory");
75 #define LEVELDB_HAVE_MEMORY_BARRIER
78 #elif defined(ARCH_CPU_ARM_FAMILY) && defined(__linux__)
79 typedef void (*LinuxKernelMemoryBarrierFunc)(void);
80 // The Linux ARM kernel provides a highly optimized device-specific memory
81 // barrier function at a fixed memory address that is mapped in every
82 // user-level process.
84 // This beats using CPU-specific instructions which are, on single-core
85 // devices, un-necessary and very costly (e.g. ARMv7-A "dmb" takes more
86 // than 180ns on a Cortex-A8 like the one on a Nexus One). Benchmarking
87 // shows that the extra function call cost is completely negligible on
88 // multi-core devices.
90 inline void MemoryBarrier() {
91 (*(LinuxKernelMemoryBarrierFunc)0xffff0fa0)();
93 #define LEVELDB_HAVE_MEMORY_BARRIER
96 #elif defined(ARCH_CPU_PPC_FAMILY) && defined(__GNUC__)
97 inline void MemoryBarrier() {
98 // TODO for some powerpc expert: is there a cheaper suitable variant?
99 // Perhaps by having separate barriers for acquire and release ops.
100 asm volatile("sync" : : : "memory");
102 #define LEVELDB_HAVE_MEMORY_BARRIER
106 // AtomicPointer built using platform-specific MemoryBarrier()
107 #if defined(LEVELDB_HAVE_MEMORY_BARRIER)
108 class AtomicPointer {
113 explicit AtomicPointer(void* p) : rep_(p) {}
114 inline void* NoBarrier_Load() const { return rep_; }
115 inline void NoBarrier_Store(void* v) { rep_ = v; }
116 inline void* Acquire_Load() const {
121 inline void Release_Store(void* v) {
127 // AtomicPointer based on <cstdatomic>
128 #elif defined(LEVELDB_ATOMIC_PRESENT)
129 class AtomicPointer {
131 std::atomic<void*> rep_;
134 explicit AtomicPointer(void* v) : rep_(v) { }
135 inline void* Acquire_Load() const {
136 return rep_.load(std::memory_order_acquire);
138 inline void Release_Store(void* v) {
139 rep_.store(v, std::memory_order_release);
141 inline void* NoBarrier_Load() const {
142 return rep_.load(std::memory_order_relaxed);
144 inline void NoBarrier_Store(void* v) {
145 rep_.store(v, std::memory_order_relaxed);
149 // Atomic pointer based on sparc memory barriers
150 #elif defined(__sparcv9) && defined(__GNUC__)
151 class AtomicPointer {
156 explicit AtomicPointer(void* v) : rep_(v) { }
157 inline void* Acquire_Load() const {
159 __asm__ __volatile__ (
160 "ldx [%[rep_]], %[val] \n\t"
161 "membar #LoadLoad|#LoadStore \n\t"
167 inline void Release_Store(void* v) {
168 __asm__ __volatile__ (
169 "membar #LoadStore|#StoreStore \n\t"
170 "stx %[v], [%[rep_]] \n\t"
172 : [rep_] "r" (&rep_), [v] "r" (v)
175 inline void* NoBarrier_Load() const { return rep_; }
176 inline void NoBarrier_Store(void* v) { rep_ = v; }
179 // Atomic pointer based on ia64 acq/rel
180 #elif defined(__ia64) && defined(__GNUC__)
181 class AtomicPointer {
186 explicit AtomicPointer(void* v) : rep_(v) { }
187 inline void* Acquire_Load() const {
189 __asm__ __volatile__ (
190 "ld8.acq %[val] = [%[rep_]] \n\t"
197 inline void Release_Store(void* v) {
198 __asm__ __volatile__ (
199 "st8.rel [%[rep_]] = %[v] \n\t"
201 : [rep_] "r" (&rep_), [v] "r" (v)
205 inline void* NoBarrier_Load() const { return rep_; }
206 inline void NoBarrier_Store(void* v) { rep_ = v; }
209 // We have neither MemoryBarrier(), nor <atomic>
211 #error Please implement AtomicPointer for this platform.
215 #undef LEVELDB_HAVE_MEMORY_BARRIER
216 #undef ARCH_CPU_X86_FAMILY
217 #undef ARCH_CPU_ARM_FAMILY
218 #undef ARCH_CPU_PPC_FAMILY
221 } // namespace leveldb
223 #endif // PORT_ATOMIC_POINTER_H_