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() throw()
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 int
main()125 main()
126     {
127     BOOST_TEST(++exc_count==1);
128     try
129         {
130         std::vector< boost::shared_ptr<thread_handle> > threads;
131         std::generate_n(std::inserter(threads,threads.end()),1,boost::bind(create_thread,thread_func));
132         std::for_each(threads.begin(),threads.end(),check);
133         return boost::report_errors();
134         }
135     catch(
136     ... )
137         {
138         std::cerr <<
139             "Caught unexpected exception.\n"
140             "Output from current_exception_diagnostic_information:\n" <<
141             boost::current_exception_diagnostic_information() << std::endl;
142         return 42;
143         }
144     BOOST_TEST(!--exc_count);
145     }
146