mutex.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. #ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP
  2. #define BOOST_THREAD_PTHREAD_MUTEX_HPP
  3. // (C) Copyright 2007-8 Anthony Williams
  4. // (C) Copyright 2011,2012,2015 Vicente J. Botet Escriba
  5. // Distributed under the Boost Software License, Version 1.0. (See
  6. // accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. #include <boost/thread/detail/config.hpp>
  9. #include <boost/assert.hpp>
  10. #include <pthread.h>
  11. #include <boost/throw_exception.hpp>
  12. #include <boost/core/ignore_unused.hpp>
  13. #include <boost/thread/exceptions.hpp>
  14. #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
  15. #include <boost/thread/lock_types.hpp>
  16. #endif
  17. #include <boost/thread/thread_time.hpp>
  18. #if defined BOOST_THREAD_USES_DATETIME
  19. #include <boost/thread/xtime.hpp>
  20. #endif
  21. #include <boost/assert.hpp>
  22. #include <errno.h>
  23. #include <boost/thread/detail/platform_time.hpp>
  24. #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
  25. #include <boost/thread/pthread/pthread_helpers.hpp>
  26. #ifdef BOOST_THREAD_USES_CHRONO
  27. #include <boost/chrono/system_clocks.hpp>
  28. #include <boost/chrono/ceil.hpp>
  29. #endif
  30. #include <boost/thread/detail/delete.hpp>
  31. #include <boost/config/abi_prefix.hpp>
  32. #ifndef BOOST_THREAD_HAS_NO_EINTR_BUG
  33. #define BOOST_THREAD_HAS_EINTR_BUG
  34. #endif
  35. namespace boost
  36. {
  37. namespace posix {
  38. #ifdef BOOST_THREAD_HAS_EINTR_BUG
  39. BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
  40. {
  41. int ret;
  42. do
  43. {
  44. ret = ::pthread_mutex_destroy(m);
  45. } while (ret == EINTR);
  46. return ret;
  47. }
  48. BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
  49. {
  50. int ret;
  51. do
  52. {
  53. ret = ::pthread_mutex_lock(m);
  54. } while (ret == EINTR);
  55. return ret;
  56. }
  57. BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
  58. {
  59. int ret;
  60. do
  61. {
  62. ret = ::pthread_mutex_unlock(m);
  63. } while (ret == EINTR);
  64. return ret;
  65. }
  66. #else
  67. BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
  68. {
  69. return ::pthread_mutex_destroy(m);
  70. }
  71. BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
  72. {
  73. return ::pthread_mutex_lock(m);
  74. }
  75. BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
  76. {
  77. return ::pthread_mutex_unlock(m);
  78. }
  79. #endif
  80. }
  81. class mutex
  82. {
  83. private:
  84. pthread_mutex_t m;
  85. public:
  86. BOOST_THREAD_NO_COPYABLE(mutex)
  87. mutex()
  88. {
  89. int const res=pthread_mutex_init(&m,NULL);
  90. if(res)
  91. {
  92. boost::throw_exception(thread_resource_error(res, "boost:: mutex constructor failed in pthread_mutex_init"));
  93. }
  94. }
  95. ~mutex()
  96. {
  97. int const res = posix::pthread_mutex_destroy(&m);
  98. boost::ignore_unused(res);
  99. BOOST_ASSERT(!res);
  100. }
  101. void lock()
  102. {
  103. int res = posix::pthread_mutex_lock(&m);
  104. if (res)
  105. {
  106. boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
  107. }
  108. }
  109. void unlock()
  110. {
  111. int res = posix::pthread_mutex_unlock(&m);
  112. (void)res;
  113. BOOST_ASSERT(res == 0);
  114. // if (res)
  115. // {
  116. // boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
  117. // }
  118. }
  119. bool try_lock()
  120. {
  121. int res;
  122. do
  123. {
  124. res = pthread_mutex_trylock(&m);
  125. } while (res == EINTR);
  126. if (res==EBUSY)
  127. {
  128. return false;
  129. }
  130. return !res;
  131. }
  132. #define BOOST_THREAD_DEFINES_MUTEX_NATIVE_HANDLE
  133. typedef pthread_mutex_t* native_handle_type;
  134. native_handle_type native_handle()
  135. {
  136. return &m;
  137. }
  138. #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
  139. typedef unique_lock<mutex> scoped_lock;
  140. typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
  141. #endif
  142. };
  143. typedef mutex try_mutex;
  144. class timed_mutex
  145. {
  146. private:
  147. pthread_mutex_t m;
  148. #ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
  149. pthread_cond_t cond;
  150. bool is_locked;
  151. #endif
  152. public:
  153. BOOST_THREAD_NO_COPYABLE(timed_mutex)
  154. timed_mutex()
  155. {
  156. int const res=pthread_mutex_init(&m,NULL);
  157. if(res)
  158. {
  159. boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init"));
  160. }
  161. #ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
  162. int const res2=pthread::cond_init(cond);
  163. if(res2)
  164. {
  165. BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
  166. boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread::cond_init"));
  167. }
  168. is_locked=false;
  169. #endif
  170. }
  171. ~timed_mutex()
  172. {
  173. BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
  174. #ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
  175. BOOST_VERIFY(!pthread_cond_destroy(&cond));
  176. #endif
  177. }
  178. #if defined BOOST_THREAD_USES_DATETIME
  179. template<typename TimeDuration>
  180. bool timed_lock(TimeDuration const & relative_time)
  181. {
  182. if (relative_time.is_pos_infinity())
  183. {
  184. lock();
  185. return true;
  186. }
  187. if (relative_time.is_special())
  188. {
  189. return true;
  190. }
  191. detail::platform_duration d(relative_time);
  192. #if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
  193. const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
  194. d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
  195. while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
  196. {
  197. d = ts - detail::mono_platform_clock::now();
  198. if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
  199. d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
  200. }
  201. return true;
  202. #else
  203. return do_try_lock_until(detail::internal_platform_clock::now() + d);
  204. #endif
  205. }
  206. bool timed_lock(boost::xtime const & absolute_time)
  207. {
  208. return timed_lock(system_time(absolute_time));
  209. }
  210. #endif
  211. #ifdef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
  212. void lock()
  213. {
  214. int res = posix::pthread_mutex_lock(&m);
  215. if (res)
  216. {
  217. boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
  218. }
  219. }
  220. void unlock()
  221. {
  222. int res = posix::pthread_mutex_unlock(&m);
  223. (void)res;
  224. BOOST_ASSERT(res == 0);
  225. // if (res)
  226. // {
  227. // boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
  228. // }
  229. }
  230. bool try_lock()
  231. {
  232. int res;
  233. do
  234. {
  235. res = pthread_mutex_trylock(&m);
  236. } while (res == EINTR);
  237. if (res==EBUSY)
  238. {
  239. return false;
  240. }
  241. return !res;
  242. }
  243. private:
  244. bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
  245. {
  246. int const res=pthread_mutex_timedlock(&m,&timeout.getTs());
  247. BOOST_ASSERT(!res || res==ETIMEDOUT);
  248. return !res;
  249. }
  250. public:
  251. #else
  252. void lock()
  253. {
  254. boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
  255. while(is_locked)
  256. {
  257. BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
  258. }
  259. is_locked=true;
  260. }
  261. void unlock()
  262. {
  263. boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
  264. is_locked=false;
  265. BOOST_VERIFY(!pthread_cond_signal(&cond));
  266. }
  267. bool try_lock()
  268. {
  269. boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
  270. if(is_locked)
  271. {
  272. return false;
  273. }
  274. is_locked=true;
  275. return true;
  276. }
  277. private:
  278. bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
  279. {
  280. boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
  281. while(is_locked)
  282. {
  283. int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout.getTs());
  284. if(cond_res==ETIMEDOUT)
  285. {
  286. break;
  287. }
  288. BOOST_ASSERT(!cond_res);
  289. }
  290. if(is_locked)
  291. {
  292. return false;
  293. }
  294. is_locked=true;
  295. return true;
  296. }
  297. public:
  298. #endif
  299. #if defined BOOST_THREAD_USES_DATETIME
  300. bool timed_lock(system_time const & abs_time)
  301. {
  302. const detail::real_platform_timepoint ts(abs_time);
  303. #if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
  304. detail::platform_duration d(ts - detail::real_platform_clock::now());
  305. d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
  306. while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
  307. {
  308. d = ts - detail::real_platform_clock::now();
  309. if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
  310. d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
  311. }
  312. return true;
  313. #else
  314. return do_try_lock_until(ts);
  315. #endif
  316. }
  317. #endif
  318. #ifdef BOOST_THREAD_USES_CHRONO
  319. template <class Rep, class Period>
  320. bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
  321. {
  322. return try_lock_until(chrono::steady_clock::now() + rel_time);
  323. }
  324. template <class Clock, class Duration>
  325. bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
  326. {
  327. typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
  328. common_duration d(t - Clock::now());
  329. d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
  330. while ( ! try_lock_until(detail::internal_chrono_clock::now() + d))
  331. {
  332. d = t - Clock::now();
  333. if ( d <= common_duration::zero() ) return false; // timeout occurred
  334. d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
  335. }
  336. return true;
  337. }
  338. template <class Duration>
  339. bool try_lock_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
  340. {
  341. detail::internal_platform_timepoint ts(t);
  342. return do_try_lock_until(ts);
  343. }
  344. #endif
  345. #define BOOST_THREAD_DEFINES_TIMED_MUTEX_NATIVE_HANDLE
  346. typedef pthread_mutex_t* native_handle_type;
  347. native_handle_type native_handle()
  348. {
  349. return &m;
  350. }
  351. #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
  352. typedef unique_lock<timed_mutex> scoped_timed_lock;
  353. typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
  354. typedef scoped_timed_lock scoped_lock;
  355. #endif
  356. };
  357. }
  358. #include <boost/config/abi_suffix.hpp>
  359. #endif