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 (&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} 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); 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 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(lock, 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(delay(0, 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