Add Google's LevelDB support
[novacoin.git] / src / leveldb / port / atomic_pointer.h
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.
4
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 cstdatomic is present (on newer versions of gcc, it is), we use
9 //   a cstdatomic-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 <cstdatomic>
12 //   implementation.  Also, some <cstdatomic> implementations are much
13 //   slower than a memory-barrier based implementation (~16ns for
14 //   <cstdatomic> based acquire-load vs. ~1ns for a barrier based
15 //   acquire-load).
16 // This code is based on atomicops-internals-* in Google's perftools:
17 // http://code.google.com/p/google-perftools/source/browse/#svn%2Ftrunk%2Fsrc%2Fbase
18
19 #ifndef PORT_ATOMIC_POINTER_H_
20 #define PORT_ATOMIC_POINTER_H_
21
22 #include <stdint.h>
23 #ifdef LEVELDB_CSTDATOMIC_PRESENT
24 #include <cstdatomic>
25 #endif
26 #ifdef OS_WIN
27 #include <windows.h>
28 #endif
29 #ifdef OS_MACOSX
30 #include <libkern/OSAtomic.h>
31 #endif
32
33 #if defined(_M_X64) || defined(__x86_64__)
34 #define ARCH_CPU_X86_FAMILY 1
35 #elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
36 #define ARCH_CPU_X86_FAMILY 1
37 #elif defined(__ARMEL__)
38 #define ARCH_CPU_ARM_FAMILY 1
39 #elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__)
40 #define ARCH_CPU_PPC_FAMILY 1
41 #endif
42
43 namespace leveldb {
44 namespace port {
45
46 // Define MemoryBarrier() if available
47 // Windows on x86
48 #if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY)
49 // windows.h already provides a MemoryBarrier(void) macro
50 // http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx
51 #define LEVELDB_HAVE_MEMORY_BARRIER
52
53 // Gcc on x86
54 #elif defined(ARCH_CPU_X86_FAMILY) && defined(__GNUC__)
55 inline void MemoryBarrier() {
56   // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on
57   // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering.
58   __asm__ __volatile__("" : : : "memory");
59 }
60 #define LEVELDB_HAVE_MEMORY_BARRIER
61
62 // Sun Studio
63 #elif defined(ARCH_CPU_X86_FAMILY) && defined(__SUNPRO_CC)
64 inline void MemoryBarrier() {
65   // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on
66   // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering.
67   asm volatile("" : : : "memory");
68 }
69 #define LEVELDB_HAVE_MEMORY_BARRIER
70
71 // Mac OS
72 #elif defined(OS_MACOSX)
73 inline void MemoryBarrier() {
74   OSMemoryBarrier();
75 }
76 #define LEVELDB_HAVE_MEMORY_BARRIER
77
78 // ARM Linux
79 #elif defined(ARCH_CPU_ARM_FAMILY) && defined(__linux__)
80 typedef void (*LinuxKernelMemoryBarrierFunc)(void);
81 // The Linux ARM kernel provides a highly optimized device-specific memory
82 // barrier function at a fixed memory address that is mapped in every
83 // user-level process.
84 //
85 // This beats using CPU-specific instructions which are, on single-core
86 // devices, un-necessary and very costly (e.g. ARMv7-A "dmb" takes more
87 // than 180ns on a Cortex-A8 like the one on a Nexus One). Benchmarking
88 // shows that the extra function call cost is completely negligible on
89 // multi-core devices.
90 //
91 inline void MemoryBarrier() {
92   (*(LinuxKernelMemoryBarrierFunc)0xffff0fa0)();
93 }
94 #define LEVELDB_HAVE_MEMORY_BARRIER
95
96 // PPC
97 #elif defined(ARCH_CPU_PPC_FAMILY) && defined(__GNUC__)
98 inline void MemoryBarrier() {
99   // TODO for some powerpc expert: is there a cheaper suitable variant?
100   // Perhaps by having separate barriers for acquire and release ops.
101   asm volatile("sync" : : : "memory");
102 }
103 #define LEVELDB_HAVE_MEMORY_BARRIER
104
105 #endif
106
107 // AtomicPointer built using platform-specific MemoryBarrier()
108 #if defined(LEVELDB_HAVE_MEMORY_BARRIER)
109 class AtomicPointer {
110  private:
111   void* rep_;
112  public:
113   AtomicPointer() { }
114   explicit AtomicPointer(void* p) : rep_(p) {}
115   inline void* NoBarrier_Load() const { return rep_; }
116   inline void NoBarrier_Store(void* v) { rep_ = v; }
117   inline void* Acquire_Load() const {
118     void* result = rep_;
119     MemoryBarrier();
120     return result;
121   }
122   inline void Release_Store(void* v) {
123     MemoryBarrier();
124     rep_ = v;
125   }
126 };
127
128 // AtomicPointer based on <cstdatomic>
129 #elif defined(LEVELDB_CSTDATOMIC_PRESENT)
130 class AtomicPointer {
131  private:
132   std::atomic<void*> rep_;
133  public:
134   AtomicPointer() { }
135   explicit AtomicPointer(void* v) : rep_(v) { }
136   inline void* Acquire_Load() const {
137     return rep_.load(std::memory_order_acquire);
138   }
139   inline void Release_Store(void* v) {
140     rep_.store(v, std::memory_order_release);
141   }
142   inline void* NoBarrier_Load() const {
143     return rep_.load(std::memory_order_relaxed);
144   }
145   inline void NoBarrier_Store(void* v) {
146     rep_.store(v, std::memory_order_relaxed);
147   }
148 };
149
150 // Atomic pointer based on sparc memory barriers
151 #elif defined(__sparcv9) && defined(__GNUC__)
152 class AtomicPointer {
153  private:
154   void* rep_;
155  public:
156   AtomicPointer() { }
157   explicit AtomicPointer(void* v) : rep_(v) { }
158   inline void* Acquire_Load() const {
159     void* val;
160     __asm__ __volatile__ (
161         "ldx [%[rep_]], %[val] \n\t"
162          "membar #LoadLoad|#LoadStore \n\t"
163         : [val] "=r" (val)
164         : [rep_] "r" (&rep_)
165         : "memory");
166     return val;
167   }
168   inline void Release_Store(void* v) {
169     __asm__ __volatile__ (
170         "membar #LoadStore|#StoreStore \n\t"
171         "stx %[v], [%[rep_]] \n\t"
172         :
173         : [rep_] "r" (&rep_), [v] "r" (v)
174         : "memory");
175   }
176   inline void* NoBarrier_Load() const { return rep_; }
177   inline void NoBarrier_Store(void* v) { rep_ = v; }
178 };
179
180 // Atomic pointer based on ia64 acq/rel
181 #elif defined(__ia64) && defined(__GNUC__)
182 class AtomicPointer {
183  private:
184   void* rep_;
185  public:
186   AtomicPointer() { }
187   explicit AtomicPointer(void* v) : rep_(v) { }
188   inline void* Acquire_Load() const {
189     void* val    ;
190     __asm__ __volatile__ (
191         "ld8.acq %[val] = [%[rep_]] \n\t"
192         : [val] "=r" (val)
193         : [rep_] "r" (&rep_)
194         : "memory"
195         );
196     return val;
197   }
198   inline void Release_Store(void* v) {
199     __asm__ __volatile__ (
200         "st8.rel [%[rep_]] = %[v]  \n\t"
201         :
202         : [rep_] "r" (&rep_), [v] "r" (v)
203         : "memory"
204         );
205   }
206   inline void* NoBarrier_Load() const { return rep_; }
207   inline void NoBarrier_Store(void* v) { rep_ = v; }
208 };
209
210 // We have neither MemoryBarrier(), nor <cstdatomic>
211 #else
212 #error Please implement AtomicPointer for this platform.
213
214 #endif
215
216 #undef LEVELDB_HAVE_MEMORY_BARRIER
217 #undef ARCH_CPU_X86_FAMILY
218 #undef ARCH_CPU_ARM_FAMILY
219 #undef ARCH_CPU_PPC_FAMILY
220
221 }  // namespace port
222 }  // namespace leveldb
223
224 #endif  // PORT_ATOMIC_POINTER_H_