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