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()165 BOOST_LOG_API light_rw_mutex::~light_rw_mutex()
166 {
167     g_pDestroyLWRWMutex((mutex_impl*)&m_Mutex);
168 }
169 
lock_shared()170 BOOST_LOG_API void light_rw_mutex::lock_shared()
171 {
172     g_pLockSharedLWRWMutex((mutex_impl*)&m_Mutex);
173 }
174 
unlock_shared()175 BOOST_LOG_API void light_rw_mutex::unlock_shared()
176 {
177     g_pUnlockSharedLWRWMutex((mutex_impl*)&m_Mutex);
178 }
179 
lock()180 BOOST_LOG_API void light_rw_mutex::lock()
181 {
182     g_pLockExclusiveLWRWMutex((mutex_impl*)&m_Mutex);
183 }
184 
unlock()185 BOOST_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