interprocess_upgradable_mutex.hpp 22 KB

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