2007-04-24 17:44:43 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Access Method
|
|
|
|
* MODULE: GlobalRWLock.cpp
|
|
|
|
* DESCRIPTION: GlobalRWLock
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Initial
|
|
|
|
* Developer's Public License Version 1.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the
|
|
|
|
* License. You may obtain a copy of the License at
|
|
|
|
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed AS IS,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing rights
|
|
|
|
* and limitations under the License.
|
|
|
|
*
|
|
|
|
* The Original Code was created by Nickolay Samofatov
|
|
|
|
* for the Firebird Open Source RDBMS project.
|
|
|
|
*
|
|
|
|
* Copyright (c) 2006 Nickolay Samofatov
|
|
|
|
* and all contributors signed below.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
2009-03-17 08:39:55 +01:00
|
|
|
* Contributor(s):
|
2007-04-24 17:44:43 +02:00
|
|
|
*
|
2009-03-17 08:39:55 +01:00
|
|
|
* Roman Simakov <roman-simakov@users.sourceforge.net>
|
2009-09-29 11:13:37 +02:00
|
|
|
* Khorsun Vladyslav <hvlad@users.sourceforge.net>
|
2007-04-24 17:44:43 +02:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2007-04-27 18:27:18 +02:00
|
|
|
#include "firebird.h"
|
2007-04-24 17:44:43 +02:00
|
|
|
#include "GlobalRWLock.h"
|
|
|
|
#include "../lock/lock_proto.h"
|
2010-10-12 10:02:57 +02:00
|
|
|
#include "../common/isc_proto.h"
|
2007-04-24 17:44:43 +02:00
|
|
|
#include "jrd.h"
|
|
|
|
#include "lck_proto.h"
|
|
|
|
#include "err_proto.h"
|
2011-05-09 12:15:19 +02:00
|
|
|
#include "Attachment.h"
|
2009-03-17 08:39:55 +01:00
|
|
|
#include "../common/classes/rwlock.h"
|
|
|
|
#include "../common/classes/condition.h"
|
2007-04-24 17:44:43 +02:00
|
|
|
|
|
|
|
#ifdef COS_DEBUG
|
2008-08-27 14:20:47 +02:00
|
|
|
#include <stdarg.h>
|
2007-04-24 17:44:43 +02:00
|
|
|
IMPLEMENT_TRACE_ROUTINE(cos_trace, "COS")
|
|
|
|
#endif
|
|
|
|
|
2011-11-16 18:41:27 +01:00
|
|
|
using namespace Firebird;
|
|
|
|
using namespace Jrd;
|
2011-05-09 12:15:19 +02:00
|
|
|
|
2007-04-24 17:44:43 +02:00
|
|
|
|
|
|
|
int GlobalRWLock::blocking_ast_cached_lock(void* ast_object)
|
|
|
|
{
|
2008-03-12 17:53:57 +01:00
|
|
|
GlobalRWLock* globalRWLock = static_cast<GlobalRWLock*>(ast_object);
|
2007-04-24 17:44:43 +02:00
|
|
|
|
2008-03-12 17:53:57 +01:00
|
|
|
try
|
|
|
|
{
|
2014-02-25 15:18:32 +01:00
|
|
|
if (!globalRWLock->cachedLock)
|
|
|
|
return 0;
|
2011-10-18 20:02:57 +02:00
|
|
|
|
2014-02-25 15:18:32 +01:00
|
|
|
Database* const dbb = globalRWLock->cachedLock->lck_dbb;
|
2012-12-14 18:59:02 +01:00
|
|
|
AsyncContextHolder tdbb(dbb, FB_FUNCTION);
|
2008-01-26 14:17:19 +01:00
|
|
|
|
2012-12-14 18:59:02 +01:00
|
|
|
MutexLockGuard counterGuard(globalRWLock->counterMutex, FB_FUNCTION);
|
2014-02-25 15:18:32 +01:00
|
|
|
globalRWLock->blockingAstHandler(tdbb);
|
2008-03-12 17:53:57 +01:00
|
|
|
}
|
2011-11-16 18:41:27 +01:00
|
|
|
catch (const Exception&)
|
2008-03-12 17:53:57 +01:00
|
|
|
{} // no-op
|
2007-04-24 17:44:43 +02:00
|
|
|
|
2008-12-04 10:29:16 +01:00
|
|
|
return 0;
|
2007-04-24 17:44:43 +02:00
|
|
|
}
|
|
|
|
|
2012-05-31 18:53:42 +02:00
|
|
|
GlobalRWLock::GlobalRWLock(thread_db* tdbb, MemoryPool& p, lck_t lckType,
|
2014-07-17 20:48:46 +02:00
|
|
|
bool lock_caching, FB_SIZE_T lockLen, const UCHAR* lockStr)
|
2009-03-18 03:55:35 +01:00
|
|
|
: PermanentStorage(p), pendingLock(0), readers(0), pendingWriters(0), currentWriter(false),
|
|
|
|
lockCaching(lock_caching), blocking(false)
|
2007-04-24 17:44:43 +02:00
|
|
|
{
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
2012-06-21 17:37:38 +02:00
|
|
|
cachedLock = FB_NEW_RPT(getPool(), lockLen)
|
|
|
|
Lock(tdbb, lockLen, lckType, this, lockCaching ? blocking_ast_cached_lock : NULL);
|
2016-05-09 22:41:33 +02:00
|
|
|
memcpy(cachedLock->getKeyPtr(), lockStr, lockLen);
|
2007-04-24 17:44:43 +02:00
|
|
|
}
|
|
|
|
|
2007-08-12 07:22:59 +02:00
|
|
|
GlobalRWLock::~GlobalRWLock()
|
2009-03-17 08:39:55 +01:00
|
|
|
{
|
2013-11-13 08:44:50 +01:00
|
|
|
delete cachedLock;
|
2009-03-17 08:39:55 +01:00
|
|
|
}
|
|
|
|
|
2013-11-13 08:44:50 +01:00
|
|
|
void GlobalRWLock::shutdownLock(thread_db* tdbb)
|
2007-08-12 07:22:59 +02:00
|
|
|
{
|
2013-11-13 08:44:50 +01:00
|
|
|
SET_TDBB(tdbb);
|
2009-03-17 08:39:55 +01:00
|
|
|
|
2015-11-29 16:12:31 +01:00
|
|
|
CheckoutLockGuard counterGuard(tdbb, counterMutex, FB_FUNCTION, true);
|
2009-03-17 08:39:55 +01:00
|
|
|
|
|
|
|
COS_TRACE(("(%p)->shutdownLock readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
|
|
|
|
this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
|
|
|
|
|
|
|
|
LCK_release(tdbb, cachedLock);
|
2007-04-24 17:44:43 +02:00
|
|
|
}
|
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
bool GlobalRWLock::lockWrite(thread_db* tdbb, SSHORT wait)
|
2007-08-12 07:22:59 +02:00
|
|
|
{
|
2007-04-24 17:44:43 +02:00
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
{ // scope 1
|
2015-11-29 16:12:31 +01:00
|
|
|
CheckoutLockGuard counterGuard(tdbb, counterMutex, FB_FUNCTION, true);
|
2009-03-17 08:39:55 +01:00
|
|
|
|
|
|
|
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 )
|
2008-08-13 11:02:35 +02:00
|
|
|
{
|
2015-11-29 16:12:31 +01:00
|
|
|
EngineCheckout cout(tdbb, FB_FUNCTION, true);
|
2009-03-17 08:39:55 +01:00
|
|
|
noReaders.wait(counterMutex);
|
2007-04-24 17:44:43 +02:00
|
|
|
}
|
2007-08-10 15:57:25 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
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));
|
2007-08-10 15:57:25 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
while (currentWriter || pendingLock)
|
2007-04-24 17:44:43 +02:00
|
|
|
{
|
2015-11-29 16:12:31 +01:00
|
|
|
EngineCheckout cout(tdbb, FB_FUNCTION, true);
|
2009-03-17 08:39:55 +01:00
|
|
|
writerFinished.wait(counterMutex);
|
2007-08-10 15:57:25 +02:00
|
|
|
}
|
2007-04-24 17:44:43 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
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);
|
|
|
|
|
2016-08-17 14:52:27 +02:00
|
|
|
if (cachedLock->lck_physical == LCK_write)
|
|
|
|
{
|
|
|
|
--pendingWriters;
|
|
|
|
|
|
|
|
fb_assert(!currentWriter);
|
|
|
|
currentWriter = true;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
if (cachedLock->lck_physical > LCK_none)
|
2007-08-10 15:57:25 +02:00
|
|
|
{
|
2009-03-18 03:43:15 +01:00
|
|
|
LCK_release(tdbb, cachedLock); // To prevent self deadlock
|
2009-03-17 08:39:55 +01:00
|
|
|
invalidate(tdbb);
|
2007-08-10 15:57:25 +02:00
|
|
|
}
|
2007-04-24 17:44:43 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
++pendingLock;
|
2007-04-24 17:44:43 +02:00
|
|
|
}
|
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
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))
|
2008-08-13 11:02:35 +02:00
|
|
|
{
|
2015-03-20 19:02:30 +01:00
|
|
|
FbStatusVector* const vector = tdbb->tdbb_status_vector;
|
|
|
|
const ISC_STATUS* status = vector->getErrors();
|
2013-11-12 17:52:32 +01:00
|
|
|
if ((wait == LCK_NO_WAIT) || ((wait < 0) && (status[1] == isc_lock_timeout)))
|
2015-03-20 19:02:30 +01:00
|
|
|
vector->init();
|
2013-11-12 17:52:32 +01:00
|
|
|
|
2015-11-29 16:12:31 +01:00
|
|
|
CheckoutLockGuard counterGuard(tdbb, counterMutex, FB_FUNCTION, true);
|
2011-05-10 03:12:14 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
--pendingLock;
|
2011-05-10 03:12:14 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
if (--pendingWriters)
|
|
|
|
{
|
|
|
|
if (!currentWriter)
|
|
|
|
writerFinished.notifyAll();
|
|
|
|
}
|
2011-05-10 03:12:14 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
return false;
|
2007-04-24 17:44:43 +02:00
|
|
|
}
|
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
{ // scope 2
|
2015-11-29 16:12:31 +01:00
|
|
|
CheckoutLockGuard counterGuard(tdbb, counterMutex, FB_FUNCTION, true);
|
2007-04-24 17:44:43 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
--pendingLock;
|
|
|
|
--pendingWriters;
|
2007-04-24 17:44:43 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
fb_assert(!currentWriter);
|
2007-04-24 17:44:43 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
currentWriter = true;
|
2007-04-24 17:44:43 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
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);
|
|
|
|
}
|
2007-04-24 17:44:43 +02:00
|
|
|
}
|
|
|
|
|
2014-06-10 13:33:59 +02:00
|
|
|
void GlobalRWLock::unlockWrite(thread_db* tdbb, const bool release)
|
2007-08-12 07:22:59 +02:00
|
|
|
{
|
2007-04-24 17:44:43 +02:00
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
2015-11-29 16:12:31 +01:00
|
|
|
CheckoutLockGuard counterGuard(tdbb, counterMutex, FB_FUNCTION, true);
|
2007-04-24 17:44:43 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
COS_TRACE(("(%p)->unlockWrite readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
|
|
|
|
this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
|
2007-04-24 17:44:43 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
currentWriter = false;
|
|
|
|
|
2014-06-10 13:33:59 +02:00
|
|
|
if (!lockCaching || release)
|
2009-03-17 08:39:55 +01:00
|
|
|
LCK_release(tdbb, cachedLock);
|
|
|
|
else if (blocking)
|
|
|
|
LCK_downgrade(tdbb, cachedLock);
|
2014-06-10 13:33:59 +02:00
|
|
|
|
|
|
|
blocking = false;
|
2008-12-04 10:29:16 +01:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
if (cachedLock->lck_physical < LCK_read)
|
|
|
|
invalidate(tdbb);
|
2007-04-24 17:44:43 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GlobalRWLock::lockRead(thread_db* tdbb, SSHORT wait, const bool queueJump)
|
|
|
|
{
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
bool needFetch;
|
|
|
|
|
|
|
|
{ // scope 1
|
2015-11-29 16:12:31 +01:00
|
|
|
CheckoutLockGuard counterGuard(tdbb, counterMutex, FB_FUNCTION, true);
|
2009-03-17 08:39:55 +01:00
|
|
|
|
|
|
|
COS_TRACE(("(%p)->lockRead stage 1 readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
|
|
|
|
this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
|
|
|
|
|
|
|
|
while (true)
|
2007-08-12 07:22:59 +02:00
|
|
|
{
|
2009-03-17 08:39:55 +01:00
|
|
|
if (readers > 0 && queueJump)
|
2008-07-23 18:03:35 +02:00
|
|
|
{
|
2009-03-17 08:39:55 +01:00
|
|
|
COS_TRACE(("(%p)->lockRead queueJump", this));
|
|
|
|
readers++;
|
|
|
|
return true;
|
2008-07-23 18:03:35 +02:00
|
|
|
}
|
2007-04-24 17:44:43 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
while (pendingWriters > 0 || currentWriter)
|
|
|
|
{
|
2015-11-29 16:12:31 +01:00
|
|
|
EngineCheckout cout(tdbb, FB_FUNCTION, true);
|
2009-03-17 08:39:55 +01:00
|
|
|
writerFinished.wait(counterMutex);
|
|
|
|
}
|
2009-04-04 18:39:31 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
COS_TRACE(("(%p)->lockRead stage 3 readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
|
|
|
|
this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
|
|
|
|
|
|
|
|
if (!pendingLock)
|
|
|
|
break;
|
|
|
|
|
2012-12-14 18:59:02 +01:00
|
|
|
MutexUnlockGuard cout(counterMutex, FB_FUNCTION);
|
2015-11-29 16:12:31 +01:00
|
|
|
EngineCheckout cout2(tdbb, FB_FUNCTION, true);
|
2014-08-15 16:19:02 +02:00
|
|
|
Thread::yield();
|
2008-12-04 10:29:16 +01:00
|
|
|
}
|
2009-03-17 08:39:55 +01:00
|
|
|
|
|
|
|
needFetch = cachedLock->lck_physical < LCK_read;
|
|
|
|
if (!needFetch)
|
2008-08-13 11:02:35 +02:00
|
|
|
{
|
2009-03-17 08:39:55 +01:00
|
|
|
++readers;
|
|
|
|
return true;
|
2007-04-24 17:44:43 +02:00
|
|
|
}
|
2009-03-17 08:39:55 +01:00
|
|
|
|
|
|
|
++pendingLock;
|
|
|
|
|
|
|
|
fb_assert(cachedLock->lck_physical == LCK_none);
|
2007-04-24 17:44:43 +02:00
|
|
|
}
|
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
if (!LCK_lock(tdbb, cachedLock, LCK_read, wait))
|
|
|
|
{
|
2015-03-20 19:02:30 +01:00
|
|
|
FbStatusVector* const vector = tdbb->tdbb_status_vector;
|
|
|
|
const ISC_STATUS* status = vector->getErrors();
|
2013-11-12 17:52:32 +01:00
|
|
|
if ((wait == LCK_NO_WAIT) || ((wait < 0) && (status[1] == isc_lock_timeout)))
|
2015-03-20 19:02:30 +01:00
|
|
|
vector->init();
|
2013-11-12 17:52:32 +01:00
|
|
|
|
2015-11-29 16:12:31 +01:00
|
|
|
CheckoutLockGuard counterGuard(tdbb, counterMutex, FB_FUNCTION, true);
|
2009-03-17 08:39:55 +01:00
|
|
|
--pendingLock;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
{ // scope 2
|
2015-11-29 16:12:31 +01:00
|
|
|
CheckoutLockGuard counterGuard(tdbb, counterMutex, FB_FUNCTION, true);
|
2009-03-17 08:39:55 +01:00
|
|
|
--pendingLock;
|
|
|
|
++readers;
|
|
|
|
|
|
|
|
COS_TRACE(("(%p)->lockRead end readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
|
|
|
|
this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
|
2009-04-04 18:39:31 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
return fetch(tdbb);
|
|
|
|
}
|
2007-04-24 17:44:43 +02:00
|
|
|
}
|
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
void GlobalRWLock::unlockRead(thread_db* tdbb)
|
2007-08-12 07:22:59 +02:00
|
|
|
{
|
2007-04-24 17:44:43 +02:00
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
2015-11-29 16:12:31 +01:00
|
|
|
CheckoutLockGuard counterGuard(tdbb, counterMutex, FB_FUNCTION, true);
|
2007-04-24 17:44:43 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
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)
|
2008-08-13 11:02:35 +02:00
|
|
|
{
|
2009-03-17 08:39:55 +01:00
|
|
|
if (!lockCaching || pendingWriters || blocking)
|
2008-08-13 11:02:35 +02:00
|
|
|
{
|
2009-03-17 08:39:55 +01:00
|
|
|
LCK_release(tdbb, cachedLock); // Release since concurrent request needs LCK_write
|
|
|
|
invalidate(tdbb);
|
2007-04-24 17:44:43 +02:00
|
|
|
}
|
2009-03-17 08:39:55 +01:00
|
|
|
|
|
|
|
noReaders.notifyAll();
|
2007-04-24 17:44:43 +02:00
|
|
|
}
|
2009-03-17 08:39:55 +01:00
|
|
|
COS_TRACE(("(%p)->unlockRead end readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
|
|
|
|
this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
|
2007-04-24 17:44:43 +02:00
|
|
|
}
|
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
bool GlobalRWLock::tryReleaseLock(thread_db* tdbb)
|
2007-08-12 07:22:59 +02:00
|
|
|
{
|
2015-11-29 16:12:31 +01:00
|
|
|
CheckoutLockGuard counterGuard(tdbb, counterMutex, FB_FUNCTION, true);
|
2009-03-17 08:39:55 +01:00
|
|
|
|
|
|
|
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;
|
2008-12-04 10:29:16 +01:00
|
|
|
}
|
2007-04-24 17:44:43 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
void GlobalRWLock::blockingAstHandler(thread_db* tdbb)
|
2007-08-12 07:22:59 +02:00
|
|
|
{
|
2007-04-24 17:44:43 +02:00
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
COS_TRACE(("(%p)->blockingAst enter", this));
|
|
|
|
COS_TRACE(("(%p)->blockingAst readers(%d), blocking(%d), pendingWriters(%d), currentWriter(%d), lck_physical(%d)",
|
|
|
|
this, readers, blocking, pendingWriters, currentWriter, cachedLock->lck_physical));
|
2007-04-24 17:44:43 +02:00
|
|
|
|
2009-03-17 08:39:55 +01:00
|
|
|
if (!pendingLock && !currentWriter && !readers)
|
2008-08-13 11:02:35 +02:00
|
|
|
{
|
2009-03-17 08:39:55 +01:00
|
|
|
COS_TRACE(("(%p)->Downgrade lock", this));
|
|
|
|
LCK_downgrade(tdbb, cachedLock);
|
|
|
|
fb_assert(!blocking);
|
|
|
|
if (cachedLock->lck_physical < LCK_read)
|
|
|
|
invalidate(tdbb);
|
2007-04-24 17:44:43 +02:00
|
|
|
}
|
2014-05-16 14:10:00 +02:00
|
|
|
else if (!pendingLock && !currentWriter && readers && cachedLock->lck_physical > LCK_read)
|
|
|
|
{
|
|
|
|
COS_TRACE(("(%p)->Convert lock to SR ", this));
|
|
|
|
if (!LCK_convert(tdbb, cachedLock, LCK_read, LCK_NO_WAIT))
|
|
|
|
{
|
|
|
|
COS_TRACE(("(%p)->Set blocking", this));
|
|
|
|
blocking = true;
|
|
|
|
}
|
|
|
|
}
|
2008-08-13 11:02:35 +02:00
|
|
|
else
|
|
|
|
{
|
2009-03-17 08:39:55 +01:00
|
|
|
COS_TRACE(("(%p)->Set blocking", this));
|
|
|
|
blocking = true;
|
2007-04-24 17:44:43 +02:00
|
|
|
}
|
|
|
|
}
|