interprocess_upgradable_mutex.hpp 25 KB

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