作者: 韩晨旭 10225101440 李畅 10225102463
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 rivejä
4.7 KiB

  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. // AtomicPointer provides storage for a lock-free pointer.
  5. // Platform-dependent implementation of AtomicPointer:
  6. // - If the platform provides a cheap barrier, we use it with raw pointers
  7. // - If cstdatomic is present (on newer versions of gcc, it is), we use
  8. // a cstdatomic-based AtomicPointer. However we prefer the memory
  9. // barrier based version, because at least on a gcc 4.4 32-bit build
  10. // on linux, we have encountered a buggy <cstdatomic>
  11. // implementation. Also, some <cstdatomic> implementations are much
  12. // slower than a memory-barrier based implementation (~16ns for
  13. // <cstdatomic> based acquire-load vs. ~1ns for a barrier based
  14. // 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. #ifndef PORT_ATOMIC_POINTER_H_
  18. #define PORT_ATOMIC_POINTER_H_
  19. #include <stdint.h>
  20. #ifdef LEVELDB_CSTDATOMIC_PRESENT
  21. #include <cstdatomic>
  22. #endif
  23. #ifdef OS_WIN
  24. #include <windows.h>
  25. #endif
  26. #ifdef OS_MACOSX
  27. #include <libkern/OSAtomic.h>
  28. #endif
  29. #if defined(_M_X64) || defined(__x86_64__)
  30. #define ARCH_CPU_X86_FAMILY 1
  31. #elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
  32. #define ARCH_CPU_X86_FAMILY 1
  33. #elif defined(__ARMEL__)
  34. #define ARCH_CPU_ARM_FAMILY 1
  35. #endif
  36. namespace leveldb {
  37. namespace port {
  38. // Define MemoryBarrier() if available
  39. // Windows on x86
  40. #if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY)
  41. // windows.h already provides a MemoryBarrier(void) macro
  42. // http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx
  43. #define LEVELDB_HAVE_MEMORY_BARRIER
  44. // Gcc on x86
  45. #elif defined(ARCH_CPU_X86_FAMILY) && defined(__GNUC__)
  46. inline void MemoryBarrier() {
  47. // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on
  48. // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering.
  49. __asm__ __volatile__("" : : : "memory");
  50. }
  51. #define LEVELDB_HAVE_MEMORY_BARRIER
  52. // Sun Studio
  53. #elif defined(ARCH_CPU_X86_FAMILY) && defined(__SUNPRO_CC)
  54. inline void MemoryBarrier() {
  55. // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on
  56. // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering.
  57. asm volatile("" : : : "memory");
  58. }
  59. #define LEVELDB_HAVE_MEMORY_BARRIER
  60. // Mac OS
  61. #elif defined(OS_MACOSX)
  62. inline void MemoryBarrier() {
  63. OSMemoryBarrier();
  64. }
  65. #define LEVELDB_HAVE_MEMORY_BARRIER
  66. // ARM Linux
  67. #elif defined(ARCH_CPU_ARM_FAMILY) && defined(__linux__)
  68. typedef void (*LinuxKernelMemoryBarrierFunc)(void);
  69. // The Linux ARM kernel provides a highly optimized device-specific memory
  70. // barrier function at a fixed memory address that is mapped in every
  71. // user-level process.
  72. //
  73. // This beats using CPU-specific instructions which are, on single-core
  74. // devices, un-necessary and very costly (e.g. ARMv7-A "dmb" takes more
  75. // than 180ns on a Cortex-A8 like the one on a Nexus One). Benchmarking
  76. // shows that the extra function call cost is completely negligible on
  77. // multi-core devices.
  78. //
  79. inline void MemoryBarrier() {
  80. (*(LinuxKernelMemoryBarrierFunc)0xffff0fa0)();
  81. }
  82. #define LEVELDB_HAVE_MEMORY_BARRIER
  83. #endif
  84. // AtomicPointer built using platform-specific MemoryBarrier()
  85. #if defined(LEVELDB_HAVE_MEMORY_BARRIER)
  86. class AtomicPointer {
  87. private:
  88. void* rep_;
  89. public:
  90. AtomicPointer() { }
  91. explicit AtomicPointer(void* p) : rep_(p) {}
  92. inline void* NoBarrier_Load() const { return rep_; }
  93. inline void NoBarrier_Store(void* v) { rep_ = v; }
  94. inline void* Acquire_Load() const {
  95. void* result = rep_;
  96. MemoryBarrier();
  97. return result;
  98. }
  99. inline void Release_Store(void* v) {
  100. MemoryBarrier();
  101. rep_ = v;
  102. }
  103. };
  104. // AtomicPointer based on <cstdatomic>
  105. #elif defined(LEVELDB_CSTDATOMIC_PRESENT)
  106. class AtomicPointer {
  107. private:
  108. std::atomic<void*> rep_;
  109. public:
  110. AtomicPointer() { }
  111. explicit AtomicPointer(void* v) : rep_(v) { }
  112. inline void* Acquire_Load() const {
  113. return rep_.load(std::memory_order_acquire);
  114. }
  115. inline void Release_Store(void* v) {
  116. rep_.store(v, std::memory_order_release);
  117. }
  118. inline void* NoBarrier_Load() const {
  119. return rep_.load(std::memory_order_relaxed);
  120. }
  121. inline void NoBarrier_Store(void* v) {
  122. rep_.store(v, std::memory_order_relaxed);
  123. }
  124. };
  125. // We have neither MemoryBarrier(), nor <cstdatomic>
  126. #else
  127. #error Please implement AtomicPointer for this platform.
  128. #endif
  129. #undef LEVELDB_HAVE_MEMORY_BARRIER
  130. #undef ARCH_CPU_X86_FAMILY
  131. #undef ARCH_CPU_ARM_FAMILY
  132. } // namespace port
  133. } // namespace leveldb
  134. #endif // PORT_ATOMIC_POINTER_H_