interprocess_upgradable_mutex.hpp 22 KB

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