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