From 3f40b571906e143d1d0144ce09feed578a928882 Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Fri, 5 Sep 2008 04:13:30 +0000 Subject: [PATCH] merged from trunk [SVN r48605] --- doc/changes.qbk | 3 + include/boost/thread/locks.hpp | 6 ++ .../thread/win32/basic_recursive_mutex.hpp | 10 --- .../boost/thread/win32/basic_timed_mutex.hpp | 10 --- src/win32/thread.cpp | 22 ++++- src/win32/tss_pe.cpp | 46 ++++++---- test/test_mutex.cpp | 84 +++++++++++++++++++ 7 files changed, 143 insertions(+), 38 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index baa24fa6..25ae1472 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -77,4 +77,7 @@ been moved to __thread_id__. * __mutex__ is now never recursive. For Boost releases prior to 1.35 __mutex__ was recursive on Windows and not on POSIX platforms. +* When using a __recursive_mutex__ with a call to [cond_any_wait_link `boost::condition_variable_any::wait()`], the mutex is only + unlocked one level, and not completely. This prior behaviour was not guaranteed and did not feature in the tests. + [endsect] diff --git a/include/boost/thread/locks.hpp b/include/boost/thread/locks.hpp index 6e4341ad..abbfd75b 100644 --- a/include/boost/thread/locks.hpp +++ b/include/boost/thread/locks.hpp @@ -234,6 +234,12 @@ namespace boost { try_lock(); } + template + unique_lock(Mutex& m_,TimeDuration const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } unique_lock(Mutex& m_,system_time const& target_time): m(&m_),is_locked(false) { diff --git a/include/boost/thread/win32/basic_recursive_mutex.hpp b/include/boost/thread/win32/basic_recursive_mutex.hpp index 89c5f1dc..05eb8d76 100644 --- a/include/boost/thread/win32/basic_recursive_mutex.hpp +++ b/include/boost/thread/win32/basic_recursive_mutex.hpp @@ -64,11 +64,6 @@ namespace boost return timed_lock(get_system_time()+timeout); } - long get_active_count() - { - return mutex.get_active_count(); - } - void unlock() { if(!--recursion_count) @@ -78,11 +73,6 @@ namespace boost } } - bool locked() - { - return mutex.locked(); - } - private: bool try_recursive_lock(long current_thread_id) { diff --git a/include/boost/thread/win32/basic_timed_mutex.hpp b/include/boost/thread/win32/basic_timed_mutex.hpp index 00206061..751bdbda 100644 --- a/include/boost/thread/win32/basic_timed_mutex.hpp +++ b/include/boost/thread/win32/basic_timed_mutex.hpp @@ -123,11 +123,6 @@ namespace boost return timed_lock(system_time(timeout)); } - long get_active_count() - { - return ::boost::detail::interlocked_read_acquire(&active_count); - } - void unlock() { long const offset=lock_flag_value; @@ -141,11 +136,6 @@ namespace boost } } - bool locked() - { - return get_active_count()>=lock_flag_value; - } - private: void* get_event() { diff --git a/src/win32/thread.cpp b/src/win32/thread.cpp index e54b847d..9c4f82b0 100644 --- a/src/win32/thread.cpp +++ b/src/win32/thread.cpp @@ -29,13 +29,26 @@ namespace boost void create_current_thread_tls_key() { + tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in current_thread_tls_key=TlsAlloc(); BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES); } + void cleanup_tls_key() + { + if(current_thread_tls_key) + { + TlsFree(current_thread_tls_key); + current_thread_tls_key=0; + } + } + detail::thread_data_base* get_current_thread_data() { - boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key); + if(!current_thread_tls_key) + { + return 0; + } return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key); } @@ -141,8 +154,8 @@ namespace boost } } + set_current_thread_data(0); } - set_current_thread_data(0); } unsigned __stdcall thread_start_function(void* param) @@ -544,7 +557,6 @@ namespace boost void set_tss_data(void const* key,boost::shared_ptr func,void* tss_data,bool cleanup_existing) { - tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in if(tss_data_node* const current_node=find_tss_data(key)) { if(cleanup_existing && current_node->func.get()) @@ -572,7 +584,9 @@ extern "C" BOOST_THREAD_DECL void on_thread_enter() {} extern "C" BOOST_THREAD_DECL void on_process_exit() -{} +{ + boost::cleanup_tls_key(); +} extern "C" BOOST_THREAD_DECL void on_thread_exit() { diff --git a/src/win32/tss_pe.cpp b/src/win32/tss_pe.cpp index bd2e61d8..ea831218 100644 --- a/src/win32/tss_pe.cpp +++ b/src/win32/tss_pe.cpp @@ -26,11 +26,11 @@ namespace { { switch (dwReason) { - case DLL_THREAD_DETACH: - { - on_thread_exit(); - break; - } + case DLL_THREAD_DETACH: + { + on_thread_exit(); + break; + } } } @@ -125,10 +125,10 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata #pragma section(".CRT$XCU",long,read) #pragma section(".CRT$XTU",long,read) #pragma section(".CRT$XLC",long,read) - static __declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback; - static __declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare; - static __declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init; - static __declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term; + __declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback; + __declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare; + __declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init; + __declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term; #else #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 # pragma data_seg(push, old_seg) @@ -168,6 +168,7 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata #pragma warning(push) #pragma warning(disable:4189) #endif + PVAPI on_tls_prepare(void) { //The following line has an important side effect: @@ -239,15 +240,32 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata { switch (dwReason) { - case DLL_THREAD_DETACH: - { - on_thread_exit(); - break; - } + case DLL_THREAD_DETACH: + on_thread_exit(); + break; } } + + BOOL WINAPI dll_callback(HANDLE, DWORD dwReason, LPVOID) + { + switch (dwReason) + { + case DLL_THREAD_DETACH: + on_thread_exit(); + break; + case DLL_PROCESS_DETACH: + on_process_exit(); + break; + } + return true; + } } //namespace +extern "C" +{ + extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD, LPVOID)=&dll_callback; +} + extern "C" void tss_cleanup_implemented(void) { /* diff --git a/test/test_mutex.cpp b/test/test_mutex.cpp index e85459c4..8725a8fd 100644 --- a/test/test_mutex.cpp +++ b/test/test_mutex.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -96,6 +97,86 @@ struct test_trylock } }; +template +struct test_lock_times_out_if_other_thread_has_lock +{ + typedef boost::unique_lock Lock; + + Mutex m; + boost::mutex done_mutex; + bool done; + bool locked; + boost::condition_variable done_cond; + + test_lock_times_out_if_other_thread_has_lock(): + done(false),locked(false) + {} + + void locking_thread() + { + Lock lock(m,boost::defer_lock); + lock.timed_lock(boost::posix_time::milliseconds(50)); + + boost::lock_guard lk(done_mutex); + locked=lock.owns_lock(); + done=true; + done_cond.notify_one(); + } + + void locking_thread_through_constructor() + { + Lock lock(m,boost::posix_time::milliseconds(50)); + + boost::lock_guard lk(done_mutex); + locked=lock.owns_lock(); + done=true; + done_cond.notify_one(); + } + + bool is_done() const + { + return done; + } + + typedef test_lock_times_out_if_other_thread_has_lock this_type; + + void do_test(void (this_type::*test_func)()) + { + Lock lock(m); + + locked=false; + done=false; + + boost::thread t(test_func,this); + + try + { + { + boost::mutex::scoped_lock lk(done_mutex); + BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2), + boost::bind(&this_type::is_done,this))); + BOOST_CHECK(!locked); + } + + lock.unlock(); + t.join(); + } + catch(...) + { + lock.unlock(); + t.join(); + throw; + } + } + + + void operator()() + { + do_test(&this_type::locking_thread); + do_test(&this_type::locking_thread_through_constructor); + } +}; + template struct test_timedlock { @@ -109,6 +190,8 @@ struct test_timedlock void operator()() { + test_lock_times_out_if_other_thread_has_lock()(); + mutex_type mutex; boost::condition condition; @@ -178,6 +261,7 @@ struct test_recursive_lock } }; + void do_test_mutex() { test_lock()();