1 //Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc.
2
3 //Distributed under the Boost Software License, Version 1.0. (See accompanying
4 //file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 #include <boost/config.hpp>
7
8 #if defined( BOOST_NO_EXCEPTIONS )
9 # error This program requires exception handling.
10 #endif
11
12 #include <boost/exception_ptr.hpp>
13 #include <boost/exception/info.hpp>
14 #include <boost/exception/get_error_info.hpp>
15 #include <boost/exception/diagnostic_information.hpp>
16 #include <boost/function.hpp>
17 #include <boost/bind.hpp>
18 #include <boost/thread.hpp>
19 #include <boost/detail/atomic_count.hpp>
20 #include <boost/detail/lightweight_test.hpp>
21 #include <iostream>
22
23 class thread_handle;
24 boost::shared_ptr<thread_handle> create_thread( boost::function<void()> const & f );
25 void join( thread_handle & t );
26
27 class
28 thread_handle
29 {
30 thread_handle( thread_handle const & );
31 thread_handle & operator=( thread_handle const & );
32
33 boost::exception_ptr err_;
34 boost::thread t_;
35
36 static
37 void
thread_wrapper(boost::function<void ()> const & f,boost::exception_ptr & ep)38 thread_wrapper( boost::function<void()> const & f, boost::exception_ptr & ep )
39 {
40 BOOST_ASSERT(!ep);
41 try
42 {
43 f();
44 }
45 catch(...)
46 {
47 ep = boost::current_exception();
48 }
49 }
50
51 explicit
thread_handle(boost::function<void ()> const & f)52 thread_handle( boost::function<void()> const & f ):
53 t_(boost::bind(thread_wrapper,f,boost::ref(err_)))
54 {
55 }
56
57 friend boost::shared_ptr<thread_handle> create_thread( boost::function<void()> const & f );
58 friend void join( thread_handle & t );
59 };
60
61 boost::shared_ptr<thread_handle>
create_thread(boost::function<void ()> const & f)62 create_thread( boost::function<void()> const & f )
63 {
64 boost::shared_ptr<thread_handle> t( new thread_handle(f) );
65 return t;
66 }
67
68 void
join(thread_handle & t)69 join( thread_handle & t )
70 {
71 t.t_.join();
72 assert(t.err_);
73 rethrow_exception(t.err_);
74 }
75
76 boost::detail::atomic_count exc_count(0);
77
78 struct
79 exc:
80 virtual boost::exception,
81 virtual std::exception
82 {
excexc83 exc()
84 {
85 ++exc_count;
86 }
87
excexc88 exc( exc const & e ):
89 boost::exception(e),
90 std::exception(e)
91 {
92 ++exc_count;
93 }
94
95 virtual
~excexc96 ~exc() BOOST_NOEXCEPT_OR_NOTHROW
97 {
98 --exc_count;
99 }
100
101 private:
102
103 exc & operator=( exc const & );
104 };
105
106 typedef boost::error_info<struct answer_,int> answer;
107
108 void
thread_func()109 thread_func()
110 {
111 BOOST_THROW_EXCEPTION(exc() << answer(42));
112 }
113
114 void
check(boost::shared_ptr<thread_handle> const & t)115 check( boost::shared_ptr<thread_handle> const & t )
116 {
117 try
118 {
119 join(*t);
120 BOOST_TEST(false);
121 }
122 catch(
123 exc & e )
124 {
125 int const * a = boost::get_error_info<answer>(e);
126 BOOST_TEST(a && *a==42);
127 }
128 }
129
130 void
test_deep_copy()131 test_deep_copy()
132 {
133 int const * p1=0;
134 boost::exception_ptr p;
135 try
136 {
137 BOOST_THROW_EXCEPTION(exc() << answer(42));
138 BOOST_ERROR("BOOST_THROW_EXCEPTION didn't throw");
139 }
140 catch(
141 exc & e )
142 {
143 p1=boost::get_error_info<answer>(e);
144 p=boost::current_exception();
145 }
146 BOOST_TEST(p1!=0);
147 BOOST_TEST(p);
148 try
149 {
150 boost::rethrow_exception(p);
151 BOOST_ERROR("rethrow_exception didn't throw");
152 }
153 catch(
154 exc & e )
155 {
156 int const * p2=boost::get_error_info<answer>(e);
157 BOOST_TEST(p2!=0 && *p2==42);
158 BOOST_TEST(p2!=p1);
159 }
160 }
161
162 int
main()163 main()
164 {
165 test_deep_copy();
166 BOOST_TEST(++exc_count==1);
167 try
168 {
169 std::vector< boost::shared_ptr<thread_handle> > threads;
170 std::generate_n(std::inserter(threads,threads.end()),1,boost::bind(create_thread,thread_func));
171 std::for_each(threads.begin(),threads.end(),check);
172 return boost::report_errors();
173 }
174 catch(
175 ... )
176 {
177 std::cerr <<
178 "Caught unexpected exception.\n"
179 "Output from current_exception_diagnostic_information:\n" <<
180 boost::current_exception_diagnostic_information() << std::endl;
181 return 42;
182 }
183 BOOST_TEST(!--exc_count);
184 }
185