• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/exception_ptr.hpp>
7 #include <boost/exception/info.hpp>
8 #include <boost/exception/get_error_info.hpp>
9 #include <boost/exception/diagnostic_information.hpp>
10 #include <boost/function.hpp>
11 #include <boost/bind.hpp>
12 #include <boost/thread.hpp>
13 #include <boost/detail/atomic_count.hpp>
14 #include <boost/detail/lightweight_test.hpp>
15 #include <iostream>
16 
17 class thread_handle;
18 boost::shared_ptr<thread_handle> create_thread( boost::function<void()> const & f );
19 void join( thread_handle & t );
20 
21 class
22 thread_handle
23     {
24     thread_handle( thread_handle const & );
25     thread_handle & operator=( thread_handle const & );
26 
27     boost::exception_ptr err_;
28     boost::thread t_;
29 
30     static
31     void
thread_wrapper(boost::function<void ()> const & f,boost::exception_ptr & ep)32     thread_wrapper( boost::function<void()> const & f, boost::exception_ptr & ep )
33         {
34         BOOST_ASSERT(!ep);
35         try
36             {
37             f();
38             }
39         catch(...)
40             {
41             ep = boost::current_exception();
42             }
43         }
44 
45     explicit
thread_handle(boost::function<void ()> const & f)46     thread_handle( boost::function<void()> const & f ):
47         t_(boost::bind(thread_wrapper,f,boost::ref(err_)))
48         {
49         }
50 
51     friend boost::shared_ptr<thread_handle> create_thread( boost::function<void()> const & f );
52     friend void join( thread_handle & t );
53     };
54 
55 boost::shared_ptr<thread_handle>
create_thread(boost::function<void ()> const & f)56 create_thread( boost::function<void()> const & f )
57     {
58     boost::shared_ptr<thread_handle> t( new thread_handle(f) );
59     return t;
60     }
61 
62 void
join(thread_handle & t)63 join( thread_handle & t )
64     {
65     t.t_.join();
66     assert(t.err_);
67     rethrow_exception(t.err_);
68     }
69 
70 boost::detail::atomic_count exc_count(0);
71 
72 struct
73 exc:
74     virtual boost::exception,
75     virtual std::exception
76     {
excexc77     exc()
78         {
79         ++exc_count;
80         }
81 
excexc82     exc( exc const & e ):
83         boost::exception(e),
84         std::exception(e)
85         {
86         ++exc_count;
87         }
88 
89     virtual
~excexc90     ~exc() BOOST_NOEXCEPT_OR_NOTHROW
91         {
92         --exc_count;
93         }
94 
95     private:
96 
97     exc & operator=( exc const & );
98     };
99 
100 typedef boost::error_info<struct answer_,int> answer;
101 
102 void
thread_func()103 thread_func()
104     {
105     BOOST_THROW_EXCEPTION(exc() << answer(42));
106     }
107 
108 void
check(boost::shared_ptr<thread_handle> const & t)109 check( boost::shared_ptr<thread_handle> const & t )
110     {
111     try
112         {
113         join(*t);
114         BOOST_TEST(false);
115         }
116     catch(
117     exc & e )
118         {
119         int const * a = boost::get_error_info<answer>(e);
120         BOOST_TEST(a && *a==42);
121         }
122     }
123 
124 void
test_deep_copy()125 test_deep_copy()
126     {
127     int const * p1=0;
128     boost::exception_ptr p;
129     try
130         {
131         BOOST_THROW_EXCEPTION(exc() << answer(42));
132         BOOST_ERROR("BOOST_THROW_EXCEPTION didn't throw");
133         }
134     catch(
135     exc & e )
136         {
137         p1=boost::get_error_info<answer>(e);
138         p=boost::current_exception();
139         }
140     BOOST_TEST(p1!=0);
141     BOOST_TEST(p);
142     try
143         {
144         boost::rethrow_exception(p);
145         BOOST_ERROR("rethrow_exception didn't throw");
146         }
147     catch(
148     exc & e )
149         {
150         int const * p2=boost::get_error_info<answer>(e);
151         BOOST_TEST(p2!=0 && *p2==42);
152         BOOST_TEST(p2!=p1);
153         }
154     }
155 
156 int
main()157 main()
158     {
159     test_deep_copy();
160     BOOST_TEST(++exc_count==1);
161     try
162         {
163         std::vector< boost::shared_ptr<thread_handle> > threads;
164         std::generate_n(std::inserter(threads,threads.end()),1,boost::bind(create_thread,thread_func));
165         std::for_each(threads.begin(),threads.end(),check);
166         return boost::report_errors();
167         }
168     catch(
169     ... )
170         {
171         std::cerr <<
172             "Caught unexpected exception.\n"
173             "Output from current_exception_diagnostic_information:\n" <<
174             boost::current_exception_diagnostic_information() << std::endl;
175         return 42;
176         }
177     BOOST_TEST(!--exc_count);
178     }
179