Skip to content

Commit 91bfc41

Browse files
committed
Fixed #7197: Segfault in linux CS after successful detach from database
1 parent 439ee45 commit 91bfc41

File tree

2 files changed

+87
-108
lines changed

2 files changed

+87
-108
lines changed

src/jrd/jrd.cpp

Lines changed: 83 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
#include "../yvalve/why_proto.h"
112112
#include "../jrd/flags.h"
113113
#include "../jrd/Mapping.h"
114+
#include "../jrd/ThreadCollect.h"
114115

115116
#include "../jrd/Database.h"
116117

@@ -124,6 +125,7 @@
124125
#include "../common/classes/fb_tls.h"
125126
#include "../common/classes/ClumpletWriter.h"
126127
#include "../common/classes/RefMutex.h"
128+
#include "../common/classes/semaphore.h"
127129
#include "../common/utils_proto.h"
128130
#include "../jrd/DebugInterface.h"
129131
#include "../jrd/CryptoManager.h"
@@ -449,6 +451,16 @@ namespace
449451
{
450452
using Jrd::Attachment;
451453

454+
// Required to sync attachment shutdown threads with provider shutdown
455+
GlobalPtr<ThreadCollect> shutThreadCollect;
456+
457+
struct AttShutParams
458+
{
459+
Semaphore thdStartedSem;
460+
Thread::Handle thrHandle;
461+
AttachmentsRefHolder* attachments;
462+
};
463+
452464
// Flag engineShutdown guarantees that no new attachment is created after setting it
453465
// and helps avoid more than 1 shutdown threads running simultaneously.
454466
bool engineShutdown = false;
@@ -4130,59 +4142,65 @@ void JProvider::shutdown(CheckStatusWrapper* status, unsigned int timeout, const
41304142
**************************************/
41314143
try
41324144
{
4133-
MutexLockGuard guard(shutdownMutex, FB_FUNCTION);
4134-
4135-
if (engineShutdown)
4136-
{
4137-
return;
4138-
}
41394145
{ // scope
4140-
MutexLockGuard guard(newAttachmentMutex, FB_FUNCTION);
4141-
engineShutdown = true;
4142-
}
4146+
MutexLockGuard guard(shutdownMutex, FB_FUNCTION);
41434147

4144-
ThreadContextHolder tdbb;
4148+
if (engineShutdown)
4149+
{
4150+
return;
4151+
}
41454152

4146-
ULONG attach_count, database_count, svc_count;
4147-
JRD_enum_attachments(NULL, attach_count, database_count, svc_count);
4153+
{ // scope
4154+
MutexLockGuard guard(newAttachmentMutex, FB_FUNCTION);
4155+
engineShutdown = true;
4156+
}
41484157

4149-
if (attach_count > 0 || svc_count > 0)
4150-
{
4151-
gds__log("Shutting down the server with %d active connection(s) to %d database(s), "
4152-
"%d active service(s)",
4153-
attach_count, database_count, svc_count);
4154-
}
4158+
ThreadContextHolder tdbb;
41554159

4156-
if (reason == fb_shutrsn_exit_called)
4157-
{
4158-
// Starting threads may fail when task is going to close.
4159-
// This happens at least with some microsoft C runtimes.
4160-
// If people wish to have timeout, they should better call fb_shutdown() themselves.
4161-
// Therefore:
4162-
timeout = 0;
4163-
}
4160+
ULONG attach_count, database_count, svc_count;
4161+
JRD_enum_attachments(NULL, attach_count, database_count, svc_count);
41644162

4165-
if (timeout)
4166-
{
4167-
Semaphore shutdown_semaphore;
4163+
if (attach_count > 0 || svc_count > 0)
4164+
{
4165+
gds__log("Shutting down the server with %d active connection(s) to %d database(s), "
4166+
"%d active service(s)",
4167+
attach_count, database_count, svc_count);
4168+
}
41684169

4169-
Thread::Handle h;
4170-
Thread::start(shutdown_thread, &shutdown_semaphore, THREAD_medium, &h);
4170+
if (reason == fb_shutrsn_exit_called)
4171+
{
4172+
// Starting threads may fail when task is going to close.
4173+
// This happens at least with some microsoft C runtimes.
4174+
// If people wish to have timeout, they should better call fb_shutdown() themselves.
4175+
// Therefore:
4176+
timeout = 0;
4177+
}
41714178

4172-
if (!shutdown_semaphore.tryEnter(0, timeout))
4173-
waitForShutdown(shutdown_semaphore);
4179+
if (timeout)
4180+
{
4181+
Semaphore shutdown_semaphore;
41744182

4175-
Thread::waitForCompletion(h);
4176-
}
4177-
else
4178-
{
4179-
shutdown_thread(NULL);
4183+
Thread::Handle h;
4184+
Thread::start(shutdown_thread, &shutdown_semaphore, THREAD_medium, &h);
4185+
4186+
if (!shutdown_semaphore.tryEnter(0, timeout))
4187+
waitForShutdown(shutdown_semaphore);
4188+
4189+
Thread::waitForCompletion(h);
4190+
}
4191+
else
4192+
{
4193+
shutdown_thread(NULL);
4194+
}
4195+
4196+
// Do not put it into separate shutdown thread - during shutdown of TraceManager
4197+
// PluginManager wants to lock a mutex, which is sometimes already locked in current thread
4198+
TraceManager::shutdown();
4199+
shutdownMappingIpc();
41804200
}
41814201

4182-
// Do not put it into separate shutdown thread - during shutdown of TraceManager
4183-
// PluginManager wants to lock a mutex, which is sometimes already locked in current thread
4184-
TraceManager::shutdown();
4185-
shutdownMappingIpc();
4202+
// Wait for completion of all shutdown threads
4203+
shutThreadCollect->join();
41864204
}
41874205
catch (const Exception& ex)
41884206
{
@@ -7478,22 +7496,26 @@ namespace
74787496
ThreadModuleRef thdRef(attachmentShutdownThread, &engineShutdown);
74797497
#endif
74807498

7499+
AttShutParams* params = static_cast<AttShutParams*>(arg);
7500+
AttachmentsRefHolder* attachments = params->attachments;
7501+
Thread::Handle th = params->thrHandle;
7502+
fb_assert(th);
7503+
74817504
try
74827505
{
7483-
MutexLockGuard guard(shutdownMutex, FB_FUNCTION);
7484-
if (engineShutdown)
7485-
{
7486-
// Shutdown was done, all attachments are gone
7487-
return 0;
7488-
}
7506+
shutThreadCollect->running(th);
7507+
params->thdStartedSem.release();
74897508

7490-
shutdownAttachments(static_cast<AttachmentsRefHolder*>(arg), false);
7509+
MutexLockGuard guard(shutdownMutex, FB_FUNCTION);
7510+
if (!engineShutdown)
7511+
shutdownAttachments(attachments, false);
74917512
}
74927513
catch (const Exception& ex)
74937514
{
74947515
iscLogException("attachmentShutdownThread", ex);
74957516
}
74967517

7518+
shutThreadCollect->ending(th);
74977519
return 0;
74987520
}
74997521
} // anonymous namespace
@@ -8183,7 +8205,12 @@ void JRD_shutdown_attachment(Attachment* attachment)
81838205
if (!(attachment->att_flags & ATT_shutdown))
81848206
attachment->signalShutdown();
81858207

8186-
Thread::start(attachmentShutdownThread, queue.release(), THREAD_high);
8208+
AttShutParams params;
8209+
params.attachments = queue;
8210+
Thread::start(attachmentShutdownThread, &params, THREAD_high, &params.thrHandle);
8211+
queue.release();
8212+
shutThreadCollect->houseKeeping();
8213+
params.thdStartedSem.enter();
81878214
}
81888215
catch (const Exception&)
81898216
{} // no-op
@@ -8239,7 +8266,12 @@ void JRD_shutdown_attachments(Database* dbb)
82398266
attachment->signalShutdown();
82408267
}
82418268

8242-
Thread::start(attachmentShutdownThread, queue.release(), THREAD_high);
8269+
AttShutParams params;
8270+
params.attachments = queue;
8271+
Thread::start(attachmentShutdownThread, &params, THREAD_high, &params.thrHandle);
8272+
queue.release();
8273+
shutThreadCollect->houseKeeping();
8274+
params.thdStartedSem.enter();
82438275
}
82448276
}
82458277
catch (const Exception&)

src/jrd/svc.cpp

Lines changed: 4 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
#include "../utilities/nbackup/nbkswi.h"
7878
#include "../jrd/trace/traceswi.h"
7979
#include "../jrd/val_proto.h"
80+
#include "../jrd/ThreadCollect.h"
8081

8182
#ifdef HAVE_SYS_TYPES_H
8283
#include <sys/types.h>
@@ -114,6 +115,7 @@
114115

115116

116117
using namespace Firebird;
118+
using namespace Jrd;
117119

118120
const int SVC_user_dba = 2;
119121
const int SVC_user_any = 1;
@@ -132,63 +134,10 @@ namespace {
132134
GlobalPtr<Mutex> globalServicesMutex;
133135

134136
// All that we need to shutdown service threads when shutdown in progress
135-
typedef Array<Jrd::Service*> AllServices;
137+
typedef Array<Service*> AllServices;
136138
GlobalPtr<AllServices> allServices; // protected by globalServicesMutex
137139
volatile bool svcShutdown = false;
138140

139-
class ThreadCollect
140-
{
141-
public:
142-
ThreadCollect(MemoryPool& p)
143-
: threads(p)
144-
{ }
145-
146-
void join()
147-
{
148-
// join threads to be sure they are gone when shutdown is complete
149-
// no need locking something cause this is expected to run when services are closing
150-
waitFor(threads);
151-
}
152-
153-
void add(Thread::Handle& h)
154-
{
155-
// put thread into completion wait queue when it finished running
156-
MutexLockGuard g(threadsMutex, FB_FUNCTION);
157-
threads.add(h);
158-
}
159-
160-
void houseKeeping()
161-
{
162-
if (!threads.hasData())
163-
return;
164-
165-
// join finished threads
166-
AllThreads t;
167-
{ // mutex scope
168-
MutexLockGuard g(threadsMutex, FB_FUNCTION);
169-
t.assign(threads);
170-
threads.clear();
171-
}
172-
173-
waitFor(t);
174-
}
175-
176-
private:
177-
typedef Array<Thread::Handle> AllThreads;
178-
179-
static void waitFor(AllThreads& thr)
180-
{
181-
while (thr.hasData())
182-
{
183-
Thread::Handle h(thr.pop());
184-
Thread::waitForCompletion(h);
185-
}
186-
}
187-
188-
AllThreads threads;
189-
Mutex threadsMutex;
190-
};
191-
192141
GlobalPtr<ThreadCollect> threadCollect;
193142

194143
void spbVersionError()
@@ -200,8 +149,6 @@ namespace {
200149
} // anonymous namespace
201150

202151

203-
using namespace Jrd;
204-
205152
Service::Validate::Validate(Service* svc)
206153
: sharedGuard(globalServicesMutex, FB_FUNCTION)
207154
{
@@ -1983,7 +1930,7 @@ THREAD_ENTRY_DECLARE Service::run(THREAD_ENTRY_PARAM arg)
19831930
svc->finish(SVC_finished);
19841931

19851932
if (thrHandle)
1986-
threadCollect->add(thrHandle);
1933+
threadCollect->ending(thrHandle);
19871934
}
19881935
catch (const Exception& ex)
19891936
{

0 commit comments

Comments
 (0)