recursive_mutex.hpp 14 KB

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