diff --git a/include/boost/thread/detail/thread.hpp b/include/boost/thread/detail/thread.hpp index afa22c32..a7e82f7f 100644 --- a/include/boost/thread/detail/thread.hpp +++ b/include/boost/thread/detail/thread.hpp @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include @@ -121,7 +123,11 @@ namespace boost template static inline detail::thread_data_ptr make_thread_info(F&& f) { - return detail::thread_data_ptr(detail::heap_new >(static_cast(f))); + return detail::thread_data_ptr(detail::heap_new::type> >(static_cast(f))); + } + static inline detail::thread_data_ptr make_thread_info(void (*f)()) + { + return detail::thread_data_ptr(detail::heap_new >(f)); } #else template @@ -134,6 +140,8 @@ namespace boost { return detail::thread_data_ptr(detail::heap_new >(f)); } + + struct dummy; #endif public: thread(); @@ -166,12 +174,12 @@ namespace boost #else template - explicit thread(F f): + explicit thread(F f,typename disable_if >, dummy* >::type=0): thread_info(make_thread_info(f)) { start_thread(); } - + template thread(detail::thread_move_t f): thread_info(make_thread_info(f)) diff --git a/include/boost/thread/locks.hpp b/include/boost/thread/locks.hpp index 8b183d38..b175c859 100644 --- a/include/boost/thread/locks.hpp +++ b/include/boost/thread/locks.hpp @@ -275,6 +275,12 @@ namespace boost friend class upgrade_lock; }; + template + void swap(unique_lock& lhs,unique_lock& rhs) + { + lhs.swap(rhs); + } + template class shared_lock { @@ -723,6 +729,12 @@ namespace boost return static_cast(*this); } }; + + template + void swap(try_lock_wrapper& lhs,try_lock_wrapper& rhs) + { + lhs.swap(rhs); + } template unsigned try_lock_internal(MutexType1& m1,MutexType2& m2) diff --git a/include/boost/thread/pthread/tss.hpp b/include/boost/thread/pthread/tss.hpp deleted file mode 100644 index 1f3cb246..00000000 --- a/include/boost/thread/pthread/tss.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef BOOST_THREAD_PTHREAD_TSS_HPP -#define BOOST_THREAD_PTHREAD_TSS_HPP - -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// (C) Copyright 2007-8 Anthony Williams - -#include -#include - -#include - -namespace boost -{ - namespace detail - { - struct tss_cleanup_function - { - virtual ~tss_cleanup_function() - {} - - virtual void operator()(void* data)=0; - }; - - BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr func,void* tss_data,bool cleanup_existing); - BOOST_THREAD_DECL void* get_tss_data(void const* key); - } - - template - class thread_specific_ptr - { - private: - thread_specific_ptr(thread_specific_ptr&); - thread_specific_ptr& operator=(thread_specific_ptr&); - - struct delete_data: - detail::tss_cleanup_function - { - void operator()(void* data) - { - delete static_cast(data); - } - }; - - struct run_custom_cleanup_function: - detail::tss_cleanup_function - { - void (*cleanup_function)(T*); - - explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)): - cleanup_function(cleanup_function_) - {} - - void operator()(void* data) - { - cleanup_function(static_cast(data)); - } - }; - - - boost::shared_ptr cleanup; - - public: - thread_specific_ptr(): - cleanup(new delete_data) - {} - explicit thread_specific_ptr(void (*func_)(T*)): - cleanup(new run_custom_cleanup_function(func_)) - {} - ~thread_specific_ptr() - { - reset(); - } - - T* get() const - { - return static_cast(detail::get_tss_data(this)); - } - T* operator->() const - { - return get(); - } - T& operator*() const - { - return *get(); - } - T* release() - { - T* const temp=get(); - detail::set_tss_data(this,boost::shared_ptr(),0,false); - return temp; - } - void reset(T* new_value=0) - { - T* const current_value=get(); - if(current_value!=new_value) - { - detail::set_tss_data(this,cleanup,new_value,true); - } - } - }; -} - -#include - -#endif diff --git a/include/boost/thread/tss.hpp b/include/boost/thread/tss.hpp index 131bcde2..4efc6e8b 100644 --- a/include/boost/thread/tss.hpp +++ b/include/boost/thread/tss.hpp @@ -1,18 +1,110 @@ -// Copyright (C) 2007 Anthony Williams -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - #ifndef BOOST_THREAD_TSS_HPP #define BOOST_THREAD_TSS_HPP +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007-8 Anthony Williams -#include -#if defined(BOOST_THREAD_PLATFORM_WIN32) -#include -#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) -#include -#else -#error "Boost threads unavailable on this platform" -#endif +#include +#include + +#include + +namespace boost +{ + namespace detail + { + struct tss_cleanup_function + { + virtual ~tss_cleanup_function() + {} + + virtual void operator()(void* data)=0; + }; + + BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr func,void* tss_data,bool cleanup_existing); + BOOST_THREAD_DECL void* get_tss_data(void const* key); + } + + template + class thread_specific_ptr + { + private: + thread_specific_ptr(thread_specific_ptr&); + thread_specific_ptr& operator=(thread_specific_ptr&); + + struct delete_data: + detail::tss_cleanup_function + { + void operator()(void* data) + { + delete static_cast(data); + } + }; + + struct run_custom_cleanup_function: + detail::tss_cleanup_function + { + void (*cleanup_function)(T*); + + explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)): + cleanup_function(cleanup_function_) + {} + + void operator()(void* data) + { + cleanup_function(static_cast(data)); + } + }; + + + boost::shared_ptr cleanup; + + public: + thread_specific_ptr(): + cleanup(detail::heap_new(),detail::do_heap_delete()) + {} + explicit thread_specific_ptr(void (*func_)(T*)) + { + if(func_) + { + cleanup.reset(detail::heap_new(func_),detail::do_heap_delete()); + } + } + ~thread_specific_ptr() + { + reset(); + } + + T* get() const + { + return static_cast(detail::get_tss_data(this)); + } + T* operator->() const + { + return get(); + } + T& operator*() const + { + return *get(); + } + T* release() + { + T* const temp=get(); + detail::set_tss_data(this,boost::shared_ptr(),0,false); + return temp; + } + void reset(T* new_value=0) + { + T* const current_value=get(); + if(current_value!=new_value) + { + detail::set_tss_data(this,cleanup,new_value,true); + } + } + }; +} + +#include #endif diff --git a/include/boost/thread/win32/thread_primitives.hpp b/include/boost/thread/win32/thread_primitives.hpp index 022dc9ee..de58c45b 100644 --- a/include/boost/thread/win32/thread_primitives.hpp +++ b/include/boost/thread/win32/thread_primitives.hpp @@ -281,8 +281,7 @@ namespace boost } } -#if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN) -#if _MSC_VER>=1400 +#if defined(BOOST_MSVC) && (_MSC_VER>=1400) && !defined(UNDER_CE) #if _MSC_VER==1400 extern "C" unsigned char _interlockedbittestandset(long *a,long b); extern "C" unsigned char _interlockedbittestandreset(long *a,long b); @@ -314,7 +313,7 @@ namespace boost } } #define BOOST_THREAD_BTS_DEFINED -#elif defined(_M_IX86) +#elif (defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)) && defined(_M_IX86) namespace boost { namespace detail @@ -346,7 +345,6 @@ namespace boost } #define BOOST_THREAD_BTS_DEFINED #endif -#endif #ifndef BOOST_THREAD_BTS_DEFINED diff --git a/include/boost/thread/win32/tss.hpp b/include/boost/thread/win32/tss.hpp deleted file mode 100644 index a5f1c31c..00000000 --- a/include/boost/thread/win32/tss.hpp +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef BOOST_THREAD_WIN32_TSS_HPP -#define BOOST_THREAD_WIN32_TSS_HPP -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// (C) Copyright 2007-8 Anthony Williams - -#include -#include "thread_heap_alloc.hpp" - -#include - -namespace boost -{ - namespace detail - { - struct tss_cleanup_function - { - virtual ~tss_cleanup_function() - {} - - virtual void operator()(void* data)=0; - }; - - BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr func,void* tss_data,bool cleanup_existing); - BOOST_THREAD_DECL void* get_tss_data(void const* key); - } - - template - class thread_specific_ptr - { - private: - thread_specific_ptr(thread_specific_ptr&); - thread_specific_ptr& operator=(thread_specific_ptr&); - - struct delete_data: - detail::tss_cleanup_function - { - void operator()(void* data) - { - delete static_cast(data); - } - }; - - struct run_custom_cleanup_function: - detail::tss_cleanup_function - { - void (*cleanup_function)(T*); - - explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)): - cleanup_function(cleanup_function_) - {} - - void operator()(void* data) - { - cleanup_function(static_cast(data)); - } - }; - - - boost::shared_ptr cleanup; - - public: - thread_specific_ptr(): - cleanup(detail::heap_new(),detail::do_heap_delete()) - {} - explicit thread_specific_ptr(void (*func_)(T*)): - cleanup(detail::heap_new(func_),detail::do_heap_delete()) - {} - ~thread_specific_ptr() - { - reset(); - } - - T* get() const - { - return static_cast(detail::get_tss_data(this)); - } - T* operator->() const - { - return get(); - } - T& operator*() const - { - return *get(); - } - T* release() - { - T* const temp=get(); - detail::set_tss_data(this,boost::shared_ptr(),0,false); - return temp; - } - void reset(T* new_value=0) - { - T* const current_value=get(); - if(current_value!=new_value) - { - detail::set_tss_data(this,cleanup,new_value,true); - } - } - }; -} - -#include - -#endif diff --git a/test/test_lock_concept.cpp b/test/test_lock_concept.cpp index 6b8b483f..8b16dfb5 100644 --- a/test/test_lock_concept.cpp +++ b/test/test_lock_concept.cpp @@ -1,4 +1,4 @@ -// (C) Copyright 2006-7 Anthony Williams +// (C) Copyright 2006-8 Anthony Williams // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -196,6 +196,35 @@ struct test_default_constructed_has_no_mutex_and_unlocked }; }; + +template +struct test_locks_can_be_swapped +{ + void operator()() const + { + Mutex m1; + Mutex m2; + Lock l1(m1); + Lock l2(m2); + + BOOST_CHECK_EQUAL(l1.mutex(),&m1); + BOOST_CHECK_EQUAL(l2.mutex(),&m2); + + l1.swap(l2); + + BOOST_CHECK_EQUAL(l1.mutex(),&m2); + BOOST_CHECK_EQUAL(l2.mutex(),&m1); + + swap(l1,l2); + + BOOST_CHECK_EQUAL(l1.mutex(),&m1); + BOOST_CHECK_EQUAL(l2.mutex(),&m2); + + } +}; + + + BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex) { typedef typename Mutex::scoped_lock Lock; @@ -208,6 +237,7 @@ BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex) test_locked_after_lock_called()(); test_throws_if_lock_called_when_already_locked()(); test_throws_if_unlock_called_when_already_unlocked()(); + test_locks_can_be_swapped()(); } BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex) @@ -225,6 +255,7 @@ BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex) test_throws_if_lock_called_when_already_locked()(); test_throws_if_try_lock_called_when_already_locked()(); test_throws_if_unlock_called_when_already_unlocked()(); + test_locks_can_be_swapped()(); } boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) diff --git a/test/test_tss.cpp b/test/test_tss.cpp index bbd78d42..8a6545ce 100644 --- a/test/test_tss.cpp +++ b/test/test_tss.cpp @@ -258,11 +258,58 @@ void do_test_tss_does_no_cleanup_after_release() } } +struct dummy_class_tracks_deletions +{ + static unsigned deletions; + + ~dummy_class_tracks_deletions() + { + ++deletions; + } + +}; + +unsigned dummy_class_tracks_deletions::deletions=0; + +boost::thread_specific_ptr tss_with_null_cleanup(NULL); + +void tss_thread_with_null_cleanup(dummy_class_tracks_deletions* delete_tracker) +{ + tss_with_null_cleanup.reset(delete_tracker); +} + +void do_test_tss_does_no_cleanup_with_null_cleanup_function() +{ + dummy_class_tracks_deletions* delete_tracker=new dummy_class_tracks_deletions; + boost::thread t(tss_thread_with_null_cleanup,delete_tracker); + try + { + t.join(); + } + catch(...) + { + t.interrupt(); + t.join(); + throw; + } + + BOOST_CHECK(!dummy_class_tracks_deletions::deletions); + if(!dummy_class_tracks_deletions::deletions) + { + delete delete_tracker; + } +} + void test_tss_does_no_cleanup_after_release() { timed_test(&do_test_tss_does_no_cleanup_after_release, 2); } +void test_tss_does_no_cleanup_with_null_cleanup_function() +{ + timed_test(&do_test_tss_does_no_cleanup_with_null_cleanup_function, 2); +} + boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { boost::unit_test_framework::test_suite* test = @@ -271,6 +318,7 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(test_tss)); test->add(BOOST_TEST_CASE(test_tss_with_custom_cleanup)); test->add(BOOST_TEST_CASE(test_tss_does_no_cleanup_after_release)); + test->add(BOOST_TEST_CASE(test_tss_does_no_cleanup_with_null_cleanup_function)); return test; }