mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 00:03:02 +01:00
Better fix for #6947: Query to mon$ tables does not return data when the encryption/decryption thread is running
This commit is contained in:
parent
12be4beed7
commit
9ed56eff6c
@ -210,7 +210,10 @@ void Thread::kill(Handle& thread)
|
||||
ThreadId Thread::getId()
|
||||
{
|
||||
#ifdef USE_LWP_AS_THREAD_ID
|
||||
return syscall(SYS_gettid);
|
||||
static __thread int tid = 0;
|
||||
if (!tid)
|
||||
tid = syscall(SYS_gettid);
|
||||
return tid;
|
||||
#else
|
||||
return pthread_self();
|
||||
#endif
|
||||
|
@ -101,7 +101,7 @@ namespace Firebird
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Mtx, typename RefCounted = DefaultRefCounted<Mtx> >
|
||||
template <typename Mtx, template <typename T> class RefCounted = DefaultRefCounted >
|
||||
class EnsureUnlock
|
||||
{
|
||||
public:
|
||||
@ -114,14 +114,14 @@ namespace Firebird
|
||||
#define FB_LOCKED_FROM NULL
|
||||
#endif
|
||||
{
|
||||
RefCounted::addRef(m_mutex);
|
||||
RefCounted<Mtx>::addRef(m_mutex);
|
||||
}
|
||||
|
||||
~EnsureUnlock()
|
||||
{
|
||||
while (m_locked)
|
||||
leave();
|
||||
RefCounted::release(m_mutex);
|
||||
RefCounted<Mtx>::release(m_mutex);
|
||||
}
|
||||
|
||||
void enter()
|
||||
@ -155,7 +155,7 @@ namespace Firebird
|
||||
};
|
||||
#undef FB_LOCKED_FROM
|
||||
|
||||
typedef EnsureUnlock<Mutex, NotRefCounted<Mutex> > MutexEnsureUnlock;
|
||||
typedef EnsureUnlock<Mutex, NotRefCounted> MutexEnsureUnlock;
|
||||
typedef EnsureUnlock<RefMutex> RefMutexEnsureUnlock;
|
||||
|
||||
} // namespace
|
||||
|
@ -89,7 +89,7 @@ private:
|
||||
};
|
||||
|
||||
typedef RaiiLockGuard<XThreadMutex> XThreadLockGuard;
|
||||
typedef EnsureUnlock<XThreadMutex, NotRefCounted<XThreadMutex> > XThreadEnsureUnlock;
|
||||
typedef EnsureUnlock<XThreadMutex, NotRefCounted> XThreadEnsureUnlock;
|
||||
|
||||
}
|
||||
|
||||
|
@ -320,7 +320,7 @@ typedef Mutex Spinlock;
|
||||
#endif //WIN_NT
|
||||
|
||||
|
||||
// RAII holder
|
||||
// RAII holders
|
||||
template <typename M>
|
||||
class RaiiLockGuard
|
||||
{
|
||||
@ -363,10 +363,12 @@ private:
|
||||
|
||||
typedef RaiiLockGuard<Mutex> MutexLockGuard;
|
||||
|
||||
class MutexUnlockGuard
|
||||
|
||||
template <typename M>
|
||||
class RaiiUnlockGuard
|
||||
{
|
||||
public:
|
||||
explicit MutexUnlockGuard(Mutex& aLock, const char* aReason)
|
||||
explicit RaiiUnlockGuard(M& aLock, const char* aReason)
|
||||
: lock(&aLock)
|
||||
#ifdef DEV_BUILD
|
||||
, saveReason(aReason)
|
||||
@ -375,7 +377,7 @@ public:
|
||||
lock->leave();
|
||||
}
|
||||
|
||||
~MutexUnlockGuard()
|
||||
~RaiiUnlockGuard()
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -393,15 +395,17 @@ public:
|
||||
|
||||
private:
|
||||
// Forbid copying
|
||||
MutexUnlockGuard(const MutexUnlockGuard&);
|
||||
MutexUnlockGuard& operator=(const MutexUnlockGuard&);
|
||||
RaiiUnlockGuard(const RaiiUnlockGuard&);
|
||||
RaiiUnlockGuard& operator=(const RaiiUnlockGuard&);
|
||||
|
||||
Mutex* lock;
|
||||
M* lock;
|
||||
#ifdef DEV_BUILD
|
||||
const char* saveReason;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef RaiiUnlockGuard<Mutex> MutexUnlockGuard;
|
||||
|
||||
|
||||
class MutexCheckoutGuard
|
||||
{
|
||||
|
@ -989,10 +989,10 @@ void Jrd::Attachment::SyncGuard::init(const char* f, bool
|
||||
|
||||
if (jStable)
|
||||
{
|
||||
jStable->getMutex()->enter(f);
|
||||
jStable->getSync()->enter(f);
|
||||
if (!jStable->getHandle())
|
||||
{
|
||||
jStable->getMutex()->leave();
|
||||
jStable->getSync()->leave();
|
||||
Arg::Gds(isc_att_shutdown).raise();
|
||||
}
|
||||
}
|
||||
@ -1004,13 +1004,13 @@ void StableAttachmentPart::manualLock(ULONG& flags, const ULONG whatLock)
|
||||
|
||||
if (whatLock & ATT_async_manual_lock)
|
||||
{
|
||||
asyncMutex.enter(FB_FUNCTION);
|
||||
async.enter(FB_FUNCTION);
|
||||
flags |= ATT_async_manual_lock;
|
||||
}
|
||||
|
||||
if (whatLock & ATT_manual_lock)
|
||||
{
|
||||
mainMutex.enter(FB_FUNCTION);
|
||||
mainSync.enter(FB_FUNCTION);
|
||||
flags |= ATT_manual_lock;
|
||||
}
|
||||
}
|
||||
@ -1020,7 +1020,7 @@ void StableAttachmentPart::manualUnlock(ULONG& flags)
|
||||
if (flags & ATT_manual_lock)
|
||||
{
|
||||
flags &= ~ATT_manual_lock;
|
||||
mainMutex.leave();
|
||||
mainSync.leave();
|
||||
}
|
||||
manualAsyncUnlock(flags);
|
||||
}
|
||||
@ -1030,7 +1030,7 @@ void StableAttachmentPart::manualAsyncUnlock(ULONG& flags)
|
||||
if (flags & ATT_async_manual_lock)
|
||||
{
|
||||
flags &= ~ATT_async_manual_lock;
|
||||
asyncMutex.leave();
|
||||
async.leave();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1038,7 +1038,7 @@ void StableAttachmentPart::onIdleTimer(TimerImpl*)
|
||||
{
|
||||
// Ensure attachment is still alive and still idle
|
||||
|
||||
MutexEnsureUnlock guard(*this->getMutex(), FB_FUNCTION);
|
||||
EnsureUnlock<Sync, NotRefCounted> guard(*this->getSync(), FB_FUNCTION);
|
||||
if (!guard.tryEnter())
|
||||
return;
|
||||
|
||||
|
@ -203,6 +203,107 @@ private:
|
||||
class StableAttachmentPart : public Firebird::RefCounted, public Firebird::GlobalStorage
|
||||
{
|
||||
public:
|
||||
class Sync
|
||||
{
|
||||
public:
|
||||
Sync()
|
||||
: waiters(0), threadId(0), totalLocksCounter(0), currentLocksCounter(0)
|
||||
{ }
|
||||
|
||||
void enter(const char* aReason)
|
||||
{
|
||||
int curTid = getThreadId();
|
||||
|
||||
if (threadId == curTid)
|
||||
{
|
||||
currentLocksCounter++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (threadId || !syncMutex.tryEnter(aReason))
|
||||
{
|
||||
// we have contention with another thread
|
||||
waiters.fetch_add(1, std::memory_order_relaxed);
|
||||
syncMutex.enter(aReason);
|
||||
waiters.fetch_sub(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
threadId = curTid;
|
||||
totalLocksCounter++;
|
||||
fb_assert(currentLocksCounter == 0);
|
||||
currentLocksCounter++;
|
||||
}
|
||||
|
||||
bool tryEnter(const char* aReason)
|
||||
{
|
||||
int curTid = getThreadId();
|
||||
|
||||
if (threadId == curTid)
|
||||
{
|
||||
currentLocksCounter++;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (threadId || !syncMutex.tryEnter(aReason))
|
||||
return false;
|
||||
|
||||
threadId = curTid;
|
||||
totalLocksCounter++;
|
||||
fb_assert(currentLocksCounter == 0);
|
||||
currentLocksCounter++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void leave()
|
||||
{
|
||||
fb_assert(currentLocksCounter > 0);
|
||||
|
||||
if (--currentLocksCounter == 0)
|
||||
{
|
||||
threadId = 0;
|
||||
syncMutex.leave();
|
||||
}
|
||||
}
|
||||
|
||||
bool hasContention() const
|
||||
{
|
||||
return (waiters.load(std::memory_order_relaxed) > 0);
|
||||
}
|
||||
|
||||
FB_UINT64 getLockCounter() const
|
||||
{
|
||||
return totalLocksCounter;
|
||||
}
|
||||
|
||||
#ifdef DEV_BUILD
|
||||
bool locked() const
|
||||
{
|
||||
return threadId == getThreadId();
|
||||
}
|
||||
#endif
|
||||
|
||||
~Sync()
|
||||
{
|
||||
if (threadId == getThreadId())
|
||||
{
|
||||
syncMutex.leave();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// copying is prohibited
|
||||
Sync(const Sync&);
|
||||
Sync& operator=(const Sync&);
|
||||
|
||||
Firebird::Mutex syncMutex;
|
||||
std::atomic<int> waiters;
|
||||
ThreadId threadId;
|
||||
volatile FB_UINT64 totalLocksCounter;
|
||||
int currentLocksCounter;
|
||||
};
|
||||
|
||||
typedef Firebird::RaiiLockGuard<StableAttachmentPart> SyncGuard;
|
||||
|
||||
explicit StableAttachmentPart(Attachment* handle)
|
||||
: att(handle), jAtt(NULL), shutError(0)
|
||||
{ }
|
||||
@ -226,13 +327,13 @@ public:
|
||||
shutError = 0;
|
||||
}
|
||||
|
||||
Firebird::Mutex* getMutex(bool useAsync = false, bool forceAsync = false)
|
||||
Sync* getSync(bool useAsync = false, bool forceAsync = false)
|
||||
{
|
||||
if (useAsync && !forceAsync)
|
||||
{
|
||||
fb_assert(!mainMutex.locked());
|
||||
fb_assert(!mainSync.locked());
|
||||
}
|
||||
return useAsync ? &asyncMutex : &mainMutex;
|
||||
return useAsync ? &async : &mainSync;
|
||||
}
|
||||
|
||||
Firebird::Mutex* getBlockingMutex()
|
||||
@ -242,8 +343,8 @@ public:
|
||||
|
||||
void cancel()
|
||||
{
|
||||
fb_assert(asyncMutex.locked());
|
||||
fb_assert(mainMutex.locked());
|
||||
fb_assert(async.locked());
|
||||
fb_assert(mainSync.locked());
|
||||
att = NULL;
|
||||
}
|
||||
|
||||
@ -279,13 +380,16 @@ private:
|
||||
JAttachment* jAtt;
|
||||
ISC_STATUS shutError;
|
||||
|
||||
// These mutexes guarantee attachment existence. After releasing both of them with possibly
|
||||
// These syncs guarantee attachment existence. After releasing both of them with possibly
|
||||
// zero att_use_count one should check does attachment still exists calling getHandle().
|
||||
Firebird::Mutex mainMutex, asyncMutex;
|
||||
Sync mainSync, async;
|
||||
// This mutex guarantees attachment is not accessed by more than single external thread.
|
||||
Firebird::Mutex blockingMutex;
|
||||
};
|
||||
|
||||
typedef Firebird::RaiiLockGuard<StableAttachmentPart::Sync> AttSyncLockGuard;
|
||||
typedef Firebird::RaiiUnlockGuard<StableAttachmentPart::Sync> AttSyncUnlockGuard;
|
||||
|
||||
//
|
||||
// the attachment block; one is created for each attachment to a database
|
||||
//
|
||||
@ -310,7 +414,7 @@ public:
|
||||
~SyncGuard()
|
||||
{
|
||||
if (jStable)
|
||||
jStable->getMutex()->leave();
|
||||
jStable->getSync()->leave();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -970,7 +970,7 @@ namespace Jrd {
|
||||
dbb.dbb_database_name.c_str(), writer.getBufferLength(), writer.getBuffer()));
|
||||
check(&status_vector);
|
||||
|
||||
MutexLockGuard attGuard(*(jAtt->getStable()->getMutex()), FB_FUNCTION);
|
||||
AttSyncLockGuard attGuard(*(jAtt->getStable()->getSync()), FB_FUNCTION);
|
||||
Attachment* att = jAtt->getHandle();
|
||||
if (!att)
|
||||
Arg::Gds(isc_att_shutdown).raise();
|
||||
|
@ -2541,10 +2541,10 @@ void EngineCallbackGuard::init(thread_db* tdbb, Connection& conn, const char* fr
|
||||
{
|
||||
m_saveConnection = attachment->att_ext_connection;
|
||||
m_stable = attachment->getStable();
|
||||
m_stable->getMutex()->leave();
|
||||
m_stable->getSync()->leave();
|
||||
|
||||
MutexLockGuard guardAsync(*m_stable->getMutex(true, true), FB_FUNCTION);
|
||||
MutexLockGuard guardMain(*m_stable->getMutex(), FB_FUNCTION);
|
||||
Jrd::AttSyncLockGuard guardAsync(*m_stable->getSync(true, true), FB_FUNCTION);
|
||||
Jrd::AttSyncLockGuard guardMain(*m_stable->getSync(), FB_FUNCTION);
|
||||
if (m_stable->getHandle() == attachment)
|
||||
attachment->att_ext_connection = &conn;
|
||||
}
|
||||
@ -2566,13 +2566,13 @@ EngineCallbackGuard::~EngineCallbackGuard()
|
||||
Jrd::Attachment* attachment = m_tdbb->getAttachment();
|
||||
if (attachment && m_stable.hasData())
|
||||
{
|
||||
MutexLockGuard guardAsync(*m_stable->getMutex(true, true), FB_FUNCTION);
|
||||
m_stable->getMutex()->enter(FB_FUNCTION);
|
||||
Jrd::AttSyncLockGuard guardAsync(*m_stable->getSync(true, true), FB_FUNCTION);
|
||||
m_stable->getSync()->enter(FB_FUNCTION);
|
||||
|
||||
if (m_stable->getHandle() == attachment)
|
||||
attachment->att_ext_connection = m_saveConnection;
|
||||
else
|
||||
m_stable->getMutex()->leave();
|
||||
m_stable->getSync()->leave();
|
||||
}
|
||||
|
||||
jrd_tra* transaction = m_tdbb->getTransaction();
|
||||
|
@ -733,7 +733,7 @@ namespace
|
||||
try
|
||||
{
|
||||
if (!nolock)
|
||||
sAtt->getMutex(async)->enter(from);
|
||||
sAtt->getSync(async)->enter(from);
|
||||
|
||||
Jrd::Attachment* attachment = sAtt->getHandle(); // Must be done after entering mutex
|
||||
|
||||
@ -764,7 +764,7 @@ namespace
|
||||
catch (const Firebird::Exception&)
|
||||
{
|
||||
if (!nolock)
|
||||
sAtt->getMutex(async)->leave();
|
||||
sAtt->getSync(async)->leave();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@ -788,7 +788,7 @@ namespace
|
||||
}
|
||||
|
||||
if (!nolock)
|
||||
sAtt->getMutex(async)->leave();
|
||||
sAtt->getSync(async)->leave();
|
||||
|
||||
if (blocking)
|
||||
sAtt->getBlockingMutex()->leave();
|
||||
@ -3373,12 +3373,12 @@ void JAttachment::deprecatedDropDatabase(CheckStatusWrapper* user_status)
|
||||
try
|
||||
{
|
||||
EngineContextHolder tdbb(user_status, this, FB_FUNCTION, AttachmentHolder::ATT_LOCK_ASYNC);
|
||||
Jrd::Attachment* attachment = getHandle();
|
||||
Attachment* attachment = getHandle();
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
|
||||
try
|
||||
{
|
||||
MutexEnsureUnlock guard(*(getStable()->getMutex()), FB_FUNCTION);
|
||||
EnsureUnlock<StableAttachmentPart::Sync, NotRefCounted> guard(*(getStable()->getSync()), FB_FUNCTION);
|
||||
if (!guard.tryEnter())
|
||||
{
|
||||
status_exception::raise(Arg::Gds(isc_attachment_in_use));
|
||||
@ -4975,8 +4975,8 @@ void SysStableAttachment::destroy(Attachment* attachment)
|
||||
}
|
||||
|
||||
// Make Attachment::destroy() happy
|
||||
MutexLockGuard async(*getMutex(true), FB_FUNCTION);
|
||||
MutexLockGuard sync(*getMutex(), FB_FUNCTION);
|
||||
AttSyncLockGuard async(*getSync(true), FB_FUNCTION);
|
||||
AttSyncLockGuard sync(*getSync(), FB_FUNCTION);
|
||||
|
||||
setInterface(NULL);
|
||||
Jrd::Attachment::destroy(attachment);
|
||||
@ -8095,8 +8095,8 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
|
||||
**************************************/
|
||||
SET_TDBB(tdbb);
|
||||
|
||||
Mutex* const attMutex = sAtt->getMutex();
|
||||
fb_assert(attMutex->locked());
|
||||
StableAttachmentPart::Sync* const attSync = sAtt->getSync();
|
||||
fb_assert(attSync->locked());
|
||||
|
||||
Jrd::Attachment* attachment = sAtt->getHandle();
|
||||
|
||||
@ -8111,10 +8111,10 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
|
||||
attachment->att_use_count--;
|
||||
|
||||
{ // scope
|
||||
MutexUnlockGuard cout(*attMutex, FB_FUNCTION);
|
||||
AttSyncUnlockGuard cout(*attSync, FB_FUNCTION);
|
||||
// !!!!!!!!!!!!!!!!! - event? semaphore? condvar? (when ATT_purge_started / sAtt->getHandle() changes)
|
||||
|
||||
fb_assert(!attMutex->locked());
|
||||
fb_assert(!attSync->locked());
|
||||
Thread::yield();
|
||||
Thread::sleep(1);
|
||||
}
|
||||
@ -8138,10 +8138,10 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
|
||||
attachment->att_use_count--;
|
||||
|
||||
{ // scope
|
||||
MutexUnlockGuard cout(*attMutex, FB_FUNCTION);
|
||||
AttSyncUnlockGuard cout(*attSync, FB_FUNCTION);
|
||||
// !!!!!!!!!!!!!!!!! - event? semaphore? condvar? (when --att_use_count)
|
||||
|
||||
fb_assert(!attMutex->locked());
|
||||
fb_assert(!attSync->locked());
|
||||
Thread::yield();
|
||||
Thread::sleep(1);
|
||||
}
|
||||
@ -8152,7 +8152,7 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
|
||||
attachment->att_use_count++;
|
||||
}
|
||||
|
||||
fb_assert(attMutex->locked());
|
||||
fb_assert(attSync->locked());
|
||||
|
||||
if (!attachment)
|
||||
return;
|
||||
@ -8257,13 +8257,13 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
|
||||
attachment->att_trace_manager->event_detach(&conn, false);
|
||||
}
|
||||
|
||||
fb_assert(attMutex->locked());
|
||||
Mutex* asyncMutex = sAtt->getMutex(true, true);
|
||||
MutexEnsureUnlock asyncGuard(*asyncMutex, FB_FUNCTION);
|
||||
fb_assert(attSync->locked());
|
||||
StableAttachmentPart::Sync* attAsync = sAtt->getSync(true, true);
|
||||
EnsureUnlock<StableAttachmentPart::Sync, NotRefCounted> asyncGuard(*attAsync, FB_FUNCTION);
|
||||
|
||||
{ // scope - ensure correct order of taking both async and main mutexes
|
||||
MutexUnlockGuard cout(*attMutex, FB_FUNCTION);
|
||||
fb_assert(!attMutex->locked());
|
||||
AttSyncUnlockGuard cout(*attSync, FB_FUNCTION);
|
||||
fb_assert(!attSync->locked());
|
||||
asyncGuard.enter();
|
||||
}
|
||||
|
||||
@ -8280,7 +8280,7 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign
|
||||
release_attachment(tdbb, attachment);
|
||||
|
||||
asyncGuard.leave();
|
||||
MutexUnlockGuard cout(*attMutex, FB_FUNCTION);
|
||||
AttSyncUnlockGuard cout(*attSync, FB_FUNCTION);
|
||||
MutexUnlockGuard coutBlocking(*sAtt->getBlockingMutex(), FB_FUNCTION);
|
||||
|
||||
// Try to close database if there are no attachments
|
||||
@ -8560,7 +8560,7 @@ namespace
|
||||
{
|
||||
StableAttachmentPart* const sAtt = *iter;
|
||||
|
||||
MutexLockGuard guard(*(sAtt->getMutex(true)), FB_FUNCTION);
|
||||
AttSyncLockGuard guard(*(sAtt->getSync(true)), FB_FUNCTION);
|
||||
Attachment* attachment = sAtt->getHandle();
|
||||
|
||||
if (attachment)
|
||||
@ -8575,7 +8575,7 @@ namespace
|
||||
StableAttachmentPart* const sAtt = *iter;
|
||||
|
||||
MutexLockGuard guardBlocking(*(sAtt->getBlockingMutex()), FB_FUNCTION);
|
||||
MutexLockGuard guard(*(sAtt->getMutex()), FB_FUNCTION);
|
||||
AttSyncLockGuard guard(*(sAtt->getSync()), FB_FUNCTION);
|
||||
Attachment* attachment = sAtt->getHandle();
|
||||
|
||||
if (attachment)
|
||||
@ -8993,9 +8993,18 @@ void thread_db::reschedule()
|
||||
|
||||
checkCancelState();
|
||||
|
||||
{ // checkout scope
|
||||
StableAttachmentPart::Sync* sync = this->getAttachment()->getStable()->getSync();
|
||||
Database* dbb = this->getDatabase();
|
||||
|
||||
if (sync->hasContention())
|
||||
{
|
||||
FB_UINT64 cnt = sync->getLockCounter();
|
||||
|
||||
EngineCheckout cout(this, FB_FUNCTION);
|
||||
Thread::yield();
|
||||
|
||||
while (sync->hasContention() && (sync->getLockCounter() == cnt))
|
||||
Thread::sleep(1);
|
||||
}
|
||||
|
||||
checkCancelState();
|
||||
|
@ -1089,13 +1089,13 @@ namespace Jrd {
|
||||
fb_assert(optional || m_ref.hasData());
|
||||
|
||||
if (m_ref.hasData())
|
||||
m_ref->getMutex()->leave();
|
||||
m_ref->getSync()->leave();
|
||||
}
|
||||
|
||||
~EngineCheckout()
|
||||
{
|
||||
if (m_ref.hasData())
|
||||
m_ref->getMutex()->enter(m_from);
|
||||
m_ref->getSync()->enter(m_from);
|
||||
|
||||
// If we were signalled to cancel/shutdown, react as soon as possible.
|
||||
// We cannot throw immediately, but we can reschedule ourselves.
|
||||
|
@ -462,7 +462,6 @@ static bool notify_shutdown(thread_db* tdbb, SSHORT flag, SSHORT delay, Sync* gu
|
||||
*
|
||||
**************************************/
|
||||
Database* const dbb = tdbb->getDatabase();
|
||||
StableAttachmentPart* const sAtt = tdbb->getAttachment()->getStable();
|
||||
|
||||
shutdown_data data;
|
||||
data.data_items.flag = flag;
|
||||
@ -472,7 +471,7 @@ static bool notify_shutdown(thread_db* tdbb, SSHORT flag, SSHORT delay, Sync* gu
|
||||
|
||||
{ // scope
|
||||
// Checkout before calling AST function
|
||||
MutexUnlockGuard uguard(*(sAtt->getMutex()), FB_FUNCTION);
|
||||
EngineCheckout uguard(tdbb, FB_FUNCTION);
|
||||
|
||||
// Notify local attachments
|
||||
SHUT_blocking_ast(tdbb, true);
|
||||
|
Loading…
Reference in New Issue
Block a user