interprocess_upgradable_mutex.hpp 27 KB

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