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