1 /* 2 * Copyright Andrey Semashev 2007 - 2015. 3 * Distributed under the Boost Software License, Version 1.0. 4 * (See accompanying file LICENSE_1_0.txt or copy at 5 * http://www.boost.org/LICENSE_1_0.txt) 6 */ 7 /*! 8 * \file light_rw_mutex.cpp 9 * \author Andrey Semashev 10 * \date 19.06.2010 11 * 12 * \brief This header is the Boost.Log library implementation, see the library documentation 13 * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. 14 */ 15 16 #include <boost/log/detail/config.hpp> 17 #include <boost/log/detail/light_rw_mutex.hpp> 18 19 #if !defined(BOOST_LOG_NO_THREADS) 20 21 #if !defined(BOOST_LOG_LWRWMUTEX_USE_PTHREAD) && !defined(BOOST_LOG_LWRWMUTEX_USE_SRWLOCK) 22 23 #include <cstddef> 24 #include <new> 25 #include <boost/assert.hpp> 26 #include <boost/align/aligned_alloc.hpp> 27 #include <boost/thread/shared_mutex.hpp> 28 #include <boost/log/utility/once_block.hpp> 29 30 #include <boost/winapi/basic_types.hpp> 31 #include <boost/winapi/dll.hpp> 32 33 #include <boost/log/detail/header.hpp> 34 35 namespace boost { 36 37 BOOST_LOG_OPEN_NAMESPACE 38 39 namespace aux { 40 41 BOOST_LOG_ANONYMOUS_NAMESPACE { 42 43 struct BOOST_LOG_MAY_ALIAS mutex_impl { void* p; }; // has the same layout as SRWLOCK and light_rw_mutex::m_Mutex 44 45 typedef void (BOOST_WINAPI_WINAPI_CC *init_fun_t)(mutex_impl*); 46 typedef void (BOOST_WINAPI_WINAPI_CC *destroy_fun_t)(mutex_impl*); 47 typedef void (BOOST_WINAPI_WINAPI_CC *lock_exclusive_fun_t)(mutex_impl*); 48 typedef void (BOOST_WINAPI_WINAPI_CC *lock_shared_fun_t)(mutex_impl*); 49 typedef void (BOOST_WINAPI_WINAPI_CC *unlock_exclusive_fun_t)(mutex_impl*); 50 typedef void (BOOST_WINAPI_WINAPI_CC *unlock_shared_fun_t)(mutex_impl*); 51 52 //! A complement stub function for InitializeSRWLock 53 void BOOST_WINAPI_WINAPI_CC DeinitializeSRWLock(mutex_impl*) 54 { 55 } 56 57 // The Boost.Thread-based implementation 58 void BOOST_WINAPI_WINAPI_CC InitializeSharedMutex(mutex_impl* mtx) 59 { 60 // To avoid cache line aliasing we do aligned memory allocation here 61 enum 62 { 63 // Allocation size is the minimum number of cache lines to accommodate shared_mutex 64 size = 65 ( 66 (sizeof(shared_mutex) + BOOST_LOG_CPU_CACHE_LINE_SIZE - 1u) / BOOST_LOG_CPU_CACHE_LINE_SIZE 67 ) 68 * BOOST_LOG_CPU_CACHE_LINE_SIZE 69 }; 70 mtx->p = alignment::aligned_alloc(BOOST_LOG_CPU_CACHE_LINE_SIZE, size); 71 BOOST_ASSERT(mtx->p != NULL); 72 new (mtx->p) shared_mutex(); 73 } 74 75 void BOOST_WINAPI_WINAPI_CC DeinitializeSharedMutex(mutex_impl* mtx) 76 { 77 static_cast< shared_mutex* >(mtx->p)->~shared_mutex(); 78 alignment::aligned_free(mtx->p); 79 mtx->p = NULL; 80 } 81 82 void BOOST_WINAPI_WINAPI_CC ExclusiveLockSharedMutex(mutex_impl* mtx) 83 { 84 static_cast< shared_mutex* >(mtx->p)->lock(); 85 } 86 87 void BOOST_WINAPI_WINAPI_CC SharedLockSharedMutex(mutex_impl* mtx) 88 { 89 static_cast< shared_mutex* >(mtx->p)->lock_shared(); 90 } 91 92 void BOOST_WINAPI_WINAPI_CC ExclusiveUnlockSharedMutex(mutex_impl* mtx) 93 { 94 static_cast< shared_mutex* >(mtx->p)->unlock(); 95 } 96 97 void BOOST_WINAPI_WINAPI_CC SharedUnlockSharedMutex(mutex_impl* mtx) 98 { 99 static_cast< shared_mutex* >(mtx->p)->unlock_shared(); 100 } 101 102 // Pointers to the actual implementation functions 103 init_fun_t g_pInitializeLWRWMutex = NULL; 104 destroy_fun_t g_pDestroyLWRWMutex = NULL; 105 lock_exclusive_fun_t g_pLockExclusiveLWRWMutex = NULL; 106 lock_shared_fun_t g_pLockSharedLWRWMutex = NULL; 107 unlock_exclusive_fun_t g_pUnlockExclusiveLWRWMutex = NULL; 108 unlock_shared_fun_t g_pUnlockSharedLWRWMutex = NULL; 109 110 //! The function dynamically initializes the implementation pointers 111 void init_light_rw_mutex_impl() 112 { 113 boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll"); 114 if (hKernel32) 115 { 116 g_pInitializeLWRWMutex = 117 (init_fun_t)boost::winapi::get_proc_address(hKernel32, "InitializeSRWLock"); 118 if (g_pInitializeLWRWMutex) 119 { 120 g_pLockExclusiveLWRWMutex = 121 (lock_exclusive_fun_t)boost::winapi::get_proc_address(hKernel32, "AcquireSRWLockExclusive"); 122 if (g_pLockExclusiveLWRWMutex) 123 { 124 g_pUnlockExclusiveLWRWMutex = 125 (unlock_exclusive_fun_t)boost::winapi::get_proc_address(hKernel32, "ReleaseSRWLockExclusive"); 126 if (g_pUnlockExclusiveLWRWMutex) 127 { 128 g_pLockSharedLWRWMutex = 129 (lock_shared_fun_t)boost::winapi::get_proc_address(hKernel32, "AcquireSRWLockShared"); 130 if (g_pLockSharedLWRWMutex) 131 { 132 g_pUnlockSharedLWRWMutex = 133 (unlock_shared_fun_t)boost::winapi::get_proc_address(hKernel32, "ReleaseSRWLockShared"); 134 if (g_pUnlockSharedLWRWMutex) 135 { 136 g_pDestroyLWRWMutex = &DeinitializeSRWLock; 137 return; 138 } 139 } 140 } 141 } 142 } 143 } 144 145 // Current OS doesn't have support for SRWLOCK, use Boost.Thread instead 146 g_pInitializeLWRWMutex = &InitializeSharedMutex; 147 g_pDestroyLWRWMutex = &DeinitializeSharedMutex; 148 g_pLockExclusiveLWRWMutex = &ExclusiveLockSharedMutex; 149 g_pUnlockExclusiveLWRWMutex = &ExclusiveUnlockSharedMutex; 150 g_pLockSharedLWRWMutex = &SharedLockSharedMutex; 151 g_pUnlockSharedLWRWMutex = &SharedUnlockSharedMutex; 152 } 153 154 } // namespace 155 156 BOOST_LOG_API light_rw_mutex::light_rw_mutex() 157 { BOOST_LOG_ONCE_BLOCK()158 BOOST_LOG_ONCE_BLOCK() 159 { 160 init_light_rw_mutex_impl(); 161 } 162 g_pInitializeLWRWMutex((mutex_impl*)&m_Mutex); 163 } 164 ~light_rw_mutex()165BOOST_LOG_API light_rw_mutex::~light_rw_mutex() 166 { 167 g_pDestroyLWRWMutex((mutex_impl*)&m_Mutex); 168 } 169 lock_shared()170BOOST_LOG_API void light_rw_mutex::lock_shared() 171 { 172 g_pLockSharedLWRWMutex((mutex_impl*)&m_Mutex); 173 } 174 unlock_shared()175BOOST_LOG_API void light_rw_mutex::unlock_shared() 176 { 177 g_pUnlockSharedLWRWMutex((mutex_impl*)&m_Mutex); 178 } 179 lock()180BOOST_LOG_API void light_rw_mutex::lock() 181 { 182 g_pLockExclusiveLWRWMutex((mutex_impl*)&m_Mutex); 183 } 184 unlock()185BOOST_LOG_API void light_rw_mutex::unlock() 186 { 187 g_pUnlockExclusiveLWRWMutex((mutex_impl*)&m_Mutex); 188 } 189 190 } // namespace aux 191 192 BOOST_LOG_CLOSE_NAMESPACE // namespace log 193 194 } // namespace boost 195 196 #include <boost/log/detail/footer.hpp> 197 198 #endif // !defined(BOOST_LOG_LWRWMUTEX_USE_PTHREAD) && !defined(BOOST_LOG_LWRWMUTEX_USE_SRWLOCK) 199 200 #endif // !defined(BOOST_LOG_NO_THREADS) 201