diff --git a/build/.cvsignore b/build/.cvsignore deleted file mode 100644 index 76bf5bcd..00000000 --- a/build/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -bin* -*.pdb diff --git a/example/.cvsignore b/example/.cvsignore deleted file mode 100644 index cdbfc82a..00000000 --- a/example/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -bin -*.pdb diff --git a/include/boost/thread/pthread/thread.hpp b/include/boost/thread/pthread/thread.hpp index db4eb974..d86e3465 100644 --- a/include/boost/thread/pthread/thread.hpp +++ b/include/boost/thread/pthread/thread.hpp @@ -277,6 +277,7 @@ namespace boost void add_thread(thread* thrd); void remove_thread(thread* thrd); void join_all(); + void interrupt_all(); int size() const; private: diff --git a/include/boost/thread/pthread/tss.hpp b/include/boost/thread/pthread/tss.hpp new file mode 100644 index 00000000..462d6304 --- /dev/null +++ b/include/boost/thread/pthread/tss.hpp @@ -0,0 +1,109 @@ +#ifndef BOOST_THREAD_PTHREAD_TSS_HPP +#define BOOST_THREAD_PTHREAD_TSS_HPP + +// Copyright (C) 2001-2003 William E. Kempf +// Copyright (C) 2006 Roland Schwarz +// 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) + +#include +#include +#include +#include + +#include + +namespace boost { + +// disable warnings about non dll import +// see: http://www.boost.org/more/separate_compilation.html#dlls +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4251 4231 4660 4275) +#endif + +namespace detail { + +class BOOST_THREAD_DECL tss : private noncopyable +{ +public: + tss(boost::function1* pcleanup) { + if (pcleanup == 0) throw boost::thread_resource_error(); + try + { + init(pcleanup); + } + catch (...) + { + delete pcleanup; + throw boost::thread_resource_error(); + } + } + + ~tss(); + void* get() const; + void set(void* value); + void cleanup(void* p); + +private: + unsigned int m_slot; //This is a "pseudo-slot", not a native slot + + void init(boost::function1* pcleanup); +}; + +template +struct tss_adapter +{ + template + tss_adapter(const F& cleanup) : m_cleanup(cleanup) { } + void operator()(void* p) { m_cleanup(static_cast(p)); } + boost::function1 m_cleanup; +}; + +} // namespace detail + +template +class thread_specific_ptr : private noncopyable +{ +public: + thread_specific_ptr() + : m_tss(new boost::function1( + boost::detail::tss_adapter( + &thread_specific_ptr::cleanup))) + { + } + thread_specific_ptr(void (*clean)(T*)) + : m_tss(new boost::function1( + boost::detail::tss_adapter(clean))) + { + } + ~thread_specific_ptr() { reset(); } + + T* get() const { return static_cast(m_tss.get()); } + T* operator->() const { return get(); } + T& operator*() const { return *get(); } + T* release() { T* temp = get(); if (temp) m_tss.set(0); return temp; } + void reset(T* p=0) + { + T* cur = get(); + if (cur == p) return; + m_tss.set(p); + if (cur) m_tss.cleanup(cur); + } + +private: + static void cleanup(T* p) { delete p; } + detail::tss m_tss; +}; + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +} // namespace boost + + + +#endif diff --git a/include/boost/thread/tss.hpp b/include/boost/thread/tss.hpp index 1870324c..787700f5 100644 --- a/include/boost/thread/tss.hpp +++ b/include/boost/thread/tss.hpp @@ -1,130 +1,12 @@ -// Copyright (C) 2001-2003 William E. Kempf -// Copyright (C) 2006 Roland Schwarz // 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_TSS_WEK070601_HPP -#define BOOST_TSS_WEK070601_HPP +#ifndef BOOST_THREAD_TSS_HPP +#define BOOST_THREAD_TSS_HPP -#include - -#ifdef BOOST_HAS_WINTHREADS #include #include BOOST_THREAD_PLATFORM(tss.hpp) -#else - -#include -#include -#include - -#if defined(BOOST_HAS_PTHREADS) -# include -#endif - -namespace boost { - -// disable warnings about non dll import -// see: http://www.boost.org/more/separate_compilation.html#dlls -#ifdef BOOST_MSVC -# pragma warning(push) -# pragma warning(disable: 4251 4231 4660 4275) -#endif - -namespace detail { - -class BOOST_THREAD_DECL tss : private noncopyable -{ -public: - tss(boost::function1* pcleanup) { - if (pcleanup == 0) throw boost::thread_resource_error(); - try - { - init(pcleanup); - } - catch (...) - { - delete pcleanup; - throw boost::thread_resource_error(); - } - } - - ~tss(); - void* get() const; - void set(void* value); - void cleanup(void* p); - -private: - unsigned int m_slot; //This is a "pseudo-slot", not a native slot - - void init(boost::function1* pcleanup); -}; - -template -struct tss_adapter -{ - template - tss_adapter(const F& cleanup) : m_cleanup(cleanup) { } - void operator()(void* p) { m_cleanup(static_cast(p)); } - boost::function1 m_cleanup; -}; - -} // namespace detail - -template -class thread_specific_ptr : private noncopyable -{ -public: - thread_specific_ptr() - : m_tss(new boost::function1( - boost::detail::tss_adapter( - &thread_specific_ptr::cleanup))) - { - } - thread_specific_ptr(void (*clean)(T*)) - : m_tss(new boost::function1( - boost::detail::tss_adapter(clean))) - { - } - ~thread_specific_ptr() { reset(); } - - T* get() const { return static_cast(m_tss.get()); } - T* operator->() const { return get(); } - T& operator*() const { return *get(); } - T* release() { T* temp = get(); if (temp) m_tss.set(0); return temp; } - void reset(T* p=0) - { - T* cur = get(); - if (cur == p) return; - m_tss.set(p); - if (cur) m_tss.cleanup(cur); - } - -private: - static void cleanup(T* p) { delete p; } - detail::tss m_tss; -}; - -#ifdef BOOST_MSVC -# pragma warning(pop) -#endif - -} // namespace boost #endif - -#endif //BOOST_TSS_WEK070601_HPP - -// Change Log: -// 6 Jun 01 -// WEKEMPF Initial version. -// 30 May 02 WEKEMPF -// Added interface to set specific cleanup handlers. -// Removed TLS slot limits from most implementations. -// 22 Mar 04 GlassfordM for WEKEMPF -// Fixed: thread_specific_ptr::reset() doesn't check error returned -// by tss::set(); tss::set() now throws if it fails. -// Fixed: calling thread_specific_ptr::reset() or -// thread_specific_ptr::release() causes double-delete: once on -// reset()/release() and once on ~thread_specific_ptr(). diff --git a/include/boost/thread/win32/thread.hpp b/include/boost/thread/win32/thread.hpp index 1e237791..eab05119 100644 --- a/include/boost/thread/win32/thread.hpp +++ b/include/boost/thread/win32/thread.hpp @@ -429,6 +429,18 @@ namespace boost } } + void interrupt_all() + { + boost::lock_guard guard(m); + + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + (*it)->interrupt(); + } + } + int size() const { boost::lock_guard guard(m); diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index 87a565ae..1d8370de 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -491,6 +491,19 @@ namespace boost } } + 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(); + } + } + + int thread_group::size() const { return m_threads.size(); diff --git a/test/.cvsignore b/test/.cvsignore deleted file mode 100644 index cdbfc82a..00000000 --- a/test/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -bin -*.pdb diff --git a/test/test_barrier.cpp b/test/test_barrier.cpp index b6982966..bccd346f 100644 --- a/test/test_barrier.cpp +++ b/test/test_barrier.cpp @@ -10,6 +10,7 @@ #include #include +#include namespace { @@ -38,11 +39,19 @@ void test_barrier() boost::thread_group g; global_parameter = 0; - for (int i = 0; i < N_THREADS; ++i) - g.create_thread(&barrier_thread); - - g.join_all(); - + try + { + for (int i = 0; i < N_THREADS; ++i) + g.create_thread(&barrier_thread); + g.join_all(); + } + catch(...) + { + g.interrupt_all(); + g.join_all(); + throw; + } + BOOST_CHECK(global_parameter == 5); } diff --git a/test/test_condition.cpp b/test/test_condition.cpp index b827be2c..2dbe32d0 100644 --- a/test/test_condition.cpp +++ b/test/test_condition.cpp @@ -112,17 +112,27 @@ void do_test_condition_notify_all() boost::thread_group threads; condition_test_data data; - for (int i = 0; i < NUMTHREADS; ++i) - threads.create_thread(bind(&condition_test_thread, &data)); - + try { - boost::mutex::scoped_lock lock(data.mutex); - BOOST_CHECK(lock ? true : false); - data.notified++; - data.condition.notify_all(); + for (int i = 0; i < NUMTHREADS; ++i) + threads.create_thread(bind(&condition_test_thread, &data)); + + { + boost::mutex::scoped_lock lock(data.mutex); + BOOST_CHECK(lock ? true : false); + data.notified++; + data.condition.notify_all(); + } + + threads.join_all(); + } + catch(...) + { + threads.interrupt_all(); + threads.join_all(); + throw; } - threads.join_all(); BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS); } diff --git a/test/test_once.cpp b/test/test_once.cpp index fe79cef9..634b4fd7 100644 --- a/test/test_once.cpp +++ b/test/test_once.cpp @@ -40,12 +40,22 @@ void test_call_once() { unsigned const num_threads=20; boost::thread_group group; - - for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, - finish_mutex,simultaneous_running_count,max_simultaneous_running)); - } + try { - boost::mutex::scoped_lock lk(unblocked_count_mutex); - while(unblocked_count >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); } + + { + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_count >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, - finish_mutex,simultaneous_running_count,max_simultaneous_running)); + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + + boost::thread::sleep(delay(2)); + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + + finish_lock.unlock(); + + pool.join_all(); + } + catch(...) + { + pool.interrupt_all(); + pool.join_all(); + throw; } - - boost::thread::sleep(delay(2)); - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); - - finish_lock.unlock(); - - pool.join_all(); CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads); CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); @@ -162,24 +180,34 @@ void test_reader_blocks_writer() boost::mutex finish_mutex; boost::mutex::scoped_lock finish_lock(finish_mutex); - pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, - finish_mutex,simultaneous_running_count,max_simultaneous_running)); + try { - boost::mutex::scoped_lock lk(unblocked_count_mutex); - while(unblocked_count<1) + + pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); { - unblocked_condition.wait(lk); + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_count<1) + { + unblocked_condition.wait(lk); + } } + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + + finish_lock.unlock(); + + pool.join_all(); + } + catch(...) + { + pool.interrupt_all(); + pool.join_all(); + throw; } - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); - pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, - finish_mutex,simultaneous_running_count,max_simultaneous_running)); - boost::thread::sleep(delay(1)); - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); - - finish_lock.unlock(); - - pool.join_all(); CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,2U); CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); @@ -201,28 +229,38 @@ void test_unlocking_writer_unblocks_all_readers() unsigned const reader_count=100; - for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, - finish_mutex,simultaneous_running_count,max_simultaneous_running)); - } - boost::thread::sleep(delay(1)); - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,0U); - - write_lock.unlock(); - - { - boost::mutex::scoped_lock lk(unblocked_count_mutex); - while(unblocked_count >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); } + boost::thread::sleep(delay(1)); + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,0U); + + write_lock.unlock(); + + { + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_count >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, - finish_reading_mutex,simultaneous_running_readers,max_simultaneous_readers)); - } - boost::thread::sleep(delay(1)); - for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, - finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers)); - } - { - boost::mutex::scoped_lock lk(unblocked_count_mutex); - while(unblocked_count >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_reading_mutex,simultaneous_running_readers,max_simultaneous_readers)); } - } - boost::thread::sleep(delay(1)); - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count); - - finish_reading_lock.unlock(); - - { - boost::mutex::scoped_lock lk(unblocked_count_mutex); - while(unblocked_count<(reader_count+1)) + boost::thread::sleep(delay(1)); + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers)); } - } - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1); + { + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_count >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, - finish_mutex,simultaneous_running_count,max_simultaneous_running)); + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + } + + boost::thread::sleep(delay(1)); + + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); + + finish_lock.unlock(); + + pool.join_all(); + } + catch(...) + { + pool.interrupt_all(); + pool.join_all(); + throw; } - - boost::thread::sleep(delay(1)); - - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U); - - finish_lock.unlock(); - - pool.join_all(); CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads); CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u); @@ -333,25 +391,36 @@ void test_can_lock_upgrade_if_currently_locked_shared() unsigned const reader_count=100; - for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, - finish_mutex,simultaneous_running_count,max_simultaneous_running)); - } - boost::thread::sleep(delay(1)); - pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, - finish_mutex,simultaneous_running_count,max_simultaneous_running)); - { - boost::mutex::scoped_lock lk(unblocked_count_mutex); - while(unblocked_count<(reader_count+1)) + for(unsigned i=0;i >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); } - } - CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1); + boost::thread::sleep(delay(1)); + pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, + finish_mutex,simultaneous_running_count,max_simultaneous_running)); + { + boost::mutex::scoped_lock lk(unblocked_count_mutex); + while(unblocked_count<(reader_count+1)) + { + unblocked_condition.wait(lk); + } + } + CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1); + + finish_lock.unlock(); + pool.join_all(); + } + catch(...) + { + pool.interrupt_all(); + pool.join_all(); + throw; + } + - finish_lock.unlock(); - pool.join_all(); CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1); CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1); } diff --git a/test/test_tss.cpp b/test/test_tss.cpp index 6ed570f1..7c166648 100644 --- a/test/test_tss.cpp +++ b/test/test_tss.cpp @@ -100,9 +100,19 @@ void do_test_tss() const int NUMTHREADS=5; boost::thread_group threads; - for (int i=0; i