| 100 | } |
| 101 | |
| 102 | bool GlobalRWLock::lockWrite(thread_db* tdbb, SSHORT wait) |
| 103 | { |
| 104 | SET_TDBB(tdbb); |
| 105 | |
| 106 | { // scope 1 |
| 107 | CheckoutLockGuard counterGuard(tdbb, counterMutex, FB_FUNCTION, true); |
| 108 | |
| 109 | COS_TRACE(("(%p)->lockWrite stage 1 readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)", |
| 110 | this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical)); |
| 111 | ++pendingWriters; |
| 112 | |
| 113 | while (readers > 0 ) |
| 114 | { |
| 115 | EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY); |
| 116 | noReaders.wait(counterMutex); |
| 117 | } |
| 118 | |
| 119 | COS_TRACE(("(%p)->lockWrite stage 2 readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)", |
| 120 | this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical)); |
| 121 | |
| 122 | while (currentWriter || pendingLock) |
| 123 | { |
| 124 | EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY); |
| 125 | writerFinished.wait(counterMutex); |
| 126 | } |
| 127 | |
| 128 | COS_TRACE(("(%p)->lockWrite stage 3 readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)", |
| 129 | this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical)); |
| 130 | |
| 131 | fb_assert(!readers && !currentWriter); |
| 132 | |
| 133 | if (cachedLock->lck_physical == LCK_write) |
| 134 | { |
| 135 | --pendingWriters; |
| 136 | |
| 137 | fb_assert(!currentWriter); |
| 138 | currentWriter = true; |
| 139 | |
| 140 | return true; |
| 141 | } |
| 142 | |
| 143 | if (cachedLock->lck_physical > LCK_none) |
| 144 | { |
| 145 | LCK_release(tdbb, cachedLock); // To prevent self deadlock |
| 146 | invalidate(tdbb); |
| 147 | } |
| 148 | |
| 149 | ++pendingLock; |
| 150 | } |
| 151 | |
| 152 | COS_TRACE(("(%p)->lockWrite LCK_lock readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d), pendingLock(%d)", |
| 153 | this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical, pendingLock)); |
| 154 | |
| 155 | if (!LCK_lock(tdbb, cachedLock, LCK_write, wait)) |
| 156 | { |
| 157 | FbStatusVector* const vector = tdbb->tdbb_status_vector; |
| 158 | const ISC_STATUS* status = vector->getErrors(); |
| 159 | if ((wait == LCK_NO_WAIT) || ((wait < 0) && (status[1] == isc_lock_timeout))) |