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