util.inl 5.1 KB

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