A method to acquire queuing_rw_mutex lock
| 142 | |
| 143 | //! A method to acquire queuing_rw_mutex lock |
| 144 | void queuing_rw_mutex::scoped_lock::acquire( queuing_rw_mutex& m, bool write ) |
| 145 | { |
| 146 | __TBB_ASSERT( !my_mutex, "scoped_lock is already holding a mutex"); |
| 147 | |
| 148 | // Must set all fields before the fetch_and_store, because once the |
| 149 | // fetch_and_store executes, *this becomes accessible to other threads. |
| 150 | my_mutex = &m; |
| 151 | __TBB_store_relaxed(my_prev , (scoped_lock*)0); |
| 152 | __TBB_store_relaxed(my_next , (scoped_lock*)0); |
| 153 | __TBB_store_relaxed(my_going, 0); |
| 154 | my_state = state_t(write ? STATE_WRITER : STATE_READER); |
| 155 | my_internal_lock = RELEASED; |
| 156 | |
| 157 | queuing_rw_mutex::scoped_lock* pred = m.q_tail.fetch_and_store<tbb::release>(this); |
| 158 | |
| 159 | if( write ) { // Acquiring for write |
| 160 | |
| 161 | if( pred ) { |
| 162 | ITT_NOTIFY(sync_prepare, my_mutex); |
| 163 | pred = tricky_pointer(pred) & ~FLAG; |
| 164 | __TBB_ASSERT( !( uintptr_t(pred) & FLAG ), "use of corrupted pointer!" ); |
| 165 | #if TBB_USE_ASSERT |
| 166 | __TBB_control_consistency_helper(); // on "m.q_tail" |
| 167 | __TBB_ASSERT( !__TBB_load_relaxed(pred->my_next), "the predecessor has another successor!"); |
| 168 | #endif |
| 169 | __TBB_store_with_release(pred->my_next,this); |
| 170 | spin_wait_until_eq(my_going, 1); |
| 171 | } |
| 172 | |
| 173 | } else { // Acquiring for read |
| 174 | #if DO_ITT_NOTIFY |
| 175 | bool sync_prepare_done = false; |
| 176 | #endif |
| 177 | if( pred ) { |
| 178 | unsigned short pred_state; |
| 179 | __TBB_ASSERT( !__TBB_load_relaxed(my_prev), "the predecessor is already set" ); |
| 180 | if( uintptr_t(pred) & FLAG ) { |
| 181 | /* this is only possible if pred is an upgrading reader and it signals us to wait */ |
| 182 | pred_state = STATE_UPGRADE_WAITING; |
| 183 | pred = tricky_pointer(pred) & ~FLAG; |
| 184 | } else { |
| 185 | // Load pred->my_state now, because once pred->my_next becomes |
| 186 | // non-NULL, we must assume that *pred might be destroyed. |
| 187 | pred_state = pred->my_state.compare_and_swap<tbb::acquire>(STATE_READER_UNBLOCKNEXT, STATE_READER); |
| 188 | } |
| 189 | __TBB_store_relaxed(my_prev, pred); |
| 190 | __TBB_ASSERT( !( uintptr_t(pred) & FLAG ), "use of corrupted pointer!" ); |
| 191 | #if TBB_USE_ASSERT |
| 192 | __TBB_control_consistency_helper(); // on "m.q_tail" |
| 193 | __TBB_ASSERT( !__TBB_load_relaxed(pred->my_next), "the predecessor has another successor!"); |
| 194 | #endif |
| 195 | __TBB_store_with_release(pred->my_next,this); |
| 196 | if( pred_state != STATE_ACTIVEREADER ) { |
| 197 | #if DO_ITT_NOTIFY |
| 198 | sync_prepare_done = true; |
| 199 | ITT_NOTIFY(sync_prepare, my_mutex); |
| 200 | #endif |
| 201 | spin_wait_until_eq(my_going, 1); |
nothing calls this directly
no test coverage detected