From 58ffb2bc1655e540c742ffc94d91df2621d39393 Mon Sep 17 00:00:00 2001 From: Michael Glassford Date: Sat, 15 May 2004 02:03:48 +0000 Subject: [PATCH] Win32: use critical section instead of mutex whenever possible; abstract common code into functions. [SVN r22828] --- include/boost/thread/mutex.hpp | 14 +- include/boost/thread/recursive_mutex.hpp | 17 ++- src/mutex.cpp | 121 ++++++++------- src/mutex.inl | 119 +++++++++++++++ src/recursive_mutex.cpp | 185 ++++++++++++----------- 5 files changed, 304 insertions(+), 152 deletions(-) create mode 100644 src/mutex.inl diff --git a/include/boost/thread/mutex.hpp b/include/boost/thread/mutex.hpp index 66ab2ff5..31886741 100644 --- a/include/boost/thread/mutex.hpp +++ b/include/boost/thread/mutex.hpp @@ -13,12 +13,13 @@ #define BOOST_MUTEX_WEK070601_HPP #include + // insist on threading support being available: #include #include -#include #include +#include #if defined(BOOST_HAS_PTHREADS) # include @@ -32,7 +33,8 @@ namespace boost { struct xtime; -class BOOST_THREAD_DECL mutex : private noncopyable +class BOOST_THREAD_DECL mutex + : private noncopyable { public: friend class detail::thread::lock_ops; @@ -62,6 +64,7 @@ private: #if defined(BOOST_HAS_WINTHREADS) void* m_mutex; + bool m_critical_section; #elif defined(BOOST_HAS_PTHREADS) pthread_mutex_t m_mutex; #elif defined(BOOST_HAS_MPTASKS) @@ -70,7 +73,8 @@ private: #endif }; -class BOOST_THREAD_DECL try_mutex : private noncopyable +class BOOST_THREAD_DECL try_mutex + : private noncopyable { public: friend class detail::thread::lock_ops; @@ -102,6 +106,7 @@ private: #if defined(BOOST_HAS_WINTHREADS) void* m_mutex; + bool m_critical_section; #elif defined(BOOST_HAS_PTHREADS) pthread_mutex_t m_mutex; #elif defined(BOOST_HAS_MPTASKS) @@ -110,7 +115,8 @@ private: #endif }; -class BOOST_THREAD_DECL timed_mutex : private noncopyable +class BOOST_THREAD_DECL timed_mutex + : private noncopyable { public: friend class detail::thread::lock_ops; diff --git a/include/boost/thread/recursive_mutex.hpp b/include/boost/thread/recursive_mutex.hpp index ddd3ea7d..122c1399 100644 --- a/include/boost/thread/recursive_mutex.hpp +++ b/include/boost/thread/recursive_mutex.hpp @@ -18,12 +18,14 @@ #include #include -#include #include +#include #if defined(BOOST_HAS_PTHREADS) # include -#elif defined(BOOST_HAS_MPTASKS) +#endif + +#if defined(BOOST_HAS_MPTASKS) # include "scoped_critical_region.hpp" #endif @@ -31,7 +33,8 @@ namespace boost { struct xtime; -class BOOST_THREAD_DECL recursive_mutex : private noncopyable +class BOOST_THREAD_DECL recursive_mutex + : private noncopyable { public: friend class detail::thread::lock_ops; @@ -58,6 +61,7 @@ private: #if defined(BOOST_HAS_WINTHREADS) void* m_mutex; + bool m_critical_section; unsigned long m_count; #elif defined(BOOST_HAS_PTHREADS) pthread_mutex_t m_mutex; @@ -74,7 +78,8 @@ private: #endif }; -class BOOST_THREAD_DECL recursive_try_mutex : private noncopyable +class BOOST_THREAD_DECL recursive_try_mutex + : private noncopyable { public: friend class detail::thread::lock_ops; @@ -104,6 +109,7 @@ private: #if defined(BOOST_HAS_WINTHREADS) void* m_mutex; + bool m_critical_section; unsigned long m_count; #elif defined(BOOST_HAS_PTHREADS) pthread_mutex_t m_mutex; @@ -120,7 +126,8 @@ private: #endif }; -class BOOST_THREAD_DECL recursive_timed_mutex : private noncopyable +class BOOST_THREAD_DECL recursive_timed_mutex + : private noncopyable { public: friend class detail::thread::lock_ops; diff --git a/src/mutex.cpp b/src/mutex.cpp index 887406e5..224c663d 100644 --- a/src/mutex.cpp +++ b/src/mutex.cpp @@ -19,47 +19,56 @@ #include "timeconv.inl" #if defined(BOOST_HAS_WINTHREADS) +# include +# include # include # include +# include "mutex.inl" #elif defined(BOOST_HAS_PTHREADS) # include #elif defined(BOOST_HAS_MPTASKS) -# include -# include "mac/init.hpp" -# include "mac/safe.hpp" +# include +# include "mac/init.hpp" +# include "mac/safe.hpp" #endif namespace boost { #if defined(BOOST_HAS_WINTHREADS) -mutex::mutex() : m_mutex(0) + +mutex::mutex() + : m_mutex(0) + , m_critical_section(false) { - try - { - m_mutex = reinterpret_cast(new CRITICAL_SECTION); - } - catch (...) - { - } - if (!m_mutex) - throw thread_resource_error(); - InitializeCriticalSection(reinterpret_cast(m_mutex)); + m_critical_section = true; + if (m_critical_section) + m_mutex = new_critical_section(); + else + m_mutex = new_mutex(0); } mutex::~mutex() { - DeleteCriticalSection(reinterpret_cast(m_mutex)); - delete reinterpret_cast(m_mutex); + if (m_critical_section) + delete_critical_section(m_mutex); + else + delete_mutex(m_mutex); } void mutex::do_lock() { - EnterCriticalSection(reinterpret_cast(m_mutex)); + if (m_critical_section) + wait_critical_section_infinite(m_mutex); + else + wait_mutex(m_mutex, INFINITE); } void mutex::do_unlock() { - LeaveCriticalSection(reinterpret_cast(m_mutex)); + if (m_critical_section) + release_critical_section(m_mutex); + else + release_mutex(m_mutex); } void mutex::do_lock(cv_state&) @@ -73,39 +82,46 @@ void mutex::do_unlock(cv_state&) } try_mutex::try_mutex() + : m_mutex(0) + , m_critical_section(false) { - m_mutex = reinterpret_cast(CreateMutex(0, 0, 0)); - if (!m_mutex) - throw thread_resource_error(); + m_critical_section = has_TryEnterCriticalSection(); + if (m_critical_section) + m_mutex = new_critical_section(); + else + m_mutex = new_mutex(0); } try_mutex::~try_mutex() { - int res = 0; - res = CloseHandle(reinterpret_cast(m_mutex)); - assert(res); + if (m_critical_section) + delete_critical_section(m_mutex); + else + delete_mutex(m_mutex); } void try_mutex::do_lock() { - int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_mutex), INFINITE); - assert(res == WAIT_OBJECT_0); + if (m_critical_section) + wait_critical_section_infinite(m_mutex); + else + wait_mutex(m_mutex, INFINITE); } bool try_mutex::do_trylock() { - unsigned int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_mutex), 0); - assert(res != WAIT_FAILED && res != WAIT_ABANDONED); - return res == WAIT_OBJECT_0; + if (m_critical_section) + return wait_critical_section_try(m_mutex); + else + return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0; } void try_mutex::do_unlock() { - int res = 0; - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); + if (m_critical_section) + release_critical_section(m_mutex); + else + release_mutex(m_mutex); } void try_mutex::do_lock(cv_state&) @@ -119,51 +135,40 @@ void try_mutex::do_unlock(cv_state&) } timed_mutex::timed_mutex() + : m_mutex(0) { - m_mutex = reinterpret_cast(CreateMutex(0, 0, 0)); - if (!m_mutex) - throw thread_resource_error(); + m_mutex = new_mutex(0); } timed_mutex::~timed_mutex() { - int res = 0; - res = CloseHandle(reinterpret_cast(m_mutex)); - assert(res); + delete_mutex(m_mutex); } void timed_mutex::do_lock() { - int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_mutex), INFINITE); - assert(res == WAIT_OBJECT_0); + wait_mutex(m_mutex, INFINITE); } bool timed_mutex::do_trylock() { - unsigned int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_mutex), 0); - assert(res != WAIT_FAILED && res != WAIT_ABANDONED); - return res == WAIT_OBJECT_0; + return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0; } bool timed_mutex::do_timedlock(const xtime& xt) { - unsigned int res = 0; for (;;) { int milliseconds; to_duration(xt, milliseconds); - res = WaitForSingleObject(reinterpret_cast(m_mutex), - milliseconds); - assert(res != WAIT_FAILED && res != WAIT_ABANDONED); + int res = wait_mutex(m_mutex, milliseconds); if (res == WAIT_TIMEOUT) { - xtime cur; - xtime_get(&cur, TIME_UTC); - if (xtime_cmp(xt, cur) > 0) + boost::xtime cur; + boost::xtime_get(&cur, boost::TIME_UTC); + if (boost::xtime_cmp(xt, cur) > 0) continue; } @@ -173,9 +178,7 @@ bool timed_mutex::do_timedlock(const xtime& xt) void timed_mutex::do_unlock() { - int res = 0; - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); + release_mutex(m_mutex); } void timed_mutex::do_lock(cv_state&) @@ -187,7 +190,9 @@ void timed_mutex::do_unlock(cv_state&) { do_unlock(); } + #elif defined(BOOST_HAS_PTHREADS) + mutex::mutex() { int res = 0; @@ -417,6 +422,7 @@ void timed_mutex::do_unlock(cv_state& state) state.pmutex = &m_mutex; } + #elif defined(BOOST_HAS_MPTASKS) using threads::mac::detail::safe_enter_critical_region; @@ -548,6 +554,7 @@ void timed_mutex::do_unlock(cv_state& /*state*/) { do_unlock(); } + #endif } // namespace boost diff --git a/src/mutex.inl b/src/mutex.inl new file mode 100644 index 00000000..7ff07818 --- /dev/null +++ b/src/mutex.inl @@ -0,0 +1,119 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. William E. Kempf makes no representations +// about the suitability of this software for any purpose. +// It is provided "as is" without express or implied warranty. + +namespace { + +#if defined(BOOST_HAS_WINTHREADS) +//:PREVENT THIS FROM BEING DUPLICATED +typedef BOOL (WINAPI* TryEnterCriticalSection_type)(LPCRITICAL_SECTION lpCriticalSection); +TryEnterCriticalSection_type g_TryEnterCriticalSection = 0; +boost::once_flag once_init_TryEnterCriticalSection = BOOST_ONCE_INIT; + +void init_TryEnterCriticalSection() +{ + //TryEnterCriticalSection is only available on WinNT 4.0 or later; + //it is not available on Win9x. + + OSVERSIONINFO version_info = {sizeof(OSVERSIONINFO)}; + ::GetVersionEx(&version_info); + if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && + version_info.dwMajorVersion >= 4) + { + if (HMODULE kernel_module = GetModuleHandle(TEXT("KERNEL32.DLL"))) + g_TryEnterCriticalSection = reinterpret_cast(GetProcAddress(kernel_module, "TryEnterCriticalSection")); + } +} + +inline bool has_TryEnterCriticalSection() +{ + boost::call_once(init_TryEnterCriticalSection, once_init_TryEnterCriticalSection); + return g_TryEnterCriticalSection != 0; +} + +inline HANDLE mutex_cast(void* p) +{ + return reinterpret_cast(p); +} + +inline LPCRITICAL_SECTION critical_section_cast(void* p) +{ + return reinterpret_cast(p); +} + +inline void* new_critical_section() +{ + try + { + LPCRITICAL_SECTION critical_section = new CRITICAL_SECTION; + if (critical_section == 0) throw boost::thread_resource_error(); + InitializeCriticalSection(critical_section); + return critical_section; + } + catch(...) + { + throw boost::thread_resource_error(); + } +} + +inline void* new_mutex(const char* name) +{ + HANDLE mutex = CreateMutex(0, 0, name); + if (mutex == 0 || mutex == INVALID_HANDLE_VALUE) //:xxx (check for both values?) + throw boost::thread_resource_error(); + return reinterpret_cast(mutex); +} + +inline void delete_critical_section(void* mutex) +{ + DeleteCriticalSection(critical_section_cast(mutex)); + delete critical_section_cast(mutex); +} + +inline void delete_mutex(void* mutex) +{ + int res = 0; + res = CloseHandle(mutex_cast(mutex)); + assert(res); +} + +inline void wait_critical_section_infinite(void* mutex) +{ + EnterCriticalSection(critical_section_cast(mutex)); //:xxx Can throw an exception under low memory conditions +} + +inline bool wait_critical_section_try(void* mutex) +{ + BOOL res = g_TryEnterCriticalSection(critical_section_cast(mutex)); + return res != 0; +} + +inline int wait_mutex(void* mutex, int time) +{ + unsigned int res = 0; + res = WaitForSingleObject(mutex_cast(mutex), time); +//:xxx assert(res != WAIT_FAILED && res != WAIT_ABANDONED); + return res; +} + +inline void release_critical_section(void* mutex) +{ + LeaveCriticalSection(critical_section_cast(mutex)); +} + +inline void release_mutex(void* mutex) +{ + BOOL res = FALSE; + res = ReleaseMutex(mutex_cast(mutex)); + assert(res); +} +#endif + +} \ No newline at end of file diff --git a/src/recursive_mutex.cpp b/src/recursive_mutex.cpp index eb3b60b9..5d13eaf2 100644 --- a/src/recursive_mutex.cpp +++ b/src/recursive_mutex.cpp @@ -18,8 +18,11 @@ #include "timeconv.inl" #if defined(BOOST_HAS_WINTHREADS) +# include +# include # include # include +# include "mutex.inl" #elif defined(BOOST_HAS_PTHREADS) # include #elif defined(BOOST_HAS_MPTASKS) @@ -30,44 +33,61 @@ namespace boost { #if defined(BOOST_HAS_WINTHREADS) + recursive_mutex::recursive_mutex() - : m_mutex(0), m_count(0) + : m_mutex(0) + , m_count(0) + , m_critical_section(false) { - try - { - m_mutex = reinterpret_cast(new CRITICAL_SECTION); - } - catch (...) - { - } - if (!m_mutex) - throw thread_resource_error(); - InitializeCriticalSection(reinterpret_cast(m_mutex)); + m_critical_section = true; + if (m_critical_section) + m_mutex = new_critical_section(); + else + m_mutex = new_mutex(0); } recursive_mutex::~recursive_mutex() { - DeleteCriticalSection(reinterpret_cast(m_mutex)); - delete reinterpret_cast(m_mutex); + if (m_critical_section) + delete_critical_section(m_mutex); + else + delete_mutex(m_mutex); } void recursive_mutex::do_lock() { - EnterCriticalSection(reinterpret_cast(m_mutex)); + if (m_critical_section) + wait_critical_section_infinite(m_mutex); + else + wait_mutex(m_mutex, INFINITE); if (++m_count > 1) - LeaveCriticalSection(reinterpret_cast(m_mutex)); + { + if (m_critical_section) + release_critical_section(m_mutex); + else + release_mutex(m_mutex); + } } void recursive_mutex::do_unlock() { if (--m_count == 0) - LeaveCriticalSection(reinterpret_cast(m_mutex)); + { + if (m_critical_section) + release_critical_section(m_mutex); + else + release_mutex(m_mutex); + } } void recursive_mutex::do_lock(cv_state& state) { - EnterCriticalSection(reinterpret_cast(m_mutex)); + if (m_critical_section) + wait_critical_section_infinite(m_mutex); + else + wait_mutex(m_mutex, INFINITE); + m_count = state; } @@ -75,49 +95,65 @@ void recursive_mutex::do_unlock(cv_state& state) { state = m_count; m_count = 0; - LeaveCriticalSection(reinterpret_cast(m_mutex)); + + if (m_critical_section) + release_critical_section(m_mutex); + else + release_mutex(m_mutex); } recursive_try_mutex::recursive_try_mutex() - : m_count(0) + : m_mutex(0) + , m_count(0) + , m_critical_section(false) { - m_mutex = reinterpret_cast(CreateMutex(0, 0, 0)); - if (!m_mutex) - throw thread_resource_error(); + m_critical_section = has_TryEnterCriticalSection(); + if (m_critical_section) + m_mutex = new_critical_section(); + else + m_mutex = new_mutex(0); } recursive_try_mutex::~recursive_try_mutex() { - int res = 0; - res = CloseHandle(reinterpret_cast(m_mutex)); - assert(res); + if (m_critical_section) + delete_critical_section(m_mutex); + else + delete_mutex(m_mutex); } void recursive_try_mutex::do_lock() { - int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_mutex), INFINITE); - assert(res == WAIT_OBJECT_0); + if (m_critical_section) + wait_critical_section_infinite(m_mutex); + else + wait_mutex(m_mutex, INFINITE); if (++m_count > 1) { - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); + if (m_critical_section) + release_critical_section(m_mutex); + else + release_mutex(m_mutex); } } bool recursive_try_mutex::do_trylock() { - unsigned int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_mutex), 0); - assert(res != WAIT_FAILED && res != WAIT_ABANDONED); + bool res = false; + if (m_critical_section) + res = wait_critical_section_try(m_mutex); + else + res = wait_mutex(m_mutex, 0) == WAIT_OBJECT_0; - if (res == WAIT_OBJECT_0) + if (res) { if (++m_count > 1) { - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); + if (m_critical_section) + release_critical_section(m_mutex); + else + release_mutex(m_mutex); } return true; } @@ -128,17 +164,19 @@ void recursive_try_mutex::do_unlock() { if (--m_count == 0) { - int res = 0; - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); + if (m_critical_section) + release_critical_section(m_mutex); + else + release_mutex(m_mutex); } } void recursive_try_mutex::do_lock(cv_state& state) { - int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_mutex), INFINITE); - assert(res == WAIT_OBJECT_0); + if (m_critical_section) + wait_critical_section_infinite(m_mutex); + else + wait_mutex(m_mutex, INFINITE); m_count = state; } @@ -148,52 +186,40 @@ void recursive_try_mutex::do_unlock(cv_state& state) state = m_count; m_count = 0; - int res = 0; - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); + if (m_critical_section) + release_critical_section(m_mutex); + else + release_mutex(m_mutex); } recursive_timed_mutex::recursive_timed_mutex() - : m_count(0) + : m_mutex(0) + , m_count(0) { - m_mutex = reinterpret_cast(CreateMutex(0, 0, 0)); - if (!m_mutex) - throw thread_resource_error(); + m_mutex = new_mutex(0); } recursive_timed_mutex::~recursive_timed_mutex() { - int res = 0; - res = CloseHandle(reinterpret_cast(m_mutex)); - assert(res); + delete_mutex(m_mutex); } void recursive_timed_mutex::do_lock() { - int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_mutex), INFINITE); - assert(res == WAIT_OBJECT_0); + wait_mutex(m_mutex, INFINITE); if (++m_count > 1) - { - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - } + release_mutex(m_mutex); } bool recursive_timed_mutex::do_trylock() { - unsigned int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_mutex), 0); - assert(res != WAIT_FAILED && res != WAIT_ABANDONED); + bool res = wait_mutex(m_mutex, 0) == WAIT_OBJECT_0; - if (res == WAIT_OBJECT_0) + if (res) { if (++m_count > 1) - { - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - } + release_mutex(m_mutex); return true; } return false; @@ -206,10 +232,7 @@ bool recursive_timed_mutex::do_timedlock(const xtime& xt) int milliseconds; to_duration(xt, milliseconds); - unsigned int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_mutex), - milliseconds); - assert(res != WAIT_FAILED && res != WAIT_ABANDONED); + unsigned int res = wait_mutex(m_mutex, milliseconds); if (res == WAIT_TIMEOUT) { @@ -222,10 +245,7 @@ bool recursive_timed_mutex::do_timedlock(const xtime& xt) if (res == WAIT_OBJECT_0) { if (++m_count > 1) - { - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - } + release_mutex(m_mutex); return true; } @@ -236,18 +256,12 @@ bool recursive_timed_mutex::do_timedlock(const xtime& xt) void recursive_timed_mutex::do_unlock() { if (--m_count == 0) - { - int res = 0; - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); - } + release_mutex(m_mutex); } void recursive_timed_mutex::do_lock(cv_state& state) { - int res = 0; - res = WaitForSingleObject(reinterpret_cast(m_mutex), INFINITE); - assert(res == WAIT_OBJECT_0); + wait_mutex(m_mutex, INFINITE); m_count = state; } @@ -257,10 +271,9 @@ void recursive_timed_mutex::do_unlock(cv_state& state) state = m_count; m_count = 0; - int res = 0; - res = ReleaseMutex(reinterpret_cast(m_mutex)); - assert(res); + release_mutex(m_mutex); } + #elif defined(BOOST_HAS_PTHREADS) recursive_mutex::recursive_mutex()