From 4ae002cbf855557f36657b0a4659a16ecee842bb Mon Sep 17 00:00:00 2001 From: Emil Dotchevski Date: Sat, 30 Jan 2010 05:26:43 +0000 Subject: [PATCH] Ticket #3848 (thanks Nikki Chumakov) and (unrelated) exception_ptr refactoring. [SVN r59364] --- .../boost/exception/detail/exception_ptr.hpp | 129 ++++++------------ .../exception/errinfo_nested_exception.hpp | 4 +- include/boost/exception/exception.hpp | 12 +- include/boost/exception/info.hpp | 8 ++ test/Jamfile.v2 | 2 +- test/copy_exception_test.cpp | 100 +++++++++++++- test/exception_ptr_test.cpp | 128 ++++++++--------- 7 files changed, 224 insertions(+), 159 deletions(-) diff --git a/include/boost/exception/detail/exception_ptr.hpp b/include/boost/exception/detail/exception_ptr.hpp index 78db17c..0179082 100644 --- a/include/boost/exception/detail/exception_ptr.hpp +++ b/include/boost/exception/detail/exception_ptr.hpp @@ -28,6 +28,8 @@ namespace boost { + typedef shared_ptr exception_ptr; + #ifndef BOOST_NO_RTTI typedef error_info original_exception_type; @@ -39,85 +41,34 @@ boost } #endif - class exception_ptr; - exception_ptr current_exception(); - void rethrow_exception( exception_ptr const & ); - - class - exception_ptr + namespace + exception_detail { - typedef bool exception_ptr::*unspecified_bool_type; - friend exception_ptr current_exception(); - friend void rethrow_exception( exception_ptr const & ); - - shared_ptr c_; - bool bad_alloc_; - - struct - bad_alloc_tag - { - }; - - explicit - exception_ptr( bad_alloc_tag ): - bad_alloc_(true) + inline + static + exception_ptr + exception_ptr_bad_alloc() { + static + struct + bad_alloc_: + std::bad_alloc, + exception_detail::clone_base + { + clone_base const * + clone() const + { + return new bad_alloc_(*this); + } + void + rethrow() const + { + throw*this; + } + } e; + return exception_ptr(exception_ptr(),&e); } - - explicit - exception_ptr( shared_ptr const & c ): - c_(c), - bad_alloc_(false) - { - BOOST_ASSERT(c); - } - - void - rethrow() const - { - BOOST_ASSERT(*this); - if( bad_alloc_ ) - throw enable_current_exception(std::bad_alloc()); - else - c_->rethrow(); - } - - bool - empty() const - { - return !bad_alloc_ && !c_; - } - - public: - - exception_ptr(): - bad_alloc_(false) - { - } - - ~exception_ptr() throw() - { - } - - operator unspecified_bool_type() const - { - return empty() ? 0 : &exception_ptr::bad_alloc_; - } - - friend - bool - operator==( exception_ptr const & a, exception_ptr const & b ) - { - return a.c_==b.c_ && a.bad_alloc_==b.bad_alloc_; - } - - friend - bool - operator!=( exception_ptr const & a, exception_ptr const & b ) - { - return !(a==b); - } - }; + } class unknown_exception: @@ -256,7 +207,7 @@ boost template inline - shared_ptr + exception_ptr current_exception_std_exception( T const & e1 ) { if( boost::exception const * e2 = get_boost_exception(&e1) ) @@ -266,21 +217,21 @@ boost } inline - shared_ptr + exception_ptr current_exception_unknown_exception() { return shared_ptr(new unknown_exception()); } inline - shared_ptr + exception_ptr current_exception_unknown_boost_exception( boost::exception const & e ) { return shared_ptr(new unknown_exception(e)); } inline - shared_ptr + exception_ptr current_exception_unknown_std_exception( std::exception const & e ) { if( boost::exception const * be = get_boost_exception(&e) ) @@ -290,7 +241,7 @@ boost } inline - shared_ptr + exception_ptr current_exception_impl() { try @@ -300,7 +251,7 @@ boost catch( exception_detail::clone_base & e ) { - return shared_ptr(e.clone()); + return exception_ptr(e.clone()); } catch( std::domain_error & e ) @@ -396,24 +347,28 @@ boost exception_ptr current_exception() { + exception_ptr ret; + BOOST_ASSERT(!ret); try { - return exception_ptr(exception_detail::current_exception_impl()); + ret=exception_detail::current_exception_impl(); } catch( std::bad_alloc & ) { + ret=exception_detail::exception_ptr_bad_alloc(); } catch( ... ) { try { - return exception_ptr(exception_detail::current_exception_std_exception(std::bad_exception())); + ret=exception_detail::current_exception_std_exception(std::bad_exception()); } catch( std::bad_alloc & ) { + ret=exception_detail::exception_ptr_bad_alloc(); } catch( ... ) @@ -421,7 +376,8 @@ boost BOOST_ASSERT(0); } } - return exception_ptr(exception_ptr::bad_alloc_tag()); + BOOST_ASSERT(ret); + return ret; } template @@ -444,7 +400,8 @@ boost void rethrow_exception( exception_ptr const & p ) { - p.rethrow(); + BOOST_ASSERT(p); + p->rethrow(); } inline diff --git a/include/boost/exception/errinfo_nested_exception.hpp b/include/boost/exception/errinfo_nested_exception.hpp index de055e0..e4e75d9 100644 --- a/include/boost/exception/errinfo_nested_exception.hpp +++ b/include/boost/exception/errinfo_nested_exception.hpp @@ -9,8 +9,10 @@ namespace boost { + namespace exception_detail { class clone_base; }; template class error_info; - class exception_ptr; + template class shared_ptr; + typedef shared_ptr exception_ptr; typedef error_info errinfo_nested_exception; } diff --git a/include/boost/exception/exception.hpp b/include/boost/exception/exception.hpp index 79b2739..bd86b76 100644 --- a/include/boost/exception/exception.hpp +++ b/include/boost/exception/exception.hpp @@ -163,6 +163,7 @@ boost virtual void set( shared_ptr const &, type_info_ const & ) = 0; virtual void add_ref() const = 0; virtual void release() const = 0; + virtual refcount_ptr clone() const = 0; protected: @@ -184,6 +185,8 @@ boost struct get_info; char const * get_diagnostic_information( exception const &, char const * ); + + void copy_boost_exception( exception *, exception const * ); } class @@ -240,6 +243,7 @@ boost friend struct exception_detail::get_info; friend struct exception_detail::get_info; friend struct exception_detail::get_info; + friend void exception_detail::copy_boost_exception( exception *, exception const * ); #endif mutable exception_detail::refcount_ptr data_; mutable char const * throw_function_; @@ -363,7 +367,13 @@ boost void copy_boost_exception( exception * a, exception const * b ) { - *a = *b; + refcount_ptr data; + if( error_info_container * d=b->data_.get() ) + data = d->clone(); + a->throw_file_ = b->throw_file_; + a->throw_line_ = b->throw_line_; + a->throw_function_ = b->throw_function_; + a->data_ = data; } inline diff --git a/include/boost/exception/info.hpp b/include/boost/exception/info.hpp index cbbc2c0..07207e2 100644 --- a/include/boost/exception/info.hpp +++ b/include/boost/exception/info.hpp @@ -143,6 +143,14 @@ boost if( !--count_ ) delete this; } + + refcount_ptr + clone() const + { + refcount_ptr c; + c.adopt(new exception_detail::error_info_container_impl(*this)); + return c; + } }; } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 9ed9bb2..0d45c2f 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -24,7 +24,7 @@ run 2-throw_exception_no_exceptions_test.cpp ; run 3-throw_exception_no_integration_test.cpp ; run 4-throw_exception_no_both_test.cpp ; run cloning_test.cpp ; -run copy_exception_test.cpp ; +run copy_exception_test.cpp /boost//thread : : : multi ; run unknown_exception_test.cpp ; run exception_test.cpp ; run enable_error_info_test.cpp helper1.cpp ; diff --git a/test/copy_exception_test.cpp b/test/copy_exception_test.cpp index 236a610..84974ce 100644 --- a/test/copy_exception_test.cpp +++ b/test/copy_exception_test.cpp @@ -4,25 +4,106 @@ //file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include +#include +#include #include +typedef boost::error_info answer; + struct -test_exception: - std::exception +err: + virtual boost::exception, + virtual std::exception { }; -int -main() +class +future { - boost::exception_ptr p = boost::copy_exception(test_exception()); + public: + + future (): + ready_ (false) + { + } + + void + set_exception( boost::exception_ptr const & e ) + { + boost::unique_lock lck (mux_); + exc_ = e; + ready_ = true; + cond_.notify_all(); + } + + void + get_exception() const + { + boost::unique_lock lck (mux_); + while (! ready_) + cond_.wait (lck); + rethrow_exception (exc_); + } + + private: + + bool ready_; + boost::exception_ptr exc_; + mutable boost::mutex mux_; + mutable boost::condition_variable cond_; + }; + +void +producer( future & f ) + { + f.set_exception (boost::copy_exception (err () << answer(42))); + } + +void +consumer() + { + future f; + boost::thread thr (boost::bind (&producer, boost::ref (f))); + try + { + f.get_exception (); + } + catch( + err & e ) + { + int const * ans=boost::get_error_info(e); + BOOST_TEST(ans && *ans==42); + } + thr.join(); + } + +void +consume() + { + for( int i=0; i!=100; ++i ) + consumer(); + } + +void +thread_test() + { + boost::thread_group grp; + for( int i=0; i!=50; ++i ) + grp.create_thread(&consume); + grp.join_all (); + } + +void +simple_test() + { + boost::exception_ptr p = boost::copy_exception(err()); try { rethrow_exception(p); BOOST_TEST(false); } catch( - test_exception & ) + err & ) { } catch( @@ -30,5 +111,12 @@ main() { BOOST_TEST(false); } + } + +int +main() + { + simple_test(); + thread_test(); return boost::report_errors(); } diff --git a/test/exception_ptr_test.cpp b/test/exception_ptr_test.cpp index cec02c3..994f2d4 100644 --- a/test/exception_ptr_test.cpp +++ b/test/exception_ptr_test.cpp @@ -18,91 +18,91 @@ void join( thread_handle & t ); class thread_handle - { - thread_handle( thread_handle const & ); - thread_handle & operator=( thread_handle const & ); + { + thread_handle( thread_handle const & ); + thread_handle & operator=( thread_handle const & ); - boost::exception_ptr err_; - boost::thread t_; + boost::exception_ptr err_; + boost::thread t_; - static - void - thread_wrapper( boost::function const & f, boost::exception_ptr & ep ) - { - BOOST_ASSERT(!ep); - try - { - f(); - } - catch(...) - { - ep = boost::current_exception(); - } - } + static + void + thread_wrapper( boost::function const & f, boost::exception_ptr & ep ) + { + BOOST_ASSERT(!ep); + try + { + f(); + } + catch(...) + { + ep = boost::current_exception(); + } + } - explicit - thread_handle( boost::function const & f ): - t_(boost::bind(thread_wrapper,f,err_)) - { - } + explicit + thread_handle( boost::function const & f ): + t_(boost::bind(thread_wrapper,f,err_)) + { + } - friend boost::shared_ptr create_thread( boost::function const & f ); - friend void join( thread_handle & t ); - }; + friend boost::shared_ptr create_thread( boost::function const & f ); + friend void join( thread_handle & t ); + }; boost::shared_ptr create_thread( boost::function const & f ) - { - boost::shared_ptr t( new thread_handle(f) ); - return t; - } + { + boost::shared_ptr t( new thread_handle(f) ); + return t; + } void join( thread_handle & t ) - { - t.t_.join(); - if( t.err_ ) - rethrow_exception(t.err_); - } + { + t.t_.join(); + if( t.err_ ) + rethrow_exception(t.err_); + } struct exc: boost::exception, std::exception { }; typedef boost::error_info answer; void thread_func() - { - BOOST_THROW_EXCEPTION(exc() << answer(42)); - } + { + BOOST_THROW_EXCEPTION(exc() << answer(42)); + } void check( boost::shared_ptr const & t ) - { - try - { - join(*t); - } - catch( - exc & e ) - { - int const * a = boost::get_error_info(e); - BOOST_TEST(a && *a==42); - } - } + { + try + { + join(*t); + } + catch( + exc & e ) + { + int const * a = boost::get_error_info(e); + BOOST_TEST(a && *a==42); + } + } int main() { - try - { - std::vector< boost::shared_ptr > threads; - std::generate_n(std::inserter(threads,threads.end()),256,boost::bind(create_thread,thread_func)); - std::for_each(threads.begin(),threads.end(),check); - return boost::report_errors(); - } - catch( - ... ) - { - BOOST_ERROR(boost::current_exception_diagnostic_information().c_str()); - return 42; - } + try + { + std::vector< boost::shared_ptr > threads; + std::generate_n(std::inserter(threads,threads.end()),256,boost::bind(create_thread,thread_func)); + std::for_each(threads.begin(),threads.end(),check); + return boost::report_errors(); + } + catch( + ... ) + { + BOOST_ERROR(boost::current_exception_diagnostic_information().c_str()); + return 42; + } }