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
25namespace
26{
27inline 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}
48namespace boost
49{
50namespace threads
51{
52namespace test
53{
54inline 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
66namespace
67{
68class execution_monitor
69{
70public:
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
121private:
122 boost::mutex mutex;
123 boost::condition cond;
124 bool done;
125 wait_type type;
126 int secs;
127};
128}
129namespace thread_detail_anon
130{
131template <typename F>
132class indirect_adapter
133{
134public:
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
156private:
157 F func;
158 execution_monitor& monitor;
159 void operator=(indirect_adapter&);
160};
161
162}
163// boostinspect:nounnamed
164namespace
165{
166
167template <typename F>
168void 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
181namespace thread_detail_anon
182{
183
184template <typename F, typename T>
185class thread_binder
186{
187public:
188 thread_binder(const F& func, const T& param)
189 : func(func), param(param) { }
190 void operator()() const { func(param); }
191
192private:
193 F func;
194 T param;
195};
196
197}
198
199// boostinspect:nounnamed
200namespace
201{
202template <typename F, typename T>
203thread_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
209namespace thread_detail_anon
210{
211
212template <typename R, typename T>
213class thread_member_binder
214{
215public:
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
224private:
225 void operator=(thread_member_binder&);
226
227 R (T::*func)();
228 T& param;
229};
230
231}
232
233// boostinspect:nounnamed
234namespace
235{
236template <typename R, typename T>
237thread_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

source code of boost/libs/thread/test/util.inl