]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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> | |
f67539c2 | 15 | #include <boost/config.hpp> |
7c673cae FG |
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 (&xt, 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); | |
57 | boost::xtime max = delay(0); | |
58 | return (boost::xtime_cmp(xt, min) >= 0) && | |
59 | (boost::xtime_cmp(xt, 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); | |
92f5a8d4 | 97 | if (type == use_sleep_only) { |
7c673cae | 98 | boost::thread::sleep(xt); |
92f5a8d4 TL |
99 | return done; |
100 | } | |
101 | if (type == use_condition) { | |
7c673cae | 102 | boost::unique_lock<boost::mutex> lock(mutex); |
92f5a8d4 | 103 | while (!done) { |
7c673cae FG |
104 | if (!cond.timed_wait(lock, xt)) |
105 | break; | |
106 | } | |
107 | return done; | |
108 | } | |
92f5a8d4 TL |
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(delay(0, 500)); | |
118 | } | |
7c673cae FG |
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) { } | |
f67539c2 TL |
137 | #if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) |
138 | indirect_adapter(indirect_adapter const&) = default; | |
139 | #endif | |
140 | ||
7c673cae FG |
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) { } | |
f67539c2 TL |
218 | #if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) |
219 | thread_member_binder(thread_member_binder const&) = default; | |
220 | #endif | |
221 | ||
7c673cae FG |
222 | void operator()() const { (param.*func)(); } |
223 | ||
224 | private: | |
225 | void operator=(thread_member_binder&); | |
f67539c2 | 226 | |
7c673cae FG |
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 |