010dc50e1afc58f92490ded1f2538fbb417df3a6
[platform/upstream/boost.git] / libs / thread / test / util.inl
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);
96         if (type != use_condition)
97             boost::thread::sleep(xt);
98         if (type != use_sleep_only) {
99             boost::unique_lock<boost::mutex> lock(mutex);
100             while (type == use_condition && !done) {
101                 if (!cond.timed_wait(lock, xt))
102                     break;
103             }
104             return done;
105         }
106         return done;
107     }
108
109 private:
110     boost::mutex mutex;
111     boost::condition cond;
112     bool done;
113     wait_type type;
114     int secs;
115 };
116 }
117 namespace thread_detail_anon
118 {
119 template <typename F>
120 class indirect_adapter
121 {
122 public:
123     indirect_adapter(F func, execution_monitor& monitor)
124         : func(func), monitor(monitor) { }
125     void operator()() const
126     {
127         try
128         {
129             boost::thread thrd(func);
130             thrd.join();
131         }
132         catch (...)
133         {
134             monitor.finish();
135             throw;
136         }
137         monitor.finish();
138     }
139
140 private:
141     F func;
142     execution_monitor& monitor;
143     void operator=(indirect_adapter&);
144 };
145
146 }
147 // boostinspect:nounnamed
148 namespace 
149 {
150
151 template <typename F>
152 void timed_test(F func, int secs,
153     execution_monitor::wait_type type=DEFAULT_EXECUTION_MONITOR_TYPE)
154 {
155     execution_monitor monitor(type, secs);
156     thread_detail_anon::indirect_adapter<F> ifunc(func, monitor);
157     monitor.start();
158     boost::thread thrd(ifunc);
159     BOOST_REQUIRE_MESSAGE(monitor.wait(),
160         "Timed test didn't complete in time, possible deadlock.");
161 }
162
163 }
164
165 namespace thread_detail_anon
166 {
167
168 template <typename F, typename T>
169 class thread_binder
170 {
171 public:
172     thread_binder(const F& func, const T& param)
173         : func(func), param(param) { }
174     void operator()() const { func(param); }
175
176 private:
177     F func;
178     T param;
179 };
180
181 }
182
183 // boostinspect:nounnamed
184 namespace 
185 {
186 template <typename F, typename T>
187 thread_detail_anon::thread_binder<F, T> bind(const F& func, const T& param)
188 {
189     return thread_detail_anon::thread_binder<F, T>(func, param);
190 }
191 }
192
193 namespace thread_detail_anon
194 {
195
196 template <typename R, typename T>
197 class thread_member_binder
198 {
199 public:
200     thread_member_binder(R (T::*func)(), T& param)
201         : func(func), param(param) { }
202     void operator()() const { (param.*func)(); }
203
204 private:
205     void operator=(thread_member_binder&);
206     
207     R (T::*func)();
208     T& param;
209 };
210
211 }
212
213 // boostinspect:nounnamed
214 namespace 
215 {
216 template <typename R, typename T>
217 thread_detail_anon::thread_member_binder<R, T> bind(R (T::*func)(), T& param)
218 {
219     return thread_detail_anon::thread_member_binder<R, T>(func, param);
220 }
221 } // namespace
222
223 #endif