void GlobalRWLock::unlockWrite(thread_db* tdbb, const bool release) { SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); Database::CheckoutLockGuard counterGuard(dbb, counterMutex); COS_TRACE(("(%p)->unlockWrite readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)", this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical)); currentWriter = false; if (!lockCaching || release) LCK_release(tdbb, cachedLock); else if (blocking) LCK_downgrade(tdbb, cachedLock); blocking = false; if (cachedLock->lck_physical < LCK_read) invalidate(tdbb); writerFinished.notifyAll(); COS_TRACE(("(%p)->unlockWrite end readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)", this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical)); }
void GlobalRWLock::unlockRead(thread_db* tdbb) { SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); Database::CheckoutLockGuard counterGuard(dbb, counterMutex); COS_TRACE(("(%p)->unlockRead readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)", this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical)); readers--; if (!readers) { if (!lockCaching || pendingWriters || blocking) { LCK_release(tdbb, cachedLock); // Release since concurrent request needs LCK_write invalidate(tdbb); } noReaders.notifyAll(); } COS_TRACE(("(%p)->unlockRead end readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)", this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical)); }
void Database::SharedCounter::shutdown(thread_db* tdbb) { for (size_t i = 0; i < TOTAL_ITEMS; i++) { if (m_counters[i].lock) LCK_release(tdbb, m_counters[i].lock); } }
void CryptoManager::blockingAstChangeCryptState() { AsyncContextHolder tdbb(&dbb, FB_FUNCTION); fb_assert(stateLock); LCK_release(tdbb, stateLock); needLock = true; }
void Collation::release(thread_db* tdbb) { fb_assert(useCount >= 0); if (existenceLock) LCK_release(tdbb, existenceLock); useCount = 0; }
void Database::clearSweepFlags(thread_db* tdbb) { if (!(dbb_flags & (DBB_sweep_starting | DBB_sweep_in_progress))) return; if (dbb_sweep_lock) LCK_release(tdbb, dbb_sweep_lock); dbb_flags &= ~(DBB_sweep_in_progress | DBB_sweep_starting); }
int Database::blocking_ast_sweep(void* ast_object) { Database* dbb = static_cast<Database*>(ast_object); AsyncContextHolder tdbb(dbb, FB_FUNCTION); if ((dbb->dbb_flags & DBB_sweep_starting) && !(dbb->dbb_flags & DBB_sweep_in_progress)) { dbb->dbb_flags &= ~DBB_sweep_starting; LCK_release(tdbb, dbb->dbb_sweep_lock); } return 0; }
void CryptoManager::shutdown(thread_db* tdbb) { terminateCryptThread(tdbb); if (cryptPlugin) { PluginManagerInterfacePtr()->releasePlugin(cryptPlugin); cryptPlugin = NULL; } if (stateLock) { LCK_release(tdbb, stateLock); stateLock = NULL; } }
void GlobalRWLock::shutdownLock() { thread_db* tdbb = JRD_get_thread_data(); Database::CheckoutLockGuard counterGuard(tdbb->getDatabase(), counterMutex); COS_TRACE(("(%p)->shutdownLock readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)", this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical)); if (!cachedLock) return; LCK_release(tdbb, cachedLock); delete cachedLock; cachedLock = NULL; }
bool GlobalRWLock::tryReleaseLock(thread_db* tdbb) { Database::CheckoutLockGuard counterGuard(tdbb->getDatabase(), counterMutex); COS_TRACE(("(%p)->tryReleaseLock readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)", this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical)); if (readers || currentWriter) return false; if (cachedLock->lck_physical > LCK_none) { LCK_release(tdbb, cachedLock); invalidate(tdbb); } return true; }
bool GlobalRWLock::lockWrite(thread_db* tdbb, SSHORT wait) { SET_TDBB(tdbb); Database* dbb = tdbb->getDatabase(); { // scope 1 Database::CheckoutLockGuard counterGuard(dbb, counterMutex); COS_TRACE(("(%p)->lockWrite stage 1 readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)", this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical)); ++pendingWriters; while (readers > 0 ) { Database::Checkout checkoutDbb(dbb); noReaders.wait(counterMutex); } COS_TRACE(("(%p)->lockWrite stage 2 readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)", this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical)); while (currentWriter || pendingLock) { Database::Checkout checkoutDbb(dbb); writerFinished.wait(counterMutex); } COS_TRACE(("(%p)->lockWrite stage 3 readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)", this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical)); fb_assert(!readers && !currentWriter); if (cachedLock->lck_physical > LCK_none) { LCK_release(tdbb, cachedLock); // To prevent self deadlock invalidate(tdbb); } ++pendingLock; } COS_TRACE(("(%p)->lockWrite LCK_lock readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d), pendingLock(%d)", this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical, pendingLock)); if (!LCK_lock(tdbb, cachedLock, LCK_write, wait)) { Database::CheckoutLockGuard counterGuard(dbb, counterMutex); --pendingLock; if (--pendingWriters) { if (!currentWriter) writerFinished.notifyAll(); } return false; } { // scope 2 Database::CheckoutLockGuard counterGuard(dbb, counterMutex); --pendingLock; --pendingWriters; fb_assert(!currentWriter); currentWriter = true; COS_TRACE(("(%p)->lockWrite end readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)", this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical)); return fetch(tdbb); } }
// Remove a routine from cache. void Routine::remove(thread_db* tdbb) { SET_TDBB(tdbb); Jrd::Attachment* att = tdbb->getAttachment(); // MET_procedure locks it. Lets unlock it now to avoid troubles later if (existenceLock) LCK_release(tdbb, existenceLock); // Routine that is being altered may have references // to it by other routines via pointer to current meta // data structure, so don't lose the structure or the pointer. if (checkCache(tdbb) && !(flags & Routine::FLAG_BEING_ALTERED)) clearCache(tdbb); // deallocate all structure which were allocated. The routine // blr is originally read into a new pool from which all request // are allocated. That will not be freed up. if (existenceLock) { delete existenceLock; existenceLock = NULL; } // deallocate input param structures for (Array<NestConst<Parameter> >::iterator i = getInputFields().begin(); i != getInputFields().end(); ++i) { if (*i) delete i->getObject(); } getInputFields().clear(); // deallocate output param structures for (Array<NestConst<Parameter> >::iterator i = getOutputFields().begin(); i != getOutputFields().end(); ++i) { if (*i) delete i->getObject(); } getOutputFields().clear(); if (!useCount) releaseFormat(); if (!(flags & Routine::FLAG_BEING_ALTERED) && useCount == 0) delete this; else { // Fully clear routine block. Some pieces of code check for empty // routine name and ID, this is why we do it. setName(QualifiedName()); setSecurityName(""); setId(0); setDefaultCount(0); } }
void CryptoManager::cryptThread() { ISC_STATUS_ARRAY status_vector; try { // Try to take crypt mutex // If can't take that mutex - nothing to do, cryptThread already runs in our process MutexEnsureUnlock guard(cryptThreadMtx, FB_FUNCTION); if (!guard.tryEnter()) { return; } // establish context UserId user; user.usr_user_name = "(Crypt thread)"; Jrd::Attachment* const attachment = Jrd::Attachment::create(&dbb); RefPtr<SysAttachment> jAtt(new SysAttachment(attachment)); attachment->att_interface = jAtt; attachment->att_filename = dbb.dbb_filename; attachment->att_user = &user; BackgroundContextHolder tdbb(&dbb, attachment, status_vector, FB_FUNCTION); tdbb->tdbb_quantum = SWEEP_QUANTUM; ULONG lastPage = getLastPage(tdbb); ULONG runpage = 1; Stack<ULONG> pages; // Take exclusive threadLock // If can't take that lock - nothing to do, cryptThread already runs somewhere if (!LCK_lock(tdbb, threadLock, LCK_EX, LCK_NO_WAIT)) { return; } bool lckRelease = false; try { do { // Check is there some job to do while ((runpage = currentPage.exchangeAdd(+1)) < lastPage) { // forced terminate if (down) { break; } // nbackup state check if (dbb.dbb_backup_manager && dbb.dbb_backup_manager->getState() != nbak_state_normal) { if (currentPage.exchangeAdd(-1) >= lastPage) { // currentPage was set to last page by thread, closing database break; } THD_sleep(100); continue; } // scheduling if (--tdbb->tdbb_quantum < 0) { JRD_reschedule(tdbb, SWEEP_QUANTUM, true); } // writing page to disk will change it's crypt status in usual way WIN window(DB_PAGE_SPACE, runpage); Ods::pag* page = CCH_FETCH(tdbb, &window, LCK_write, pag_undefined); if (page && page->pag_type <= pag_max && (bool(page->pag_flags & Ods::crypted_page) != crypt) && Ods::pag_crypt_page[page->pag_type]) { CCH_MARK(tdbb, &window); pages.push(runpage); } CCH_RELEASE_TAIL(tdbb, &window); // sometimes save currentPage into DB header ++runpage; if ((runpage & 0x3FF) == 0) { writeDbHeader(tdbb, runpage, pages); } } // At this moment of time all pages with number < lastpage // are guaranteed to change crypt state. Check for added pages. lastPage = getLastPage(tdbb); // forced terminate if (down) { break; } } while (runpage < lastPage); // Finalize crypt if (!down) { writeDbHeader(tdbb, 0, pages); } // Release exclusive lock on StartCryptThread lckRelease = true; LCK_release(tdbb, threadLock); } catch (const Exception&) { try { if (!lckRelease) { // try to save current state of crypt thread if (!down) { writeDbHeader(tdbb, runpage, pages); } // Release exclusive lock on StartCryptThread LCK_release(tdbb, threadLock); } } catch (const Exception&) { } throw; } } catch (const Exception& ex) { // Error during context creation - we can't even release lock iscLogException("Crypt thread:", ex); } }
void CryptoManager::startCryptThread(thread_db* tdbb) { // Try to take crypt mutex // If can't take that mutex - nothing to do, cryptThread already runs in our process MutexEnsureUnlock guard(cryptThreadMtx, FB_FUNCTION); if (!guard.tryEnter()) { return; } // Take exclusive threadLock // If can't take that lock - nothing to do, cryptThread already runs somewhere if (!LCK_lock(tdbb, threadLock, LCK_EX, LCK_NO_WAIT)) { // Cleanup lock manager error fb_utils::init_status(tdbb->tdbb_status_vector); return; } bool releasingLock = false; try { // Cleanup resources terminateCryptThread(tdbb); down = false; // Determine current page from the header Header hdr(tdbb, LCK_read); process = hdr->hdr_flags & Ods::hdr_crypt_process ? true : false; if (!process) { releasingLock = true; LCK_release(tdbb, threadLock); return; } currentPage.setValue(hdr->hdr_crypt_page); // Refresh encryption flag crypt = hdr->hdr_flags & Ods::hdr_encrypted ? true : false; // If we are going to start crypt thread, we need plugin to be loaded loadPlugin(hdr->hdr_crypt_plugin); // ready to go guard.leave(); // release in advance to avoid races with cryptThread() Thread::start(cryptThreadStatic, (THREAD_ENTRY_PARAM) this, 0, &cryptThreadId); } catch (const Firebird::Exception&) { if (!releasingLock) // avoid secondary exception in catch { try { LCK_release(tdbb, threadLock); } catch (const Firebird::Exception&) { } } throw; } }