interprocess_upgradable_mutex.hpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Code based on Howard Hinnant's upgrade_mutex class
  4. //
  5. // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
  6. // Software License, Version 1.0. (See accompanying file
  7. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // See http://www.boost.org/libs/interprocess for documentation.
  10. //
  11. //////////////////////////////////////////////////////////////////////////////
  12. #ifndef BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP
  13. #define BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP
  14. #ifndef BOOST_CONFIG_HPP
  15. # include <boost/config.hpp>
  16. #endif
  17. #
  18. #if defined(BOOST_HAS_PRAGMA_ONCE)
  19. # pragma once
  20. #endif
  21. #include <boost/interprocess/detail/config_begin.hpp>
  22. #include <boost/interprocess/detail/workaround.hpp>
  23. #include <boost/interprocess/sync/scoped_lock.hpp>
  24. #include <boost/interprocess/timed_utils.hpp>
  25. #include <boost/interprocess/sync/interprocess_mutex.hpp>
  26. #include <boost/interprocess/sync/interprocess_condition.hpp>
  27. #include <climits>
  28. //!\file
  29. //!Describes interprocess_upgradable_mutex class
  30. namespace boost {
  31. namespace interprocess {
  32. //!Wraps a interprocess_upgradable_mutex that can be placed in shared memory and can be
  33. //!shared between processes. Allows timed lock tries
  34. class interprocess_upgradable_mutex
  35. {
  36. //Non-copyable
  37. interprocess_upgradable_mutex(const interprocess_upgradable_mutex &);
  38. interprocess_upgradable_mutex &operator=(const interprocess_upgradable_mutex &);
  39. friend class interprocess_condition;
  40. public:
  41. //!Constructs the upgradable lock.
  42. //!Throws interprocess_exception on error.
  43. interprocess_upgradable_mutex();
  44. //!Destroys the upgradable lock.
  45. //!Does not throw.
  46. ~interprocess_upgradable_mutex();
  47. //Exclusive locking
  48. //!Requires: The calling thread does not own the mutex.
  49. //!
  50. //!Effects: The calling thread tries to obtain exclusive ownership of the mutex,
  51. //! and if another thread has exclusive, sharable or upgradable ownership of
  52. //! the mutex, it waits until it can obtain the ownership.
  53. //!Throws: interprocess_exception on error.
  54. //!
  55. //!Note: A program may deadlock if the thread that has ownership calls
  56. //! this function. If the implementation can detect the deadlock,
  57. //! an exception could be thrown.
  58. void lock();
  59. //!Requires: The calling thread does not own the mutex.
  60. //!
  61. //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
  62. //! without waiting. If no other thread has exclusive, sharable or upgradable
  63. //! ownership of the mutex this succeeds.
  64. //!Returns: If it can acquire exclusive ownership immediately returns true.
  65. //! If it has to wait, returns false.
  66. //!Throws: interprocess_exception on error.
  67. //!
  68. //!Note: A program may deadlock if the thread that has ownership calls
  69. //! this function. If the implementation can detect the deadlock,
  70. //! an exception could be thrown.
  71. bool try_lock();
  72. //!Requires: The calling thread does not own the mutex.
  73. //!
  74. //!Effects: The calling thread tries to acquire exclusive ownership of the mutex
  75. //! waiting if necessary until no other thread has exclusive, sharable or
  76. //! upgradable ownership of the mutex or abs_time is reached.
  77. //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
  78. //!Throws: interprocess_exception on error.
  79. //!
  80. //!Note: A program may deadlock if the thread that has ownership calls
  81. //! this function. If the implementation can detect the deadlock,
  82. //! an exception could be thrown.
  83. template<class TimePoint>
  84. bool timed_lock(const TimePoint &abs_time);
  85. //!Same as `timed_lock`, but this function is modeled after the
  86. //!standard library interface.
  87. template<class TimePoint> bool try_lock_until(const TimePoint &abs_time)
  88. { return this->timed_lock(abs_time); }
  89. //!Same as `timed_lock`, but this function is modeled after the
  90. //!standard library interface.
  91. template<class Duration> bool try_lock_for(const Duration &dur)
  92. { return this->timed_lock(ipcdetail::duration_to_ustime(dur)); }
  93. //!Precondition: The thread must have exclusive ownership of the mutex.
  94. //!Effects: The calling thread releases the exclusive ownership of the mutex.
  95. //!Throws: An exception derived from interprocess_exception on error.
  96. void unlock();
  97. //Sharable locking
  98. //!Requires: The calling thread does not own the mutex.
  99. //!
  100. //!Effects: The calling thread tries to obtain sharable ownership of the mutex,
  101. //! and if another thread has exclusive ownership of the mutex,
  102. //! waits until it can obtain the ownership.
  103. //!Throws: interprocess_exception on error.
  104. //!
  105. //!Note: A program may deadlock if the thread that has ownership calls
  106. //! this function. If the implementation can detect the deadlock,
  107. //! an exception could be thrown.
  108. void lock_sharable();
  109. //!Same as `lock_sharable` but with a std-compatible interface
  110. //!
  111. void lock_shared()
  112. { this->lock_sharable(); }
  113. //!Requires: The calling thread does not own the mutex.
  114. //!
  115. //!Effects: The calling thread tries to acquire sharable ownership of the mutex
  116. //! without waiting. If no other thread has exclusive ownership
  117. //! of the mutex this succeeds.
  118. //!Returns: If it can acquire sharable ownership immediately returns true. If it
  119. //! has to wait, returns false.
  120. //!Throws: interprocess_exception on error.
  121. //!
  122. //!Note: A program may deadlock if the thread that has ownership calls
  123. //! this function. If the implementation can detect the deadlock,
  124. //! an exception could be thrown.
  125. bool try_lock_sharable();
  126. //!Same as `try_lock_sharable` but with a std-compatible interface
  127. //!
  128. bool try_lock_shared()
  129. { return this->try_lock_sharable(); }
  130. //!Requires: The calling thread does not own the mutex.
  131. //!
  132. //!Effects: The calling thread tries to acquire sharable ownership of the mutex
  133. //! waiting if necessary until no other thread has exclusive
  134. //! ownership of the mutex or abs_time is reached.
  135. //!Returns: If acquires sharable ownership, returns true. Otherwise returns false.
  136. //!Throws: interprocess_exception on error.
  137. //!
  138. //!Note: A program may deadlock if the thread that has ownership calls
  139. //! this function. If the implementation can detect the deadlock,
  140. //! an exception could be thrown.
  141. template<class TimePoint>
  142. bool timed_lock_sharable(const TimePoint &abs_time);
  143. //!Same as `timed_lock_sharable`, but this function is modeled after the
  144. //!standard library interface.
  145. template<class TimePoint> bool try_lock_shared_until(const TimePoint &abs_time)
  146. { return this->timed_lock_sharable(abs_time); }
  147. //!Same as `timed_lock_sharable`, but this function is modeled after the
  148. //!standard library interface.
  149. template<class Duration> bool try_lock_shared_for(const Duration &dur)
  150. { return this->timed_lock_sharable(ipcdetail::duration_to_ustime(dur)); }
  151. //!Precondition: The thread must have sharable ownership of the mutex.
  152. //!Effects: The calling thread releases the sharable ownership of the mutex.
  153. //!Throws: An exception derived from interprocess_exception on error.
  154. void unlock_sharable();
  155. //!Same as `unlock_sharable` but with a std-compatible interface
  156. //!
  157. void unlock_shared()
  158. { this->unlock_sharable(); }
  159. //Upgradable locking
  160. //!Requires: The calling thread does not own the mutex.
  161. //!
  162. //!Effects: The calling thread tries to obtain upgradable ownership of the mutex,
  163. //! and if another thread has exclusive or upgradable ownership of the mutex,
  164. //! waits until it can obtain the ownership.
  165. //!Throws: interprocess_exception on error.
  166. //!
  167. //!Note: A program may deadlock if the thread that has ownership calls
  168. //! this function. If the implementation can detect the deadlock,
  169. //! an exception could be thrown.
  170. void lock_upgradable();
  171. //!Requires: The calling thread does not own the mutex.
  172. //!
  173. //!Effects: The calling thread tries to acquire upgradable ownership of the mutex
  174. //! without waiting. If no other thread has exclusive or upgradable ownership
  175. //! of the mutex this succeeds.
  176. //!Returns: If it can acquire upgradable ownership immediately returns true.
  177. //! If it has to wait, returns false.
  178. //!Throws: interprocess_exception on error.
  179. //!
  180. //!Note: A program may deadlock if the thread that has ownership calls
  181. //! this function. If the implementation can detect the deadlock,
  182. //! an exception could be thrown.
  183. bool try_lock_upgradable();
  184. //!Requires: The calling thread does not own the mutex.
  185. //!
  186. //!Effects: The calling thread tries to acquire upgradable ownership of the mutex
  187. //! waiting if necessary until no other thread has exclusive or upgradable
  188. //! ownership of the mutex or abs_time is reached.
  189. //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false.
  190. //!Throws: interprocess_exception on error.
  191. //!
  192. //!Note: A program may deadlock if the thread that has ownership calls
  193. //! this function. If the implementation can detect the deadlock,
  194. //! an exception could be thrown.
  195. template<class TimePoint>
  196. bool timed_lock_upgradable(const TimePoint &abs_time);
  197. //!Precondition: The thread must have upgradable ownership of the mutex.
  198. //!Effects: The calling thread releases the upgradable ownership of the mutex.
  199. //!Throws: An exception derived from interprocess_exception on error.
  200. void unlock_upgradable();
  201. //Demotions
  202. //!Precondition: The thread must have exclusive ownership of the mutex.
  203. //!Effects: The thread atomically releases exclusive ownership and acquires
  204. //! upgradable ownership. This operation is non-blocking.
  205. //!Throws: An exception derived from interprocess_exception on error.
  206. void unlock_and_lock_upgradable();
  207. //!Precondition: The thread must have exclusive ownership of the mutex.
  208. //!Effects: The thread atomically releases exclusive ownership and acquires
  209. //! sharable ownership. This operation is non-blocking.
  210. //!Throws: An exception derived from interprocess_exception on error.
  211. void unlock_and_lock_sharable();
  212. //!Precondition: The thread must have upgradable ownership of the mutex.
  213. //!Effects: The thread atomically releases upgradable ownership and acquires
  214. //! sharable ownership. This operation is non-blocking.
  215. //!Throws: An exception derived from interprocess_exception on error.
  216. void unlock_upgradable_and_lock_sharable();
  217. //Promotions
  218. //!Precondition: The thread must have upgradable ownership of the mutex.
  219. //!Effects: The thread atomically releases upgradable ownership and acquires
  220. //! exclusive ownership. This operation will block until all threads with
  221. //! sharable ownership release their sharable lock.
  222. //!Throws: An exception derived from interprocess_exception on error.
  223. void unlock_upgradable_and_lock();
  224. //!Precondition: The thread must have upgradable ownership of the mutex.
  225. //!Effects: The thread atomically releases upgradable ownership and tries to
  226. //! acquire exclusive ownership. This operation will fail if there are threads
  227. //! with sharable ownership, but it will maintain upgradable ownership.
  228. //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
  229. //!Throws: An exception derived from interprocess_exception on error.
  230. bool try_unlock_upgradable_and_lock();
  231. //!Precondition: The thread must have upgradable ownership of the mutex.
  232. //!Effects: The thread atomically releases upgradable ownership and tries to acquire
  233. //! exclusive ownership, waiting if necessary until abs_time. This operation will
  234. //! fail if there are threads with sharable ownership or timeout reaches, but it
  235. //! will maintain upgradable ownership.
  236. //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
  237. //!Throws: An exception derived from interprocess_exception on error. */
  238. template<class TimePoint>
  239. bool timed_unlock_upgradable_and_lock(const TimePoint &abs_time);
  240. //!Precondition: The thread must have sharable ownership of the mutex.
  241. //!Effects: The thread atomically releases sharable ownership and tries to acquire
  242. //! exclusive ownership. This operation will fail if there are threads with sharable
  243. //! or upgradable ownership, but it will maintain sharable ownership.
  244. //!Returns: If acquires exclusive ownership, returns true. Otherwise returns false.
  245. //!Throws: An exception derived from interprocess_exception on error.
  246. bool try_unlock_sharable_and_lock();
  247. //!Precondition: The thread must have sharable ownership of the mutex.
  248. //!Effects: The thread atomically releases sharable ownership and tries to acquire
  249. //! upgradable ownership. This operation will fail if there are threads with sharable
  250. //! or upgradable ownership, but it will maintain sharable ownership.
  251. //!Returns: If acquires upgradable ownership, returns true. Otherwise returns false.
  252. //!Throws: An exception derived from interprocess_exception on error.
  253. bool try_unlock_sharable_and_lock_upgradable();
  254. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  255. private:
  256. typedef scoped_lock<interprocess_mutex> scoped_lock_t;
  257. //Pack all the control data in a word to be able
  258. //to use atomic instructions in the future
  259. struct control_word_t
  260. {
  261. unsigned exclusive_in : 1;
  262. unsigned upgradable_in : 1;
  263. unsigned num_upr_shar : sizeof(unsigned)*CHAR_BIT-2;
  264. } m_ctrl;
  265. interprocess_mutex m_mut;
  266. interprocess_condition m_first_gate;
  267. interprocess_condition m_second_gate;
  268. private:
  269. //Rollback structures for exceptions or failure return values
  270. struct exclusive_rollback
  271. {
  272. exclusive_rollback(control_word_t &ctrl
  273. ,interprocess_condition &first_gate)
  274. : mp_ctrl(&ctrl), m_first_gate(first_gate)
  275. {}
  276. void release()
  277. { mp_ctrl = 0; }
  278. ~exclusive_rollback()
  279. {
  280. if(mp_ctrl){
  281. mp_ctrl->exclusive_in = 0;
  282. m_first_gate.notify_all();
  283. }
  284. }
  285. control_word_t *mp_ctrl;
  286. interprocess_condition &m_first_gate;
  287. };
  288. struct upgradable_to_exclusive_rollback
  289. {
  290. upgradable_to_exclusive_rollback(control_word_t &ctrl)
  291. : mp_ctrl(&ctrl)
  292. {}
  293. void release()
  294. { mp_ctrl = 0; }
  295. ~upgradable_to_exclusive_rollback()
  296. {
  297. if(mp_ctrl){
  298. //Recover upgradable lock
  299. mp_ctrl->upgradable_in = 1;
  300. ++mp_ctrl->num_upr_shar;
  301. //Execute the second half of exclusive locking
  302. mp_ctrl->exclusive_in = 0;
  303. }
  304. }
  305. control_word_t *mp_ctrl;
  306. };
  307. template<int Dummy>
  308. struct base_constants_t
  309. {
  310. static const unsigned max_readers
  311. = ~(unsigned(3) << (sizeof(unsigned)*CHAR_BIT-2));
  312. };
  313. typedef base_constants_t<0> constants;
  314. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  315. };
  316. #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
  317. template <int Dummy>
  318. const unsigned interprocess_upgradable_mutex::base_constants_t<Dummy>::max_readers;
  319. inline interprocess_upgradable_mutex::interprocess_upgradable_mutex()
  320. {
  321. this->m_ctrl.exclusive_in = 0;
  322. this->m_ctrl.upgradable_in = 0;
  323. this->m_ctrl.num_upr_shar = 0;
  324. }
  325. inline interprocess_upgradable_mutex::~interprocess_upgradable_mutex()
  326. {}
  327. inline void interprocess_upgradable_mutex::lock()
  328. {
  329. scoped_lock_t lck(m_mut);
  330. //The exclusive lock must block in the first gate
  331. //if an exclusive or upgradable lock has been acquired
  332. while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
  333. this->m_first_gate.wait(lck);
  334. }
  335. //Mark that exclusive lock has been acquired
  336. this->m_ctrl.exclusive_in = 1;
  337. //Prepare rollback
  338. exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
  339. //Now wait until all readers are gone
  340. while (this->m_ctrl.num_upr_shar){
  341. this->m_second_gate.wait(lck);
  342. }
  343. rollback.release();
  344. }
  345. inline bool interprocess_upgradable_mutex::try_lock()
  346. {
  347. scoped_lock_t lck(m_mut, try_to_lock);
  348. //If we can't lock or any has there is any exclusive, upgradable
  349. //or sharable mark return false;
  350. if(!lck.owns()
  351. || this->m_ctrl.exclusive_in
  352. || this->m_ctrl.num_upr_shar){
  353. return false;
  354. }
  355. this->m_ctrl.exclusive_in = 1;
  356. return true;
  357. }
  358. template<class TimePoint>
  359. bool interprocess_upgradable_mutex::timed_lock(const TimePoint &abs_time)
  360. {
  361. //Mutexes and condvars handle just fine infinite abs_times
  362. //so avoid checking it here
  363. scoped_lock_t lck(m_mut, abs_time);
  364. if(!lck.owns()) return false;
  365. //The exclusive lock must block in the first gate
  366. //if an exclusive or upgradable lock has been acquired
  367. while (this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
  368. if(!this->m_first_gate.timed_wait(lck, abs_time)){
  369. if(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in){
  370. return false;
  371. }
  372. break;
  373. }
  374. }
  375. //Mark that exclusive lock has been acquired
  376. this->m_ctrl.exclusive_in = 1;
  377. //Prepare rollback
  378. exclusive_rollback rollback(this->m_ctrl, this->m_first_gate);
  379. //Now wait until all readers are gone
  380. while (this->m_ctrl.num_upr_shar){
  381. if(!this->m_second_gate.timed_wait(lck, abs_time)){
  382. if(this->m_ctrl.num_upr_shar){
  383. return false;
  384. }
  385. break;
  386. }
  387. }
  388. rollback.release();
  389. return true;
  390. }
  391. inline void interprocess_upgradable_mutex::unlock()
  392. {
  393. scoped_lock_t lck(m_mut);
  394. this->m_ctrl.exclusive_in = 0;
  395. this->m_first_gate.notify_all();
  396. }
  397. //Upgradable locking
  398. inline void interprocess_upgradable_mutex::lock_upgradable()
  399. {
  400. scoped_lock_t lck(m_mut);
  401. //The upgradable lock must block in the first gate
  402. //if an exclusive or upgradable lock has been acquired
  403. //or there are too many sharable locks
  404. while(this->m_ctrl.exclusive_in || this->m_ctrl.upgradable_in
  405. || this->m_ctrl.num_upr_shar == constants::max_readers){
  406. this->m_first_gate.wait(lck);
  407. }
  408. //Mark that upgradable lock has been acquired
  409. //And add upgradable to the sharable count
  410. this->m_ctrl.upgradable_in = 1;
  411. ++this->m_ctrl.num_upr_shar;
  412. }
  413. inline bool interprocess_upgradable_mutex::try_lock_upgradable()
  414. {
  415. scoped_lock_t lck(m_mut, try_to_lock);
  416. //The upgradable lock must fail
  417. //if an exclusive or upgradable lock has been acquired
  418. //or there are too many sharable locks
  419. if(!lck.owns()
  420. || this->m_ctrl.exclusive_in
  421. || this->m_ctrl.upgradable_in
  422. || this->m_ctrl.num_upr_shar == constants::max_readers){
  423. return false;
  424. }
  425. //Mark that upgradable lock has been acquired
  426. //And add upgradable to the sharable count
  427. this->m_ctrl.upgradable_in = 1;
  428. ++this->m_ctrl.num_upr_shar;
  429. return true;
  430. }
  431. template<class TimePoint>
  432. bool interprocess_upgradable_mutex::timed_lock_upgradable(const TimePoint &abs_time)
  433. {
  434. //Mutexes and condvars handle just fine infinite abs_times
  435. //so avoid checking it here
  436. scoped_lock_t lck(m_mut, abs_time);
  437. if(!lck.owns()) return false;
  438. //The upgradable lock must block in the first gate
  439. //if an exclusive or upgradable lock has been acquired
  440. //or there are too many sharable locks
  441. while(this->m_ctrl.exclusive_in
  442. || this->m_ctrl.upgradable_in
  443. || this->m_ctrl.num_upr_shar == constants::max_readers){
  444. if(!this->m_first_gate.timed_wait(lck, abs_time)){
  445. if((this->m_ctrl.exclusive_in
  446. || this->m_ctrl.upgradable_in
  447. || this->m_ctrl.num_upr_shar == constants::max_readers)){
  448. return false;
  449. }
  450. break;
  451. }
  452. }
  453. //Mark that upgradable lock has been acquired
  454. //And add upgradable to the sharable count
  455. this->m_ctrl.upgradable_in = 1;
  456. ++this->m_ctrl.num_upr_shar;
  457. return true;
  458. }
  459. inline void interprocess_upgradable_mutex::unlock_upgradable()
  460. {
  461. scoped_lock_t lck(m_mut);
  462. //Mark that upgradable lock has been acquired
  463. //And add upgradable to the sharable count
  464. this->m_ctrl.upgradable_in = 0;
  465. --this->m_ctrl.num_upr_shar;
  466. this->m_first_gate.notify_all();
  467. }
  468. //Sharable locking
  469. inline void interprocess_upgradable_mutex::lock_sharable()
  470. {
  471. scoped_lock_t lck(m_mut);
  472. //The sharable lock must block in the first gate
  473. //if an exclusive lock has been acquired
  474. //or there are too many sharable locks
  475. while(this->m_ctrl.exclusive_in
  476. || this->m_ctrl.num_upr_shar == constants::max_readers){
  477. this->m_first_gate.wait(lck);
  478. }
  479. //Increment sharable count
  480. ++this->m_ctrl.num_upr_shar;
  481. }
  482. inline bool interprocess_upgradable_mutex::try_lock_sharable()
  483. {
  484. scoped_lock_t lck(m_mut, try_to_lock);
  485. //The sharable lock must fail
  486. //if an exclusive lock has been acquired
  487. //or there are too many sharable locks
  488. if(!lck.owns()
  489. || this->m_ctrl.exclusive_in
  490. || this->m_ctrl.num_upr_shar == constants::max_readers){
  491. return false;
  492. }
  493. //Increment sharable count
  494. ++this->m_ctrl.num_upr_shar;
  495. return true;
  496. }
  497. template<class TimePoint>
  498. inline bool interprocess_upgradable_mutex::timed_lock_sharable(const TimePoint &abs_time)
  499. {
  500. //Mutexes and condvars handle just fine infinite abs_times
  501. //so avoid checking it here
  502. scoped_lock_t lck(m_mut, abs_time);
  503. if(!lck.owns()) return false;
  504. //The sharable lock must block in the first gate
  505. //if an exclusive lock has been acquired
  506. //or there are too many sharable locks
  507. while (this->m_ctrl.exclusive_in
  508. || this->m_ctrl.num_upr_shar == constants::max_readers){
  509. if(!this->m_first_gate.timed_wait(lck, abs_time)){
  510. if(this->m_ctrl.exclusive_in
  511. || this->m_ctrl.num_upr_shar == constants::max_readers){
  512. return false;
  513. }
  514. break;
  515. }
  516. }
  517. //Increment sharable count
  518. ++this->m_ctrl.num_upr_shar;
  519. return true;
  520. }
  521. inline void interprocess_upgradable_mutex::unlock_sharable()
  522. {
  523. scoped_lock_t lck(m_mut);
  524. //Decrement sharable count
  525. --this->m_ctrl.num_upr_shar;
  526. if (this->m_ctrl.num_upr_shar == 0){
  527. this->m_second_gate.notify_one();
  528. }
  529. //Check if there are blocked sharables because of
  530. //there were too many sharables
  531. else if(this->m_ctrl.num_upr_shar == (constants::max_readers-1)){
  532. this->m_first_gate.notify_all();
  533. }
  534. }
  535. //Downgrading
  536. inline void interprocess_upgradable_mutex::unlock_and_lock_upgradable()
  537. {
  538. scoped_lock_t lck(m_mut);
  539. //Unmark it as exclusive
  540. this->m_ctrl.exclusive_in = 0;
  541. //Mark it as upgradable
  542. this->m_ctrl.upgradable_in = 1;
  543. //The sharable count should be 0 so increment it
  544. this->m_ctrl.num_upr_shar = 1;
  545. //Notify readers that they can enter
  546. m_first_gate.notify_all();
  547. }
  548. inline void interprocess_upgradable_mutex::unlock_and_lock_sharable()
  549. {
  550. scoped_lock_t lck(m_mut);
  551. //Unmark it as exclusive
  552. this->m_ctrl.exclusive_in = 0;
  553. //The sharable count should be 0 so increment it
  554. this->m_ctrl.num_upr_shar = 1;
  555. //Notify readers that they can enter
  556. m_first_gate.notify_all();
  557. }
  558. inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock_sharable()
  559. {
  560. scoped_lock_t lck(m_mut);
  561. //Unmark it as upgradable (we don't have to decrement count)
  562. this->m_ctrl.upgradable_in = 0;
  563. //Notify readers/upgradable that they can enter
  564. m_first_gate.notify_all();
  565. }
  566. //Upgrading
  567. inline void interprocess_upgradable_mutex::unlock_upgradable_and_lock()
  568. {
  569. scoped_lock_t lck(m_mut);
  570. //Simulate unlock_upgradable() without
  571. //notifying sharables.
  572. this->m_ctrl.upgradable_in = 0;
  573. --this->m_ctrl.num_upr_shar;
  574. //Execute the second half of exclusive locking
  575. this->m_ctrl.exclusive_in = 1;
  576. //Prepare rollback
  577. upgradable_to_exclusive_rollback rollback(m_ctrl);
  578. while (this->m_ctrl.num_upr_shar){
  579. this->m_second_gate.wait(lck);
  580. }
  581. rollback.release();
  582. }
  583. inline bool interprocess_upgradable_mutex::try_unlock_upgradable_and_lock()
  584. {
  585. scoped_lock_t lck(m_mut, try_to_lock);
  586. //Check if there are no readers
  587. if(!lck.owns()
  588. || this->m_ctrl.num_upr_shar != 1){
  589. return false;
  590. }
  591. //Now unlock upgradable and mark exclusive
  592. this->m_ctrl.upgradable_in = 0;
  593. --this->m_ctrl.num_upr_shar;
  594. this->m_ctrl.exclusive_in = 1;
  595. return true;
  596. }
  597. template<class TimePoint>
  598. bool interprocess_upgradable_mutex::timed_unlock_upgradable_and_lock(const TimePoint &abs_time)
  599. {
  600. //Mutexes and condvars handle just fine infinite abs_times
  601. //so avoid checking it here
  602. scoped_lock_t lck(m_mut, abs_time);
  603. if(!lck.owns()) return false;
  604. //Simulate unlock_upgradable() without
  605. //notifying sharables.
  606. this->m_ctrl.upgradable_in = 0;
  607. --this->m_ctrl.num_upr_shar;
  608. //Execute the second half of exclusive locking
  609. this->m_ctrl.exclusive_in = 1;
  610. //Prepare rollback
  611. upgradable_to_exclusive_rollback rollback(m_ctrl);
  612. while (this->m_ctrl.num_upr_shar){
  613. if(!this->m_second_gate.timed_wait(lck, abs_time)){
  614. if(this->m_ctrl.num_upr_shar){
  615. return false;
  616. }
  617. break;
  618. }
  619. }
  620. rollback.release();
  621. return true;
  622. }
  623. inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock()
  624. {
  625. scoped_lock_t lck(m_mut, try_to_lock);
  626. //If we can't lock or any has there is any exclusive, upgradable
  627. //or sharable mark return false;
  628. if(!lck.owns()
  629. || this->m_ctrl.exclusive_in
  630. || this->m_ctrl.upgradable_in
  631. || this->m_ctrl.num_upr_shar != 1){
  632. return false;
  633. }
  634. this->m_ctrl.exclusive_in = 1;
  635. this->m_ctrl.num_upr_shar = 0;
  636. return true;
  637. }
  638. inline bool interprocess_upgradable_mutex::try_unlock_sharable_and_lock_upgradable()
  639. {
  640. scoped_lock_t lck(m_mut, try_to_lock);
  641. //The upgradable lock must fail
  642. //if an exclusive or upgradable lock has been acquired
  643. if(!lck.owns()
  644. || this->m_ctrl.exclusive_in
  645. || this->m_ctrl.upgradable_in){
  646. return false;
  647. }
  648. //Mark that upgradable lock has been acquired
  649. this->m_ctrl.upgradable_in = 1;
  650. return true;
  651. }
  652. #endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
  653. } //namespace interprocess {
  654. } //namespace boost {
  655. #include <boost/interprocess/detail/config_end.hpp>
  656. #endif //BOOST_INTERPROCESS_UPGRADABLE_MUTEX_HPP