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)
9 * \author Andrey Semashev
12 * \brief This file 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.
15 * The code in this file is based on the \c call_once function implementation in Boost.Thread.
18 #include <boost/log/detail/config.hpp>
19 #include <boost/log/utility/once_block.hpp>
20 #ifndef BOOST_LOG_NO_THREADS
23 #include <boost/assert.hpp>
25 #if defined(BOOST_THREAD_PLATFORM_WIN32)
27 #include <boost/winapi/wait.hpp> // INFINITE
29 #if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
31 #include <boost/winapi/srw_lock.hpp>
32 #include <boost/winapi/condition_variable.hpp>
33 #include <boost/log/detail/header.hpp>
37 BOOST_LOG_OPEN_NAMESPACE
41 BOOST_LOG_ANONYMOUS_NAMESPACE
{
43 boost::winapi::SRWLOCK_ g_OnceBlockMutex
= BOOST_WINAPI_SRWLOCK_INIT
;
44 boost::winapi::CONDITION_VARIABLE_ g_OnceBlockCond
= BOOST_WINAPI_CONDITION_VARIABLE_INIT
;
48 BOOST_LOG_API
bool once_block_sentry::enter_once_block() const BOOST_NOEXCEPT
50 boost::winapi::AcquireSRWLockExclusive(&g_OnceBlockMutex
);
52 once_block_flag
volatile& flag
= m_flag
;
53 while (flag
.status
!= once_block_flag::initialized
)
55 if (flag
.status
== once_block_flag::uninitialized
)
57 flag
.status
= once_block_flag::being_initialized
;
58 boost::winapi::ReleaseSRWLockExclusive(&g_OnceBlockMutex
);
60 // Invoke the initializer block
65 while (flag
.status
== once_block_flag::being_initialized
)
67 BOOST_VERIFY(boost::winapi::SleepConditionVariableSRW(
68 &g_OnceBlockCond
, &g_OnceBlockMutex
, boost::winapi::INFINITE_
, 0));
73 boost::winapi::ReleaseSRWLockExclusive(&g_OnceBlockMutex
);
78 BOOST_LOG_API
void once_block_sentry::commit() BOOST_NOEXCEPT
80 boost::winapi::AcquireSRWLockExclusive(&g_OnceBlockMutex
);
82 // The initializer executed successfully
83 m_flag
.status
= once_block_flag::initialized
;
85 boost::winapi::ReleaseSRWLockExclusive(&g_OnceBlockMutex
);
86 boost::winapi::WakeAllConditionVariable(&g_OnceBlockCond
);
89 BOOST_LOG_API
void once_block_sentry::rollback() BOOST_NOEXCEPT
91 boost::winapi::AcquireSRWLockExclusive(&g_OnceBlockMutex
);
93 // The initializer failed, marking the flag as if it hasn't run at all
94 m_flag
.status
= once_block_flag::uninitialized
;
96 boost::winapi::ReleaseSRWLockExclusive(&g_OnceBlockMutex
);
97 boost::winapi::WakeAllConditionVariable(&g_OnceBlockCond
);
102 BOOST_LOG_CLOSE_NAMESPACE
// namespace log
106 #include <boost/log/detail/footer.hpp>
108 #else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
110 #include <cstdlib> // atexit
111 #include <boost/detail/interlocked.hpp>
112 #include <boost/winapi/basic_types.hpp>
113 #include <boost/winapi/dll.hpp>
114 #include <boost/thread/mutex.hpp>
115 #include <boost/thread/locks.hpp>
116 #include <boost/thread/condition_variable.hpp>
117 #include <boost/log/detail/header.hpp>
121 BOOST_LOG_OPEN_NAMESPACE
125 BOOST_LOG_ANONYMOUS_NAMESPACE
{
127 struct BOOST_LOG_NO_VTABLE once_block_impl_base
129 virtual ~once_block_impl_base() {}
130 virtual bool enter_once_block(once_block_flag
volatile& flag
) = 0;
131 virtual void commit(once_block_flag
& flag
) = 0;
132 virtual void rollback(once_block_flag
& flag
) = 0;
135 class once_block_impl_nt6
:
136 public once_block_impl_base
139 struct winapi_srwlock
{ void* p
; };
140 struct winapi_condition_variable
{ void* p
; };
142 typedef void (BOOST_WINAPI_WINAPI_CC
*InitializeSRWLock_t
)(winapi_srwlock
*);
143 typedef void (BOOST_WINAPI_WINAPI_CC
*AcquireSRWLockExclusive_t
)(winapi_srwlock
*);
144 typedef void (BOOST_WINAPI_WINAPI_CC
*ReleaseSRWLockExclusive_t
)(winapi_srwlock
*);
145 typedef void (BOOST_WINAPI_WINAPI_CC
*InitializeConditionVariable_t
)(winapi_condition_variable
*);
146 typedef boost::winapi::BOOL_ (BOOST_WINAPI_WINAPI_CC
*SleepConditionVariableSRW_t
)(winapi_condition_variable
*, winapi_srwlock
*, boost::winapi::DWORD_
, boost::winapi::ULONG_
);
147 typedef void (BOOST_WINAPI_WINAPI_CC
*WakeAllConditionVariable_t
)(winapi_condition_variable
*);
150 winapi_srwlock m_Mutex
;
151 winapi_condition_variable m_Cond
;
153 AcquireSRWLockExclusive_t m_pAcquireSRWLockExclusive
;
154 ReleaseSRWLockExclusive_t m_pReleaseSRWLockExclusive
;
155 SleepConditionVariableSRW_t m_pSleepConditionVariableSRW
;
156 WakeAllConditionVariable_t m_pWakeAllConditionVariable
;
160 InitializeSRWLock_t pInitializeSRWLock
,
161 AcquireSRWLockExclusive_t pAcquireSRWLockExclusive
,
162 ReleaseSRWLockExclusive_t pReleaseSRWLockExclusive
,
163 InitializeConditionVariable_t pInitializeConditionVariable
,
164 SleepConditionVariableSRW_t pSleepConditionVariableSRW
,
165 WakeAllConditionVariable_t pWakeAllConditionVariable
167 m_pAcquireSRWLockExclusive(pAcquireSRWLockExclusive
),
168 m_pReleaseSRWLockExclusive(pReleaseSRWLockExclusive
),
169 m_pSleepConditionVariableSRW(pSleepConditionVariableSRW
),
170 m_pWakeAllConditionVariable(pWakeAllConditionVariable
)
172 pInitializeSRWLock(&m_Mutex
);
173 pInitializeConditionVariable(&m_Cond
);
176 bool enter_once_block(once_block_flag
volatile& flag
)
178 m_pAcquireSRWLockExclusive(&m_Mutex
);
180 while (flag
.status
!= once_block_flag::initialized
)
182 if (flag
.status
== once_block_flag::uninitialized
)
184 flag
.status
= once_block_flag::being_initialized
;
185 m_pReleaseSRWLockExclusive(&m_Mutex
);
187 // Invoke the initializer block
192 while (flag
.status
== once_block_flag::being_initialized
)
194 BOOST_VERIFY(m_pSleepConditionVariableSRW(
195 &m_Cond
, &m_Mutex
, boost::winapi::INFINITE_
, 0));
200 m_pReleaseSRWLockExclusive(&m_Mutex
);
205 void commit(once_block_flag
& flag
)
207 m_pAcquireSRWLockExclusive(&m_Mutex
);
209 // The initializer executed successfully
210 flag
.status
= once_block_flag::initialized
;
212 m_pReleaseSRWLockExclusive(&m_Mutex
);
213 m_pWakeAllConditionVariable(&m_Cond
);
216 void rollback(once_block_flag
& flag
)
218 m_pAcquireSRWLockExclusive(&m_Mutex
);
220 // The initializer failed, marking the flag as if it hasn't run at all
221 flag
.status
= once_block_flag::uninitialized
;
223 m_pReleaseSRWLockExclusive(&m_Mutex
);
224 m_pWakeAllConditionVariable(&m_Cond
);
228 class once_block_impl_nt5
:
229 public once_block_impl_base
233 condition_variable m_Cond
;
236 bool enter_once_block(once_block_flag
volatile& flag
)
238 unique_lock
< mutex
> lock(m_Mutex
);
240 while (flag
.status
!= once_block_flag::initialized
)
242 if (flag
.status
== once_block_flag::uninitialized
)
244 flag
.status
= once_block_flag::being_initialized
;
246 // Invoke the initializer block
251 while (flag
.status
== once_block_flag::being_initialized
)
261 void commit(once_block_flag
& flag
)
264 lock_guard
< mutex
> lock(m_Mutex
);
265 flag
.status
= once_block_flag::initialized
;
270 void rollback(once_block_flag
& flag
)
273 lock_guard
< mutex
> lock(m_Mutex
);
274 flag
.status
= once_block_flag::uninitialized
;
280 once_block_impl_base
* create_once_block_impl()
282 boost::winapi::HMODULE_ hKernel32
= boost::winapi::GetModuleHandleW(L
"kernel32.dll");
285 once_block_impl_nt6::InitializeSRWLock_t pInitializeSRWLock
=
286 (once_block_impl_nt6::InitializeSRWLock_t
)boost::winapi::get_proc_address(hKernel32
, "InitializeSRWLock");
287 if (pInitializeSRWLock
)
289 once_block_impl_nt6::AcquireSRWLockExclusive_t pAcquireSRWLockExclusive
=
290 (once_block_impl_nt6::AcquireSRWLockExclusive_t
)boost::winapi::get_proc_address(hKernel32
, "AcquireSRWLockExclusive");
291 if (pAcquireSRWLockExclusive
)
293 once_block_impl_nt6::ReleaseSRWLockExclusive_t pReleaseSRWLockExclusive
=
294 (once_block_impl_nt6::ReleaseSRWLockExclusive_t
)boost::winapi::get_proc_address(hKernel32
, "ReleaseSRWLockExclusive");
295 if (pReleaseSRWLockExclusive
)
297 once_block_impl_nt6::InitializeConditionVariable_t pInitializeConditionVariable
=
298 (once_block_impl_nt6::InitializeConditionVariable_t
)boost::winapi::get_proc_address(hKernel32
, "InitializeConditionVariable");
299 if (pInitializeConditionVariable
)
301 once_block_impl_nt6::SleepConditionVariableSRW_t pSleepConditionVariableSRW
=
302 (once_block_impl_nt6::SleepConditionVariableSRW_t
)boost::winapi::get_proc_address(hKernel32
, "SleepConditionVariableSRW");
303 if (pSleepConditionVariableSRW
)
305 once_block_impl_nt6::WakeAllConditionVariable_t pWakeAllConditionVariable
=
306 (once_block_impl_nt6::WakeAllConditionVariable_t
)boost::winapi::get_proc_address(hKernel32
, "WakeAllConditionVariable");
307 if (pWakeAllConditionVariable
)
309 return new once_block_impl_nt6(
311 pAcquireSRWLockExclusive
,
312 pReleaseSRWLockExclusive
,
313 pInitializeConditionVariable
,
314 pSleepConditionVariableSRW
,
315 pWakeAllConditionVariable
);
324 return new once_block_impl_nt5();
327 once_block_impl_base
* g_pOnceBlockImpl
= NULL
;
329 void destroy_once_block_impl()
331 once_block_impl_base
* impl
= (once_block_impl_base
*)
332 BOOST_INTERLOCKED_EXCHANGE_POINTER((void**)&g_pOnceBlockImpl
, NULL
);
336 once_block_impl_base
* get_once_block_impl() BOOST_NOEXCEPT
338 once_block_impl_base
* impl
= g_pOnceBlockImpl
;
341 once_block_impl_base
* new_impl
= create_once_block_impl();
342 impl
= (once_block_impl_base
*)
343 BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER((void**)&g_pOnceBlockImpl
, (void*)new_impl
, NULL
);
350 std::atexit(&destroy_once_block_impl
);
356 BOOST_ASSERT_MSG(false, "Boost.Log: Failed to initialize the once block thread synchronization structures");
365 BOOST_LOG_API
bool once_block_sentry::enter_once_block() const BOOST_NOEXCEPT
367 return get_once_block_impl()->enter_once_block(m_flag
);
370 BOOST_LOG_API
void once_block_sentry::commit() BOOST_NOEXCEPT
372 get_once_block_impl()->commit(m_flag
);
375 BOOST_LOG_API
void once_block_sentry::rollback() BOOST_NOEXCEPT
377 get_once_block_impl()->rollback(m_flag
);
382 BOOST_LOG_CLOSE_NAMESPACE
// namespace log
386 #include <boost/log/detail/footer.hpp>
388 #endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
390 #elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
393 #include <boost/log/detail/header.hpp>
397 BOOST_LOG_OPEN_NAMESPACE
401 BOOST_LOG_ANONYMOUS_NAMESPACE
{
403 static pthread_mutex_t g_OnceBlockMutex
= PTHREAD_MUTEX_INITIALIZER
;
404 static pthread_cond_t g_OnceBlockCond
= PTHREAD_COND_INITIALIZER
;
408 BOOST_LOG_API
bool once_block_sentry::enter_once_block() const BOOST_NOEXCEPT
410 BOOST_VERIFY(!pthread_mutex_lock(&g_OnceBlockMutex
));
412 once_block_flag
volatile& flag
= m_flag
;
413 while (flag
.status
!= once_block_flag::initialized
)
415 if (flag
.status
== once_block_flag::uninitialized
)
417 flag
.status
= once_block_flag::being_initialized
;
418 BOOST_VERIFY(!pthread_mutex_unlock(&g_OnceBlockMutex
));
420 // Invoke the initializer block
425 while (flag
.status
== once_block_flag::being_initialized
)
427 BOOST_VERIFY(!pthread_cond_wait(&g_OnceBlockCond
, &g_OnceBlockMutex
));
432 BOOST_VERIFY(!pthread_mutex_unlock(&g_OnceBlockMutex
));
437 BOOST_LOG_API
void once_block_sentry::commit() BOOST_NOEXCEPT
439 BOOST_VERIFY(!pthread_mutex_lock(&g_OnceBlockMutex
));
441 // The initializer executed successfully
442 m_flag
.status
= once_block_flag::initialized
;
444 BOOST_VERIFY(!pthread_mutex_unlock(&g_OnceBlockMutex
));
445 BOOST_VERIFY(!pthread_cond_broadcast(&g_OnceBlockCond
));
448 BOOST_LOG_API
void once_block_sentry::rollback() BOOST_NOEXCEPT
450 BOOST_VERIFY(!pthread_mutex_lock(&g_OnceBlockMutex
));
452 // The initializer failed, marking the flag as if it hasn't run at all
453 m_flag
.status
= once_block_flag::uninitialized
;
455 BOOST_VERIFY(!pthread_mutex_unlock(&g_OnceBlockMutex
));
456 BOOST_VERIFY(!pthread_cond_broadcast(&g_OnceBlockCond
));
461 BOOST_LOG_CLOSE_NAMESPACE
// namespace log
465 #include <boost/log/detail/footer.hpp>
468 #error Boost.Log: unsupported threading API
471 #endif // BOOST_LOG_NO_THREADS