diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 50168a91..b38e9d18 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -180,7 +180,6 @@ rule requirements ( properties * ) alias thread_sources : ## win32 sources ## win32/thread.cpp - win32/exceptions.cpp win32/tss_dll.cpp win32/tss_pe.cpp : ## requirements ## @@ -190,7 +189,6 @@ alias thread_sources alias thread_sources : ## pthread sources ## pthread/thread.cpp - pthread/exceptions.cpp pthread/once.cpp : ## requirements ## pthread diff --git a/example/condition.cpp b/example/condition.cpp index 096c35d8..7430e462 100644 --- a/example/condition.cpp +++ b/example/condition.cpp @@ -50,8 +50,9 @@ boost::mutex io_mutex; void sender() { int n = 0; - while (n < 100) { + while (n < 1000000) { buf.send(n); + if(!(n%10000)) { boost::mutex::scoped_lock io_lock(io_mutex); std::cout << "sent: " << n << std::endl; @@ -65,18 +66,24 @@ void receiver() { int n; do { n = buf.receive(); + if(!(n%10000)) { boost::mutex::scoped_lock io_lock(io_mutex); std::cout << "received: " << n << std::endl; } } while (n != -1); // -1 indicates end of buffer + buf.send(-1); } int main(int, char*[]) { boost::thread thrd1(&sender); boost::thread thrd2(&receiver); + boost::thread thrd3(&receiver); + boost::thread thrd4(&receiver); thrd1.join(); thrd2.join(); + thrd3.join(); + thrd4.join(); return 0; } diff --git a/example/tennis.cpp b/example/tennis.cpp index e2228717..798f55e5 100644 --- a/example/tennis.cpp +++ b/example/tennis.cpp @@ -112,7 +112,7 @@ int main(int argc, char* argv[]) std::cout << "---Noise ON..." << std::endl; } - for (int i = 0; i < 1000000; ++i) + for (int i = 0; i < 1000000000; ++i) cond.notify_all(); { diff --git a/include/boost/thread/detail/move.hpp b/include/boost/thread/detail/move.hpp index 044ecda6..eb21107f 100644 --- a/include/boost/thread/detail/move.hpp +++ b/include/boost/thread/detail/move.hpp @@ -41,9 +41,9 @@ namespace boost #ifndef BOOST_NO_SFINAE template - typename enable_if >, T >::type move(T& t) + typename enable_if >, detail::thread_move_t >::type move(T& t) { - return T(detail::thread_move_t(t)); + return detail::thread_move_t(t); } #endif diff --git a/include/boost/thread/detail/thread.hpp b/include/boost/thread/detail/thread.hpp index fbb895d1..8f4bedf5 100644 --- a/include/boost/thread/detail/thread.hpp +++ b/include/boost/thread/detail/thread.hpp @@ -144,6 +144,9 @@ namespace boost struct dummy; #endif public: +#ifdef __SUNPRO_CC + thread(const volatile thread&); +#endif thread(); ~thread(); @@ -201,14 +204,21 @@ namespace boost thread_info=x->thread_info; x->thread_info.reset(); } - + +#ifdef __SUNPRO_CC + thread& operator=(thread x) + { + swap(x); + return *this; + } +#else thread& operator=(detail::thread_move_t x) { thread new_thread(x); swap(new_thread); return *this; } - +#endif operator detail::thread_move_t() { return move(); @@ -339,9 +349,9 @@ namespace boost return t; } #else - inline thread move(detail::thread_move_t t) + inline detail::thread_move_t move(detail::thread_move_t t) { - return thread(t); + return t; } #endif diff --git a/include/boost/thread/exceptions.hpp b/include/boost/thread/exceptions.hpp index 49e244fe..2a05b506 100644 --- a/include/boost/thread/exceptions.hpp +++ b/include/boost/thread/exceptions.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2001-2003 // William E. Kempf -// Copyright (C) 2007-8 Anthony Williams +// Copyright (C) 2007-9 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) @@ -24,23 +24,36 @@ namespace boost { - class BOOST_THREAD_DECL thread_interrupted + class thread_interrupted {}; -class BOOST_THREAD_DECL thread_exception : public std::exception -{ -protected: - thread_exception(); - thread_exception(int sys_err_code); + class thread_exception: + public std::exception + { + protected: + thread_exception(): + m_sys_err(0) + {} + + thread_exception(int sys_err_code): + m_sys_err(sys_err_code) + {} + -public: - ~thread_exception() throw(); + public: + ~thread_exception() throw() + {} + - int native_error() const; + int native_error() const + { + return m_sys_err; + } + -private: - int m_sys_err; -}; + private: + int m_sys_err; + }; class condition_error: public std::exception @@ -53,62 +66,117 @@ private: }; -class BOOST_THREAD_DECL lock_error : public thread_exception -{ -public: - lock_error(); - lock_error(int sys_err_code); - ~lock_error() throw(); + class lock_error: + public thread_exception + { + public: + lock_error() + {} + + lock_error(int sys_err_code): + thread_exception(sys_err_code) + {} + + ~lock_error() throw() + {} + - virtual const char* what() const throw(); -}; + virtual const char* what() const throw() + { + return "boost::lock_error"; + } + }; -class BOOST_THREAD_DECL thread_resource_error : public thread_exception -{ -public: - thread_resource_error(); - thread_resource_error(int sys_err_code); - ~thread_resource_error() throw(); + class thread_resource_error: + public thread_exception + { + public: + thread_resource_error() + {} + + thread_resource_error(int sys_err_code): + thread_exception(sys_err_code) + {} + + ~thread_resource_error() throw() + {} + - virtual const char* what() const throw(); -}; + virtual const char* what() const throw() + { + return "boost::thread_resource_error"; + } + + }; -class BOOST_THREAD_DECL unsupported_thread_option : public thread_exception -{ -public: - unsupported_thread_option(); - unsupported_thread_option(int sys_err_code); - ~unsupported_thread_option() throw(); + class unsupported_thread_option: + public thread_exception + { + public: + unsupported_thread_option() + {} + + unsupported_thread_option(int sys_err_code): + thread_exception(sys_err_code) + {} + + ~unsupported_thread_option() throw() + {} + - virtual const char* what() const throw(); -}; + virtual const char* what() const throw() + { + return "boost::unsupported_thread_option"; + } + + }; -class BOOST_THREAD_DECL invalid_thread_argument : public thread_exception -{ -public: - invalid_thread_argument(); - invalid_thread_argument(int sys_err_code); - ~invalid_thread_argument() throw(); + class invalid_thread_argument: + public thread_exception + { + public: + invalid_thread_argument() + {} + + invalid_thread_argument(int sys_err_code): + thread_exception(sys_err_code) + {} + + ~invalid_thread_argument() throw() + {} + - virtual const char* what() const throw(); -}; + virtual const char* what() const throw() + { + return "boost::invalid_thread_argument"; + } + + }; -class BOOST_THREAD_DECL thread_permission_error : public thread_exception -{ -public: - thread_permission_error(); - thread_permission_error(int sys_err_code); - ~thread_permission_error() throw(); + class thread_permission_error: + public thread_exception + { + public: + thread_permission_error() + {} + + thread_permission_error(int sys_err_code): + thread_exception(sys_err_code) + {} + + ~thread_permission_error() throw() + {} + - virtual const char* what() const throw(); -}; + virtual const char* what() const throw() + { + return "boost::thread_permission_error"; + } + + }; } // namespace boost #include -#endif // BOOST_THREAD_CONFIG_PDM070801_H - -// Change log: -// 3 Jan 03 WEKEMPF Modified for DLL implementation. - +#endif diff --git a/include/boost/thread/locks.hpp b/include/boost/thread/locks.hpp index abbfd75b..5e8e271a 100644 --- a/include/boost/thread/locks.hpp +++ b/include/boost/thread/locks.hpp @@ -214,6 +214,9 @@ namespace boost unique_lock& operator=(unique_lock&); unique_lock& operator=(upgrade_lock& other); public: +#ifdef __SUNPRO_CC + unique_lock(const volatile unique_lock&); +#endif unique_lock(): m(0),is_locked(false) {} @@ -297,12 +300,20 @@ namespace boost return detail::thread_move_t >(*this); } +#ifdef __SUNPRO_CC + unique_lock& operator=(unique_lock other) + { + swap(other); + return *this; + } +#else unique_lock& operator=(detail::thread_move_t > other) { unique_lock temp(other); swap(temp); return *this; } +#endif unique_lock& operator=(detail::thread_move_t > other) { diff --git a/include/boost/thread/pthread/thread_data.hpp b/include/boost/thread/pthread/thread_data.hpp index 244035b4..730c77ca 100644 --- a/include/boost/thread/pthread/thread_data.hpp +++ b/include/boost/thread/pthread/thread_data.hpp @@ -13,6 +13,7 @@ #include #include #include "condition_variable_fwd.hpp" +#include #include @@ -22,8 +23,18 @@ namespace boost namespace detail { + struct tss_cleanup_function; struct thread_exit_callback_node; - struct tss_data_node; + struct tss_data_node + { + boost::shared_ptr func; + void* value; + + tss_data_node(boost::shared_ptr func_, + void* value_): + func(func_),value(value_) + {} + }; struct thread_data_base; typedef boost::shared_ptr thread_data_ptr; @@ -41,14 +52,14 @@ namespace boost bool join_started; bool joined; boost::detail::thread_exit_callback_node* thread_exit_callbacks; - boost::detail::tss_data_node* tss_data; + std::map tss_data; bool interrupt_enabled; bool interrupt_requested; pthread_cond_t* current_cond; thread_data_base(): done(false),join_started(false),joined(false), - thread_exit_callbacks(0),tss_data(0), + thread_exit_callbacks(0), interrupt_enabled(true), interrupt_requested(false), current_cond(0) diff --git a/include/boost/thread/tss.hpp b/include/boost/thread/tss.hpp index 73248239..e38e3e96 100644 --- a/include/boost/thread/tss.hpp +++ b/include/boost/thread/tss.hpp @@ -1,111 +1,111 @@ -#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 -#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 +#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 +#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() + { + detail::set_tss_data(this,boost::shared_ptr(),0,true); + } + + 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/src/pthread/exceptions.cpp b/src/pthread/exceptions.cpp deleted file mode 100644 index 88813036..00000000 --- a/src/pthread/exceptions.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (C) 2001-2003 -// William E. Kempf -// -// 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) - -#include - -#include -#include -#include - -namespace boost { - -thread_exception::thread_exception() - : m_sys_err(0) -{ -} - -thread_exception::thread_exception(int sys_err_code) - : m_sys_err(sys_err_code) -{ -} - -thread_exception::~thread_exception() throw() -{ -} - -int thread_exception::native_error() const -{ - return m_sys_err; -} - -lock_error::lock_error() -{ -} - -lock_error::lock_error(int sys_err_code) - : thread_exception(sys_err_code) -{ -} - -lock_error::~lock_error() throw() -{ -} - -const char* lock_error::what() const throw() -{ - return "boost::lock_error"; -} - -thread_resource_error::thread_resource_error() -{ -} - -thread_resource_error::thread_resource_error(int sys_err_code) - : thread_exception(sys_err_code) -{ -} - -thread_resource_error::~thread_resource_error() throw() -{ -} - -const char* thread_resource_error::what() const throw() -{ - return "boost::thread_resource_error"; -} - -unsupported_thread_option::unsupported_thread_option() -{ -} - -unsupported_thread_option::unsupported_thread_option(int sys_err_code) - : thread_exception(sys_err_code) -{ -} - -unsupported_thread_option::~unsupported_thread_option() throw() -{ -} - -const char* unsupported_thread_option::what() const throw() -{ - return "boost::unsupported_thread_option"; -} - -invalid_thread_argument::invalid_thread_argument() -{ -} - -invalid_thread_argument::invalid_thread_argument(int sys_err_code) - : thread_exception(sys_err_code) -{ -} - -invalid_thread_argument::~invalid_thread_argument() throw() -{ -} - -const char* invalid_thread_argument::what() const throw() -{ - return "boost::invalid_thread_argument"; -} - -thread_permission_error::thread_permission_error() -{ -} - -thread_permission_error::thread_permission_error(int sys_err_code) - : thread_exception(sys_err_code) -{ -} - -thread_permission_error::~thread_permission_error() throw() -{ -} - -const char* thread_permission_error::what() const throw() -{ - return "boost::thread_permission_error"; -} - -} // namespace boost diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index cc71d97b..3a5ce7cd 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -42,19 +42,6 @@ namespace boost {} }; - struct tss_data_node - { - void const* key; - boost::shared_ptr func; - void* value; - tss_data_node* next; - - tss_data_node(void const* key_,boost::shared_ptr func_,void* value_, - tss_data_node* next_): - key(key_),func(func_),value(value_),next(next_) - {} - }; - namespace { boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT; @@ -67,7 +54,7 @@ namespace boost boost::detail::thread_data_base* thread_info=static_cast(data); if(thread_info) { - while(thread_info->tss_data || thread_info->thread_exit_callbacks) + while(!thread_info->tss_data.empty() || thread_info->thread_exit_callbacks) { while(thread_info->thread_exit_callbacks) { @@ -80,15 +67,18 @@ namespace boost } delete current_node; } - while(thread_info->tss_data) + for(std::map::iterator next=thread_info->tss_data.begin(), + current, + end=thread_info->tss_data.end(); + next!=end;) { - detail::tss_data_node* const current_node=thread_info->tss_data; - thread_info->tss_data=current_node->next; - if(current_node->func) + current=next; + ++next; + if(current->second.func && current->second.value) { - (*current_node->func)(current_node->value); + (*current->second.func)(current->second.value); } - delete current_node; + thread_info->tss_data.erase(current); } } thread_info->self.reset(); @@ -390,7 +380,7 @@ namespace boost { #if defined(PTW32_VERSION) || defined(__hpux) return pthread_num_processors_np(); -#elif defined(__linux__) +#elif defined(_GNU_SOURCE) return get_nprocs(); #elif defined(__APPLE__) || defined(__FreeBSD__) int count; @@ -552,14 +542,11 @@ namespace boost detail::thread_data_base* const current_thread_data(get_current_thread_data()); if(current_thread_data) { - detail::tss_data_node* current_node=current_thread_data->tss_data; - while(current_node) + std::map::iterator current_node= + current_thread_data->tss_data.find(key); + if(current_node!=current_thread_data->tss_data.end()) { - if(current_node->key==key) - { - return current_node; - } - current_node=current_node->next; + return ¤t_node->second; } } return NULL; @@ -573,106 +560,47 @@ namespace boost } return NULL; } + + void add_new_tss_node(void const* key, + boost::shared_ptr func, + void* tss_data) + { + detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); + current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(func,tss_data))); + } + + void erase_tss_node(void const* key) + { + detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); + current_thread_data->tss_data.erase(key); + } - void set_tss_data(void const* key,boost::shared_ptr func,void* tss_data,bool cleanup_existing) + void set_tss_data(void const* key, + boost::shared_ptr func, + void* tss_data,bool cleanup_existing) { if(tss_data_node* const current_node=find_tss_data(key)) { - if(cleanup_existing && current_node->func) + if(cleanup_existing && current_node->func && current_node->value) { (*current_node->func)(current_node->value); } - current_node->func=func; - current_node->value=tss_data; + if(func || tss_data) + { + current_node->func=func; + current_node->value=tss_data; + } + else + { + erase_tss_node(key); + } } else { - detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); - tss_data_node* const new_node=new tss_data_node(key,func,tss_data,current_thread_data->tss_data); - current_thread_data->tss_data=new_node; + add_new_tss_node(key,func,tss_data); } } } -// thread_group::thread_group() -// { -// } - -// thread_group::~thread_group() -// { -// // We shouldn't have to scoped_lock here, since referencing this object -// // from another thread while we're deleting it in the current thread is -// // going to lead to undefined behavior any way. -// for (std::list::iterator it = m_threads.begin(); -// it != m_threads.end(); ++it) -// { -// delete (*it); -// } -// } - -// thread* thread_group::create_thread(const function0& threadfunc) -// { -// // No scoped_lock required here since the only "shared data" that's -// // modified here occurs inside add_thread which does scoped_lock. -// std::auto_ptr thrd(new thread(threadfunc)); -// add_thread(thrd.get()); -// return thrd.release(); -// } - -// void thread_group::add_thread(thread* thrd) -// { -// mutex::scoped_lock scoped_lock(m_mutex); - -// // For now we'll simply ignore requests to add a thread object multiple -// // times. Should we consider this an error and either throw or return an -// // error value? -// std::list::iterator it = std::find(m_threads.begin(), -// m_threads.end(), thrd); -// BOOST_ASSERT(it == m_threads.end()); -// if (it == m_threads.end()) -// m_threads.push_back(thrd); -// } - -// void thread_group::remove_thread(thread* thrd) -// { -// mutex::scoped_lock scoped_lock(m_mutex); - -// // For now we'll simply ignore requests to remove a thread object that's -// // not in the group. Should we consider this an error and either throw or -// // return an error value? -// std::list::iterator it = std::find(m_threads.begin(), -// m_threads.end(), thrd); -// BOOST_ASSERT(it != m_threads.end()); -// if (it != m_threads.end()) -// m_threads.erase(it); -// } - -// void thread_group::join_all() -// { -// mutex::scoped_lock scoped_lock(m_mutex); -// for (std::list::iterator it = m_threads.begin(); -// it != m_threads.end(); ++it) -// { -// (*it)->join(); -// } -// } - -// void thread_group::interrupt_all() -// { -// boost::lock_guard guard(m_mutex); - -// for(std::list::iterator it=m_threads.begin(),end=m_threads.end(); -// it!=end; -// ++it) -// { -// (*it)->interrupt(); -// } -// } - - -// size_t thread_group::size() const -// { -// return m_threads.size(); -// } } diff --git a/src/win32/exceptions.cpp b/src/win32/exceptions.cpp deleted file mode 100644 index 88813036..00000000 --- a/src/win32/exceptions.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (C) 2001-2003 -// William E. Kempf -// -// 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) - -#include - -#include -#include -#include - -namespace boost { - -thread_exception::thread_exception() - : m_sys_err(0) -{ -} - -thread_exception::thread_exception(int sys_err_code) - : m_sys_err(sys_err_code) -{ -} - -thread_exception::~thread_exception() throw() -{ -} - -int thread_exception::native_error() const -{ - return m_sys_err; -} - -lock_error::lock_error() -{ -} - -lock_error::lock_error(int sys_err_code) - : thread_exception(sys_err_code) -{ -} - -lock_error::~lock_error() throw() -{ -} - -const char* lock_error::what() const throw() -{ - return "boost::lock_error"; -} - -thread_resource_error::thread_resource_error() -{ -} - -thread_resource_error::thread_resource_error(int sys_err_code) - : thread_exception(sys_err_code) -{ -} - -thread_resource_error::~thread_resource_error() throw() -{ -} - -const char* thread_resource_error::what() const throw() -{ - return "boost::thread_resource_error"; -} - -unsupported_thread_option::unsupported_thread_option() -{ -} - -unsupported_thread_option::unsupported_thread_option(int sys_err_code) - : thread_exception(sys_err_code) -{ -} - -unsupported_thread_option::~unsupported_thread_option() throw() -{ -} - -const char* unsupported_thread_option::what() const throw() -{ - return "boost::unsupported_thread_option"; -} - -invalid_thread_argument::invalid_thread_argument() -{ -} - -invalid_thread_argument::invalid_thread_argument(int sys_err_code) - : thread_exception(sys_err_code) -{ -} - -invalid_thread_argument::~invalid_thread_argument() throw() -{ -} - -const char* invalid_thread_argument::what() const throw() -{ - return "boost::invalid_thread_argument"; -} - -thread_permission_error::thread_permission_error() -{ -} - -thread_permission_error::thread_permission_error(int sys_err_code) - : thread_exception(sys_err_code) -{ -} - -thread_permission_error::~thread_permission_error() throw() -{ -} - -const char* thread_permission_error::what() const throw() -{ - return "boost::thread_permission_error"; -} - -} // namespace boost diff --git a/src/win32/thread.cpp b/src/win32/thread.cpp index a72f0538..46af8600 100644 --- a/src/win32/thread.cpp +++ b/src/win32/thread.cpp @@ -561,7 +561,7 @@ namespace boost { if(tss_data_node* const current_node=find_tss_data(key)) { - if(cleanup_existing && current_node->func.get()) + if(cleanup_existing && current_node->func.get() && current_node->value) { (*current_node->func)(current_node->value); } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index a6a769cb..de7231ba 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -38,6 +38,8 @@ rule thread-run ( sources ) [ thread-run test_thread_id.cpp ] [ thread-run test_hardware_concurrency.cpp ] [ thread-run test_thread_move.cpp ] + [ thread-run test_thread_return_local.cpp ] + [ thread-run test_thread_move_return.cpp ] [ thread-run test_thread_launching.cpp ] [ thread-run test_thread_mf.cpp ] [ thread-run test_move_function.cpp ] diff --git a/test/test_thread_move.cpp b/test/test_thread_move.cpp index 550b62dd..b0acc3ac 100644 --- a/test/test_thread_move.cpp +++ b/test/test_thread_move.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2007 Anthony Williams +// Copyright (C) 2007-9 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) @@ -33,21 +33,6 @@ void test_move_from_function_return() BOOST_CHECK_EQUAL(the_id,x_id); } -boost::thread make_thread_return_lvalue(boost::thread::id* the_id) -{ - boost::thread t(do_nothing,the_id); - return boost::move(t); -} - -void test_move_from_function_return_lvalue() -{ - boost::thread::id the_id; - boost::thread x=make_thread_return_lvalue(&the_id); - boost::thread::id x_id=x.get_id(); - x.join(); - BOOST_CHECK_EQUAL(the_id,x_id); -} - void test_move_assign() { boost::thread::id the_id; @@ -66,7 +51,6 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(test_move_on_construction)); test->add(BOOST_TEST_CASE(test_move_from_function_return)); - test->add(BOOST_TEST_CASE(test_move_from_function_return_lvalue)); test->add(BOOST_TEST_CASE(test_move_assign)); return test; } diff --git a/test/test_thread_move_return.cpp b/test/test_thread_move_return.cpp new file mode 100644 index 00000000..1146df59 --- /dev/null +++ b/test/test_thread_move_return.cpp @@ -0,0 +1,35 @@ +// Copyright (C) 2009 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) +#include +#include + +void do_nothing(boost::thread::id* my_id) +{ + *my_id=boost::this_thread::get_id(); +} + +boost::thread make_thread_move_return(boost::thread::id* the_id) +{ + boost::thread t(do_nothing,the_id); + return boost::move(t); +} + +void test_move_from_function_move_return() +{ + boost::thread::id the_id; + boost::thread x=make_thread_move_return(&the_id); + boost::thread::id x_id=x.get_id(); + x.join(); + BOOST_CHECK_EQUAL(the_id,x_id); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: thread move test suite"); + + test->add(BOOST_TEST_CASE(test_move_from_function_move_return)); + return test; +} diff --git a/test/test_thread_return_local.cpp b/test/test_thread_return_local.cpp new file mode 100644 index 00000000..f2f9c078 --- /dev/null +++ b/test/test_thread_return_local.cpp @@ -0,0 +1,35 @@ +// Copyright (C) 2009 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) +#include +#include + +void do_nothing(boost::thread::id* my_id) +{ + *my_id=boost::this_thread::get_id(); +} + +boost::thread make_thread_return_local(boost::thread::id* the_id) +{ + boost::thread t(do_nothing,the_id); + return t; +} + +void test_move_from_function_return_local() +{ + boost::thread::id the_id; + boost::thread x=make_thread_return_local(&the_id); + boost::thread::id x_id=x.get_id(); + x.join(); + BOOST_CHECK_EQUAL(the_id,x_id); +} + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: thread move test suite"); + + test->add(BOOST_TEST_CASE(test_move_from_function_return_local)); + return test; +} diff --git a/test/test_tss.cpp b/test/test_tss.cpp index 8a6545ce..1423d7f1 100644 --- a/test/test_tss.cpp +++ b/test/test_tss.cpp @@ -310,6 +310,39 @@ void test_tss_does_no_cleanup_with_null_cleanup_function() timed_test(&do_test_tss_does_no_cleanup_with_null_cleanup_function, 2); } +void thread_with_local_tss_ptr() +{ + { + boost::thread_specific_ptr local_tss(tss_custom_cleanup); + + local_tss.reset(new Dummy); + } + BOOST_CHECK(tss_cleanup_called); + tss_cleanup_called=false; +} + + +void test_tss_does_not_call_cleanup_after_ptr_destroyed() +{ + boost::thread t(thread_with_local_tss_ptr); + t.join(); + BOOST_CHECK(!tss_cleanup_called); +} + +void test_tss_cleanup_not_called_for_null_pointer() +{ + boost::thread_specific_ptr local_tss(tss_custom_cleanup); + local_tss.reset(new Dummy); + tss_cleanup_called=false; + local_tss.reset(0); + BOOST_CHECK(tss_cleanup_called); + tss_cleanup_called=false; + local_tss.reset(new Dummy); + BOOST_CHECK(!tss_cleanup_called); +} + + + boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { boost::unit_test_framework::test_suite* test = @@ -319,6 +352,8 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) 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)); + test->add(BOOST_TEST_CASE(test_tss_does_not_call_cleanup_after_ptr_destroyed)); + test->add(BOOST_TEST_CASE(test_tss_cleanup_not_called_for_null_pointer)); return test; }