annotate DEPENDENCIES/generic/include/boost/interprocess/sync/interprocess_upgradable_mutex.hpp @ 125:34e428693f5d vext

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