mutex.hpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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 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 <pthread.h>
  10. #include <boost/throw_exception.hpp>
  11. #include <boost/thread/exceptions.hpp>
  12. #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
  13. #include <boost/thread/lock_types.hpp>
  14. #endif
  15. #include <boost/thread/thread_time.hpp>
  16. #include <boost/thread/xtime.hpp>
  17. #include <boost/assert.hpp>
  18. #include <errno.h>
  19. #include <boost/thread/pthread/timespec.hpp>
  20. #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
  21. #ifdef BOOST_THREAD_USES_CHRONO
  22. #include <boost/chrono/system_clocks.hpp>
  23. #include <boost/chrono/ceil.hpp>
  24. #endif
  25. #include <boost/thread/detail/delete.hpp>
  26. #ifdef _POSIX_TIMEOUTS
  27. #if _POSIX_TIMEOUTS >= 0 && _POSIX_TIMEOUTS>=200112L
  28. #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
  29. #define BOOST_PTHREAD_HAS_TIMEDLOCK
  30. #endif
  31. #endif
  32. #endif
  33. #include <boost/config/abi_prefix.hpp>
  34. #ifndef BOOST_THREAD_HAS_NO_EINTR_BUG
  35. #define BOOST_THREAD_HAS_EINTR_BUG
  36. #endif
  37. namespace boost
  38. {
  39. namespace posix {
  40. #ifdef BOOST_THREAD_HAS_EINTR_BUG
  41. BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
  42. {
  43. int ret;
  44. do
  45. {
  46. ret = ::pthread_mutex_destroy(m);
  47. } while (ret == EINTR);
  48. return ret;
  49. }
  50. BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
  51. {
  52. int ret;
  53. do
  54. {
  55. ret = ::pthread_mutex_lock(m);
  56. } while (ret == EINTR);
  57. return ret;
  58. }
  59. BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
  60. {
  61. int ret;
  62. do
  63. {
  64. ret = ::pthread_mutex_unlock(m);
  65. } while (ret == EINTR);
  66. return ret;
  67. }
  68. #else
  69. BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m)
  70. {
  71. return ::pthread_mutex_destroy(m);
  72. }
  73. BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m)
  74. {
  75. return ::pthread_mutex_lock(m);
  76. }
  77. BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m)
  78. {
  79. return ::pthread_mutex_unlock(m);
  80. }
  81. #endif
  82. }
  83. class mutex
  84. {
  85. private:
  86. pthread_mutex_t m;
  87. public:
  88. BOOST_THREAD_NO_COPYABLE(mutex)
  89. mutex()
  90. {
  91. int const res=pthread_mutex_init(&m,NULL);
  92. if(res)
  93. {
  94. boost::throw_exception(thread_resource_error(res, "boost:: mutex constructor failed in pthread_mutex_init"));
  95. }
  96. }
  97. ~mutex()
  98. {
  99. BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
  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. if (res)
  113. {
  114. boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
  115. }
  116. }
  117. bool try_lock()
  118. {
  119. int res;
  120. do
  121. {
  122. res = pthread_mutex_trylock(&m);
  123. } while (res == EINTR);
  124. if (res==EBUSY)
  125. {
  126. return false;
  127. }
  128. return !res;
  129. }
  130. #define BOOST_THREAD_DEFINES_MUTEX_NATIVE_HANDLE
  131. typedef pthread_mutex_t* native_handle_type;
  132. native_handle_type native_handle()
  133. {
  134. return &m;
  135. }
  136. #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
  137. typedef unique_lock<mutex> scoped_lock;
  138. typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
  139. #endif
  140. };
  141. typedef mutex try_mutex;
  142. class timed_mutex
  143. {
  144. private:
  145. pthread_mutex_t m;
  146. #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
  147. pthread_cond_t cond;
  148. bool is_locked;
  149. #endif
  150. public:
  151. BOOST_THREAD_NO_COPYABLE(timed_mutex)
  152. timed_mutex()
  153. {
  154. int const res=pthread_mutex_init(&m,NULL);
  155. if(res)
  156. {
  157. boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init"));
  158. }
  159. #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
  160. int const res2=pthread_cond_init(&cond,NULL);
  161. if(res2)
  162. {
  163. BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
  164. //BOOST_VERIFY(!pthread_mutex_destroy(&m));
  165. boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init"));
  166. }
  167. is_locked=false;
  168. #endif
  169. }
  170. ~timed_mutex()
  171. {
  172. BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
  173. #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
  174. BOOST_VERIFY(!pthread_cond_destroy(&cond));
  175. #endif
  176. }
  177. #if defined BOOST_THREAD_USES_DATETIME
  178. template<typename TimeDuration>
  179. bool timed_lock(TimeDuration const & relative_time)
  180. {
  181. return timed_lock(get_system_time()+relative_time);
  182. }
  183. bool timed_lock(boost::xtime const & absolute_time)
  184. {
  185. return timed_lock(system_time(absolute_time));
  186. }
  187. #endif
  188. #ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
  189. void lock()
  190. {
  191. int res = posix::pthread_mutex_lock(&m);
  192. if (res)
  193. {
  194. boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
  195. }
  196. }
  197. void unlock()
  198. {
  199. int res = posix::pthread_mutex_unlock(&m);
  200. if (res)
  201. {
  202. boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock"));
  203. }
  204. }
  205. bool try_lock()
  206. {
  207. int res;
  208. do
  209. {
  210. res = pthread_mutex_trylock(&m);
  211. } while (res == EINTR);
  212. if (res==EBUSY)
  213. {
  214. return false;
  215. }
  216. return !res;
  217. }
  218. private:
  219. bool do_try_lock_until(struct timespec const &timeout)
  220. {
  221. int const res=pthread_mutex_timedlock(&m,&timeout);
  222. BOOST_ASSERT(!res || res==ETIMEDOUT);
  223. return !res;
  224. }
  225. public:
  226. #else
  227. void lock()
  228. {
  229. boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
  230. while(is_locked)
  231. {
  232. BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
  233. }
  234. is_locked=true;
  235. }
  236. void unlock()
  237. {
  238. boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
  239. is_locked=false;
  240. BOOST_VERIFY(!pthread_cond_signal(&cond));
  241. }
  242. bool try_lock()
  243. {
  244. boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
  245. if(is_locked)
  246. {
  247. return false;
  248. }
  249. is_locked=true;
  250. return true;
  251. }
  252. private:
  253. bool do_try_lock_until(struct timespec const &timeout)
  254. {
  255. boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
  256. while(is_locked)
  257. {
  258. int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
  259. if(cond_res==ETIMEDOUT)
  260. {
  261. return false;
  262. }
  263. BOOST_ASSERT(!cond_res);
  264. }
  265. is_locked=true;
  266. return true;
  267. }
  268. public:
  269. #endif
  270. #if defined BOOST_THREAD_USES_DATETIME
  271. bool timed_lock(system_time const & abs_time)
  272. {
  273. struct timespec const ts=boost::detail::to_timespec(abs_time);
  274. return do_try_lock_until(ts);
  275. }
  276. #endif
  277. #ifdef BOOST_THREAD_USES_CHRONO
  278. template <class Rep, class Period>
  279. bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
  280. {
  281. return try_lock_until(chrono::steady_clock::now() + rel_time);
  282. }
  283. template <class Clock, class Duration>
  284. bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
  285. {
  286. using namespace chrono;
  287. system_clock::time_point s_now = system_clock::now();
  288. typename Clock::time_point c_now = Clock::now();
  289. return try_lock_until(s_now + ceil<nanoseconds>(t - c_now));
  290. }
  291. template <class Duration>
  292. bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
  293. {
  294. using namespace chrono;
  295. typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
  296. return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
  297. }
  298. bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
  299. {
  300. //using namespace chrono;
  301. chrono::nanoseconds d = tp.time_since_epoch();
  302. timespec ts = boost::detail::to_timespec(d);
  303. return do_try_lock_until(ts);
  304. }
  305. #endif
  306. #define BOOST_THREAD_DEFINES_TIMED_MUTEX_NATIVE_HANDLE
  307. typedef pthread_mutex_t* native_handle_type;
  308. native_handle_type native_handle()
  309. {
  310. return &m;
  311. }
  312. #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
  313. typedef unique_lock<timed_mutex> scoped_timed_lock;
  314. typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
  315. typedef scoped_timed_lock scoped_lock;
  316. #endif
  317. };
  318. }
  319. #include <boost/config/abi_suffix.hpp>
  320. #endif