@ -4,57 +4,31 @@
// AtomicPointer provides storage for a lock-free pointer.
// AtomicPointer provides storage for a lock-free pointer.
// Platform-dependent implementation of AtomicPointer:
// Platform-dependent implementation of AtomicPointer:
// - If the platform provides a cheap barrier, we use it with raw pointers
// - If cstdatomic is present (on newer versions of gcc, it is), we use
// - If cstdatomic is present (on newer versions of gcc, it is), we use
// a cstdatomic-based AtomicPointer
// a cstdatomic-based AtomicPointer. However we prefer the memory
// - If it is not, we define processor-dependent AtomicWord operations,
// barrier based version, because at least on a gcc 4.4 32-bit build
// and then use them to build AtomicPointer
// on linux, we have encountered a buggy <cstdatomic>
//
// implementation. Also, some <cstdatomic> implementations are much
// slower than a memory-barrier based implementation (~16ns for
// <cstdatomic> based acquire-load vs. ~1ns for a barrier based
// acquire-load).
// This code is based on atomicops-internals-* in Google's perftools:
// This code is based on atomicops-internals-* in Google's perftools:
// http://code.google.com/p/google-perftools/source/browse/#svn%2Ftrunk%2Fsrc%2Fbase
// http://code.google.com/p/google-perftools/source/browse/#svn%2Ftrunk%2Fsrc%2Fbase
# ifndef PORT_ATOMIC_POINTER_H_
# ifndef PORT_ATOMIC_POINTER_H_
# define PORT_ATOMIC_POINTER_H_
# define PORT_ATOMIC_POINTER_H_
# include <stdint.h>
# ifdef LEVELDB_CSTDATOMIC_PRESENT
# ifdef LEVELDB_CSTDATOMIC_PRESENT
///////////////////////////////////////////////////////////////////////////////
// WE HAVE <cstdatomic>
// Use a <cstdatomic>-based AtomicPointer
# include <cstdatomic>
# include <cstdatomic>
# include <stdint.h>
# endif
# ifdef OS_WIN
namespace leveldb {
# include <windows.h>
namespace port {
# endif
# ifdef OS_MACOSX
// Storage for a lock-free pointer
# include <libkern/OSAtomic.h>
class AtomicPointer {
# endif
private :
std : : atomic < void * > rep_ ;
public :
AtomicPointer ( ) { }
explicit AtomicPointer ( void * v ) : rep_ ( v ) { }
inline void * Acquire_Load ( ) const {
return rep_ . load ( std : : memory_order_acquire ) ;
}
inline void Release_Store ( void * v ) {
rep_ . store ( v , std : : memory_order_release ) ;
}
inline void * NoBarrier_Load ( ) const {
return rep_ . load ( std : : memory_order_relaxed ) ;
}
inline void NoBarrier_Store ( void * v ) {
rep_ . store ( v , std : : memory_order_relaxed ) ;
}
} ;
} // namespace leveldb::port
} // namespace leveldb
# else
///////////////////////////////////////////////////////////////////////////////
// NO <cstdatomic>
// The entire rest of this file covers that case
# if defined(_M_X64) || defined(__x86_64__)
# if defined(_M_X64) || defined(__x86_64__)
# define ARCH_CPU_X86_FAMILY 1
# define ARCH_CPU_X86_FAMILY 1
@ -62,152 +36,100 @@ class AtomicPointer {
# define ARCH_CPU_X86_FAMILY 1
# define ARCH_CPU_X86_FAMILY 1
# elif defined(__ARMEL__)
# elif defined(__ARMEL__)
# define ARCH_CPU_ARM_FAMILY 1
# define ARCH_CPU_ARM_FAMILY 1
# else
# warning Please add support for your architecture in atomicpointer.h
# endif
# endif
namespace leveldb {
namespace leveldb {
namespace port {
namespace port {
namespace internal {
// AtomicWord is a machine-sized pointer.
typedef intptr_t AtomicWord ;
} // namespace leveldb::port::internal
} // namespace leveldb::port
} // namespace leveldb
// Include our platform specific implementation.
// Define MemoryBarrier() if available
///////////////////////////////////////////////////////////////////////////////
// Windows on x86
// Windows on x86
# if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY)
# if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY)
// windows.h already provides a MemoryBarrier(void) macro
// void MemoryBarrier(void) macro is defined in windows.h:
// http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx
// http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx
// Including windows.h here; MemoryBarrier() gets used below.
# define LEVELDB_HAVE_MEMORY_BARRIER
# include <windows.h>
///////////////////////////////////////////////////////////////////////////////
// Mac OS on x86
# elif defined(OS_MACOSX) && defined(ARCH_CPU_X86_FAMILY)
# include <libkern/OSAtomic.h>
namespace leveldb {
namespace port {
namespace internal {
// Gcc on x86
# elif defined(__GNUC__) && defined(ARCH_CPU_X86_FAMILY)
inline void MemoryBarrier ( ) {
inline void MemoryBarrier ( ) {
# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
// See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on
// See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on
// this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering.
// this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering.
__asm__ __volatile__ ( " " : : : " memory " ) ;
__asm__ __volatile__ ( " " : : : " memory " ) ;
# else
OSMemoryBarrier ( ) ;
# endif
}
}
# define LEVELDB_HAVE_MEMORY_BARRIER
} // namespace leveldb::port::internal
// Mac OS
} // namespace leveldb::port
# elif defined(OS_MACOSX)
} // namespace leveldb
///////////////////////////////////////////////////////////////////////////////
// Any x86 CPU
# elif defined(ARCH_CPU_X86_FAMILY)
namespace leveldb {
namespace port {
namespace internal {
inline void MemoryBarrier ( ) {
inline void MemoryBarrier ( ) {
__asm__ __volatile__ ( " " : : : " memory " ) ;
OSMemoryBarrier ( ) ;
}
}
# define LEVELDB_HAVE_MEMORY_BARRIER
} // namespace leveldb::port::internal
} // namespace leveldb::port
} // namespace leveldb
# undef ATOMICOPS_COMPILER_BARRIER
///////////////////////////////////////////////////////////////////////////////
// ARM
// ARM
# elif defined(ARCH_CPU_ARM_FAMILY)
# elif defined(ARCH_CPU_ARM_FAMILY)
namespace leveldb {
namespace port {
namespace internal {
typedef void ( * LinuxKernelMemoryBarrierFunc ) ( void ) ;
typedef void ( * LinuxKernelMemoryBarrierFunc ) ( void ) ;
LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__ ( ( weak ) ) =
LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__ ( ( weak ) ) =
( LinuxKernelMemoryBarrierFunc ) 0xffff0fa0 ;
( LinuxKernelMemoryBarrierFunc ) 0xffff0fa0 ;
inline void MemoryBarrier ( ) {
inline void MemoryBarrier ( ) {
pLinuxKernelMemoryBarrier ( ) ;
pLinuxKernelMemoryBarrier ( ) ;
}
}
# define LEVELDB_HAVE_MEMORY_BARRIER
} // namespace leveldb::port::internal
} // namespace leveldb::port
} // namespace leveldb
# else
# error "Atomic operations are not supported on your platform"
# endif
# endif
///////////////////////////////////////////////////////////////////////////////
// AtomicPointer built using platform-specific MemoryBarrier()
// Implementation of AtomicPointer based on MemoryBarriers above
# if defined(LEVELDB_HAVE_MEMORY_BARRIER)
class AtomicPointer {
namespace leveldb {
private :
namespace port {
void * rep_ ;
namespace internal {
public :
AtomicPointer ( ) { }
// Atomic operations using per-system MemoryBarrier()s
explicit AtomicPointer ( void * p ) : rep_ ( p ) { }
inline void * NoBarrier_Load ( ) const { return rep_ ; }
inline AtomicWord Acquire_Load ( volatile const AtomicWord * ptr ) {
inline void NoBarrier_Store ( void * v ) { rep_ = v ; }
AtomicWord value = * ptr ;
inline void * Acquire_Load ( ) const {
void * result = rep_ ;
MemoryBarrier ( ) ;
MemoryBarrier ( ) ;
return value ;
return result ;
}
}
inline void Release_Store ( void * v ) {
inline void Release_Store ( volatile AtomicWord * ptr , AtomicWord value ) {
MemoryBarrier ( ) ;
MemoryBarrier ( ) ;
* ptr = value ;
rep_ = v ;
}
inline AtomicWord NoBarrier_Load ( volatile const AtomicWord * ptr ) {
return * ptr ;
}
}
} ;
inline void NoBarrier_Store ( volatile AtomicWord * ptr , AtomicWord value ) {
// AtomicPointer based on <cstdatomic>
* ptr = value ;
# elif defined(LEVELDB_CSTDATOMIC_PRESENT)
}
} // namespace leveldb::port::internal
// AtomicPointer definition for systems without <cstdatomic>.
class AtomicPointer {
class AtomicPointer {
private :
private :
typedef internal : : AtomicWord Rep ;
std : : atomic < void * > rep_ ;
Rep rep_ ;
public :
public :
AtomicPointer ( ) { }
AtomicPointer ( ) { }
explicit AtomicPointer ( void * p ) : rep_ ( reinterpret_cast < Rep > ( p ) ) { }
explicit AtomicPointer ( void * v ) : rep_ ( v ) { }
inline void * Acquire_Load ( ) const {
inline void * Acquire_Load ( ) const {
return reinterpret_cast < void * > ( internal : : Acquire_Load ( & rep_ ) ) ;
return rep_ . load ( std : : memory_order_acquire ) ;
}
}
inline void Release_Store ( void * v ) {
inline void Release_Store ( void * v ) {
internal : : Release_Store ( & rep_ , reinterpret_cast < Rep > ( v ) ) ;
rep_ . store ( v , std : : memory_order_release ) ;
}
}
inline void * NoBarrier_Load ( ) const {
inline void * NoBarrier_Load ( ) const {
return reinterpret_cast < void * > ( internal : : NoBarrier_Load ( & rep_ ) ) ;
return rep_ . load ( std : : memory_order_relaxed ) ;
}
}
inline void NoBarrier_Store ( void * v ) {
inline void NoBarrier_Store ( void * v ) {
internal : : NoBarrier_Store ( & rep_ , reinterpret_cast < Rep > ( v ) ) ;
rep_ . store ( v , std : : memory_order_relaxed ) ;
}
}
} ;
} ;
// We have neither MemoryBarrier(), nor <cstdatomic>
# else
# error Please implement AtomicPointer for this platform.
# endif
# undef LEVELDB_HAVE_MEMORY_BARRIER
# undef ARCH_CPU_X86_FAMILY
# undef ARCH_CPU_ARM_FAMILY
} // namespace leveldb::port
} // namespace leveldb::port
} // namespace leveldb
} // namespace leveldb
# endif // LEVELDB_CSTDATOMIC_PRESENT
# endif // PORT_ATOMIC_POINTER_H_
# endif // PORT_ATOMIC_POINTER_H_