1 | // Copyright (C) 2001-2003 |
2 | // William E. Kempf |
3 | // Copyright (C) 2007-8 Anthony Williams |
4 | // |
5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
7 | |
8 | #if !defined(UTIL_INL_WEK01242003) |
9 | #define UTIL_INL_WEK01242003 |
10 | |
11 | #include <boost/thread/xtime.hpp> |
12 | #include <boost/thread/mutex.hpp> |
13 | #include <boost/thread/condition.hpp> |
14 | #include <boost/thread/thread.hpp> |
15 | #include <boost/config.hpp> |
16 | |
17 | #ifndef DEFAULT_EXECUTION_MONITOR_TYPE |
18 | # define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_condition |
19 | #endif |
20 | |
21 | // boostinspect:nounnamed |
22 | |
23 | |
24 | |
25 | namespace |
26 | { |
27 | inline boost::xtime delay(int secs, int msecs=0, int nsecs=0) |
28 | { |
29 | const int MILLISECONDS_PER_SECOND = 1000; |
30 | const int NANOSECONDS_PER_SECOND = 1000000000; |
31 | const int NANOSECONDS_PER_MILLISECOND = 1000000; |
32 | |
33 | boost::xtime xt; |
34 | if (boost::TIME_UTC_ != boost::xtime_get (xtp: &xt, clock_type: boost::TIME_UTC_)) |
35 | BOOST_ERROR ("boost::xtime_get != boost::TIME_UTC_" ); |
36 | |
37 | nsecs += xt.nsec; |
38 | msecs += nsecs / NANOSECONDS_PER_MILLISECOND; |
39 | secs += msecs / MILLISECONDS_PER_SECOND; |
40 | nsecs += (msecs % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND; |
41 | xt.nsec = nsecs % NANOSECONDS_PER_SECOND; |
42 | xt.sec += secs + (nsecs / NANOSECONDS_PER_SECOND); |
43 | |
44 | return xt; |
45 | } |
46 | |
47 | } |
48 | namespace boost |
49 | { |
50 | namespace threads |
51 | { |
52 | namespace test |
53 | { |
54 | inline bool in_range(const boost::xtime& xt, int secs=1) |
55 | { |
56 | boost::xtime min = delay(secs: -secs); |
57 | boost::xtime max = delay(secs: 0); |
58 | return (boost::xtime_cmp(xt1: xt, xt2: min) >= 0) && |
59 | (boost::xtime_cmp(xt1: xt, xt2: max) <= 0); |
60 | } |
61 | } |
62 | } |
63 | } |
64 | |
65 | |
66 | namespace |
67 | { |
68 | class execution_monitor |
69 | { |
70 | public: |
71 | enum wait_type { use_sleep_only, use_mutex, use_condition }; |
72 | |
73 | execution_monitor(wait_type type, int secs) |
74 | : done(false), type(type), secs(secs) { } |
75 | void start() |
76 | { |
77 | if (type != use_sleep_only) { |
78 | boost::unique_lock<boost::mutex> lock(mutex); done = false; |
79 | } else { |
80 | done = false; |
81 | } |
82 | } |
83 | void finish() |
84 | { |
85 | if (type != use_sleep_only) { |
86 | boost::unique_lock<boost::mutex> lock(mutex); |
87 | done = true; |
88 | if (type == use_condition) |
89 | cond.notify_one(); |
90 | } else { |
91 | done = true; |
92 | } |
93 | } |
94 | bool wait() |
95 | { |
96 | boost::xtime xt = delay(secs); |
97 | if (type == use_sleep_only) { |
98 | boost::thread::sleep(xt); |
99 | return done; |
100 | } |
101 | if (type == use_condition) { |
102 | boost::unique_lock<boost::mutex> lock(mutex); |
103 | while (!done) { |
104 | if (!cond.timed_wait(m&: lock, abs_time: xt)) |
105 | break; |
106 | } |
107 | return done; |
108 | } |
109 | for (int i = 0; ; ++i) { |
110 | { |
111 | boost::unique_lock<boost::mutex> lock(mutex); |
112 | if (done) |
113 | return true; |
114 | else if (i > secs * 2) |
115 | return done; |
116 | } |
117 | boost::thread::sleep(xt: delay(secs: 0, msecs: 500)); |
118 | } |
119 | } |
120 | |
121 | private: |
122 | boost::mutex mutex; |
123 | boost::condition cond; |
124 | bool done; |
125 | wait_type type; |
126 | int secs; |
127 | }; |
128 | } |
129 | namespace thread_detail_anon |
130 | { |
131 | template <typename F> |
132 | class indirect_adapter |
133 | { |
134 | public: |
135 | indirect_adapter(F func, execution_monitor& monitor) |
136 | : func(func), monitor(monitor) { } |
137 | #if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) |
138 | indirect_adapter(indirect_adapter const&) = default; |
139 | #endif |
140 | |
141 | void operator()() const |
142 | { |
143 | try |
144 | { |
145 | boost::thread thrd(func); |
146 | thrd.join(); |
147 | } |
148 | catch (...) |
149 | { |
150 | monitor.finish(); |
151 | throw; |
152 | } |
153 | monitor.finish(); |
154 | } |
155 | |
156 | private: |
157 | F func; |
158 | execution_monitor& monitor; |
159 | void operator=(indirect_adapter&); |
160 | }; |
161 | |
162 | } |
163 | // boostinspect:nounnamed |
164 | namespace |
165 | { |
166 | |
167 | template <typename F> |
168 | void timed_test(F func, int secs, |
169 | execution_monitor::wait_type type=DEFAULT_EXECUTION_MONITOR_TYPE) |
170 | { |
171 | execution_monitor monitor(type, secs); |
172 | thread_detail_anon::indirect_adapter<F> ifunc(func, monitor); |
173 | monitor.start(); |
174 | boost::thread thrd(ifunc); |
175 | BOOST_REQUIRE_MESSAGE(monitor.wait(), |
176 | "Timed test didn't complete in time, possible deadlock." ); |
177 | } |
178 | |
179 | } |
180 | |
181 | namespace thread_detail_anon |
182 | { |
183 | |
184 | template <typename F, typename T> |
185 | class thread_binder |
186 | { |
187 | public: |
188 | thread_binder(const F& func, const T& param) |
189 | : func(func), param(param) { } |
190 | void operator()() const { func(param); } |
191 | |
192 | private: |
193 | F func; |
194 | T param; |
195 | }; |
196 | |
197 | } |
198 | |
199 | // boostinspect:nounnamed |
200 | namespace |
201 | { |
202 | template <typename F, typename T> |
203 | thread_detail_anon::thread_binder<F, T> bind(const F& func, const T& param) |
204 | { |
205 | return thread_detail_anon::thread_binder<F, T>(func, param); |
206 | } |
207 | } |
208 | |
209 | namespace thread_detail_anon |
210 | { |
211 | |
212 | template <typename R, typename T> |
213 | class thread_member_binder |
214 | { |
215 | public: |
216 | thread_member_binder(R (T::*func)(), T& param) |
217 | : func(func), param(param) { } |
218 | #if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) |
219 | thread_member_binder(thread_member_binder const&) = default; |
220 | #endif |
221 | |
222 | void operator()() const { (param.*func)(); } |
223 | |
224 | private: |
225 | void operator=(thread_member_binder&); |
226 | |
227 | R (T::*func)(); |
228 | T& param; |
229 | }; |
230 | |
231 | } |
232 | |
233 | // boostinspect:nounnamed |
234 | namespace |
235 | { |
236 | template <typename R, typename T> |
237 | thread_detail_anon::thread_member_binder<R, T> bind(R (T::*func)(), T& param) |
238 | { |
239 | return thread_detail_anon::thread_member_binder<R, T>(func, param); |
240 | } |
241 | } // namespace |
242 | |
243 | #endif |
244 | |