diff options
Diffstat (limited to 'boost/container/detail/mutex.hpp')
-rw-r--r-- | boost/container/detail/mutex.hpp | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/boost/container/detail/mutex.hpp b/boost/container/detail/mutex.hpp new file mode 100644 index 0000000000..c53afa1f42 --- /dev/null +++ b/boost/container/detail/mutex.hpp @@ -0,0 +1,284 @@ +// Copyright (C) 2000 Stephen Cleary +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org for updates, documentation, and revision history. + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_MUTEX_HPP +#define BOOST_CONTAINER_MUTEX_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +//#define BOOST_CONTAINER_NO_MT +//#define BOOST_CONTAINER_NO_SPINLOCKS + +#include <boost/container/detail/config_begin.hpp> +#include <boost/container/detail/workaround.hpp> + +// Extremely Light-Weight wrapper classes for OS thread synchronization + +#define BOOST_MUTEX_HELPER_NONE 0 +#define BOOST_MUTEX_HELPER_WIN32 1 +#define BOOST_MUTEX_HELPER_PTHREAD 2 +#define BOOST_MUTEX_HELPER_SPINLOCKS 3 + +#if !defined(BOOST_HAS_THREADS) && !defined(BOOST_NO_MT) +# define BOOST_NO_MT +#endif + +#if defined(BOOST_NO_MT) || defined(BOOST_CONTAINER_NO_MT) + // No multithreading -> make locks into no-ops + #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_NONE +#else + //Taken from dlmalloc + #if !defined(BOOST_CONTAINER_NO_SPINLOCKS) && \ + ((defined(__GNUC__) && \ + ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) || \ + defined(__i386__) || defined(__x86_64__))) || \ + (defined(_MSC_VER) && _MSC_VER>=1310)) + #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_SPINLOCKS + #endif + + #if defined(BOOST_WINDOWS) + #include <windows.h> + #ifndef BOOST_MUTEX_HELPER + #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_WIN32 + #endif + #elif defined(BOOST_HAS_UNISTD_H) + #include <unistd.h> + #if !defined(BOOST_MUTEX_HELPER) && (defined(_POSIX_THREADS) || defined(BOOST_HAS_PTHREADS)) + #define BOOST_MUTEX_HELPER BOOST_MUTEX_HELPER_PTHREAD + #endif + #endif +#endif + +#ifndef BOOST_MUTEX_HELPER + #error Unable to determine platform mutex type; #define BOOST_NO_MT to assume single-threaded +#endif + +#if BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_NONE + //... +#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_SPINLOCKS + #if defined(_MSC_VER) + #ifndef _M_AMD64 + /* These are already defined on AMD64 builds */ + #ifdef __cplusplus + extern "C" { + #endif /* __cplusplus */ + long __cdecl _InterlockedCompareExchange(long volatile *Dest, long Exchange, long Comp); + long __cdecl _InterlockedExchange(long volatile *Target, long Value); + #ifdef __cplusplus + } + #endif /* __cplusplus */ + #endif /* _M_AMD64 */ + #pragma intrinsic (_InterlockedCompareExchange) + #pragma intrinsic (_InterlockedExchange) + #define interlockedcompareexchange _InterlockedCompareExchange + #define interlockedexchange _InterlockedExchange + #elif defined(WIN32) && defined(__GNUC__) + #define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b) + #define interlockedexchange __sync_lock_test_and_set + #endif /* Win32 */ + + /* First, define CAS_LOCK and CLEAR_LOCK on ints */ + /* Note CAS_LOCK defined to return 0 on success */ + + #if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) + #define BOOST_CONTAINER_CAS_LOCK(sl) __sync_lock_test_and_set(sl, 1) + #define BOOST_CONTAINER_CLEAR_LOCK(sl) __sync_lock_release(sl) + + #elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) + /* Custom spin locks for older gcc on x86 */ + static FORCEINLINE int boost_container_x86_cas_lock(int *sl) { + int ret; + int val = 1; + int cmp = 0; + __asm__ __volatile__ ("lock; cmpxchgl %1, %2" + : "=a" (ret) + : "r" (val), "m" (*(sl)), "0"(cmp) + : "memory", "cc"); + return ret; + } + + static FORCEINLINE void boost_container_x86_clear_lock(int* sl) { + assert(*sl != 0); + int prev = 0; + int ret; + __asm__ __volatile__ ("lock; xchgl %0, %1" + : "=r" (ret) + : "m" (*(sl)), "0"(prev) + : "memory"); + } + + #define BOOST_CONTAINER_CAS_LOCK(sl) boost_container_x86_cas_lock(sl) + #define BOOST_CONTAINER_CLEAR_LOCK(sl) boost_container_x86_clear_lock(sl) + + #else /* Win32 MSC */ + #define BOOST_CONTAINER_CAS_LOCK(sl) interlockedexchange((long volatile*)sl, (long)1) + #define BOOST_CONTAINER_CLEAR_LOCK(sl) interlockedexchange((long volatile*)sl, (long)0) + #endif + + /* How to yield for a spin lock */ + #define SPINS_PER_YIELD 63 + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #define SLEEP_EX_DURATION 50 /* delay for yield/sleep */ + #define SPIN_LOCK_YIELD SleepEx(SLEEP_EX_DURATION, FALSE) + #elif defined (__SVR4) && defined (__sun) /* solaris */ + #include <thread.h> + #define SPIN_LOCK_YIELD thr_yield(); + #elif !defined(LACKS_SCHED_H) + #include <sched.h> + #define SPIN_LOCK_YIELD sched_yield(); + #else + #define SPIN_LOCK_YIELD + #endif /* ... yield ... */ + + #define BOOST_CONTAINER_SPINS_PER_YIELD 63 + inline int boost_interprocess_spin_acquire_lock(int *sl) { + int spins = 0; + while (*(volatile int *)sl != 0 || + BOOST_CONTAINER_CAS_LOCK(sl)) { + if ((++spins & BOOST_CONTAINER_SPINS_PER_YIELD) == 0) { + SPIN_LOCK_YIELD; + } + } + return 0; + } + #define BOOST_CONTAINER_MLOCK_T int + #define BOOST_CONTAINER_TRY_LOCK(sl) !BOOST_CONTAINER_CAS_LOCK(sl) + #define BOOST_CONTAINER_RELEASE_LOCK(sl) BOOST_CONTAINER_CLEAR_LOCK(sl) + #define BOOST_CONTAINER_ACQUIRE_LOCK(sl) (BOOST_CONTAINER_CAS_LOCK(sl)? boost_interprocess_spin_acquire_lock(sl) : 0) + #define BOOST_CONTAINER_INITIAL_LOCK(sl) (*sl = 0) + #define BOOST_CONTAINER_DESTROY_LOCK(sl) (0) +#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_WIN32 + // +#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_PTHREAD + #include <pthread.h> +#endif + +namespace boost { +namespace container { +namespace container_detail { + +#if BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_NONE + class null_mutex + { + private: + null_mutex(const null_mutex &); + void operator=(const null_mutex &); + + public: + null_mutex() { } + + static void lock() { } + static void unlock() { } + }; + + typedef null_mutex default_mutex; +#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_SPINLOCKS + + class spin_mutex + { + private: + BOOST_CONTAINER_MLOCK_T sl; + spin_mutex(const spin_mutex &); + void operator=(const spin_mutex &); + + public: + spin_mutex() { BOOST_CONTAINER_INITIAL_LOCK(&sl); } + + void lock() { BOOST_CONTAINER_ACQUIRE_LOCK(&sl); } + void unlock() { BOOST_CONTAINER_RELEASE_LOCK(&sl); } + }; + typedef spin_mutex default_mutex; +#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_WIN32 + class mutex + { + private: + CRITICAL_SECTION mtx; + + mutex(const mutex &); + void operator=(const mutex &); + + public: + mutex() + { InitializeCriticalSection(&mtx); } + + ~mutex() + { DeleteCriticalSection(&mtx); } + + void lock() + { EnterCriticalSection(&mtx); } + + void unlock() + { LeaveCriticalSection(&mtx); } + }; + + typedef mutex default_mutex; +#elif BOOST_MUTEX_HELPER == BOOST_MUTEX_HELPER_PTHREAD + class mutex + { + private: + pthread_mutex_t mtx; + + mutex(const mutex &); + void operator=(const mutex &); + + public: + mutex() + { pthread_mutex_init(&mtx, 0); } + + ~mutex() + { pthread_mutex_destroy(&mtx); } + + void lock() + { pthread_mutex_lock(&mtx); } + + void unlock() + { pthread_mutex_unlock(&mtx); } + }; + + typedef mutex default_mutex; +#endif + +template<class Mutex> +class scoped_lock +{ + public: + scoped_lock(Mutex &m) + : m_(m) + { m_.lock(); } + ~scoped_lock() + { m_.unlock(); } + + private: + Mutex &m_; +}; + +} // namespace container_detail +} // namespace container +} // namespace boost + +#undef BOOST_MUTEX_HELPER_WIN32 +#undef BOOST_MUTEX_HELPER_PTHREAD +#undef BOOST_MUTEX_HELPER_NONE +#undef BOOST_MUTEX_HELPER +#undef BOOST_MUTEX_HELPER_SPINLOCKS + +#include <boost/container/detail/config_end.hpp> + +#endif |