/** Returns whether the upgrade happened without releasing and re-acquiring the lock */ bool x86_rtm_rw_mutex::internal_upgrade(x86_rtm_rw_mutex::scoped_lock& s) { switch(s.transaction_state) { case RTM_real_reader: { s.transaction_state = RTM_real_writer; bool no_release = s.my_scoped_lock.upgrade_to_writer(); __TBB_ASSERT(!w_flag, "After upgrade_to_writer, w_flag already true"); w_flag = true; return no_release; } case RTM_transacting_reader: #if !__TBB_RW_MUTEX_DELAY_TEST if(this->state) { // add spin_rw_mutex to read-set. // Real reader or writer holds the lock; so commit the read and re-acquire for write. internal_release(s); internal_acquire_writer(s); return false; } else #endif { s.transaction_state = RTM_transacting_writer; return true; } default: __TBB_ASSERT(false, "Invalid state for upgrade"); return false; } }
/** Returns true if the upgrade happened without re-acquiring the lock and false if opposite */ bool spin_rw_mutex_v3::internal_upgrade() { state_t s = state; __TBB_ASSERT( s & READERS, "invalid state before upgrade: no readers " ); // check and set writer-pending flag // required conditions: either no pending writers, or we are the only reader // (with multiple readers and pending writer, another upgrade could have been requested) while( (s & READERS)==ONE_READER || !(s & WRITER_PENDING) ) { state_t old_s = s; if( (s=CAS(state, s | WRITER | WRITER_PENDING, s))==old_s ) { internal::atomic_backoff backoff; ITT_NOTIFY(sync_prepare, this); // the state should be 0...0111, i.e. 1 reader and waiting writer; // both new readers and writers are blocked while( (state & READERS) != ONE_READER ) // more than 1 reader backoff.pause(); __TBB_ASSERT((state&(WRITER_PENDING|WRITER))==(WRITER_PENDING|WRITER),"invalid state when upgrading to writer"); __TBB_FetchAndAddW( &state, - (intptr_t)(ONE_READER+WRITER_PENDING)); ITT_NOTIFY(sync_acquired, this); return true; // successfully upgraded } } // slow reacquire internal_release_reader(); return internal_acquire_writer(); // always returns false }
//! Try to acquire write lock on the given mutex. // There may be reader(s) which acquired the spin_rw_mutex, as well as possibly // transactional reader(s). If this is the case, the acquire will fail, and assigning // w_flag will kill the transactors. So we only assign w_flag if we have successfully // acquired the lock. bool x86_rtm_rw_mutex::internal_try_acquire_writer(x86_rtm_rw_mutex::scoped_lock& s) { internal_acquire_writer(s, /*only_speculate=*/true); if(s.transaction_state == RTM_transacting_writer) { return true; } __TBB_ASSERT(s.transaction_state == RTM_not_in_mutex, "Trying to acquire writer which is already allocated"); // transacting write acquire failed. try_acquire the real mutex bool result = s.my_scoped_lock.try_acquire(*this, true); if(result) { // only shoot down readers if we're not transacting ourselves __TBB_ASSERT(!w_flag, "After try_acquire_writer, w_flag already true"); w_flag = true; s.transaction_state = RTM_real_writer; } return result; }