8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 00:03:03 +01:00

Fixed CORE-3646: Segmentation fault in multi-threaded program when using 2.5.x client library on Linux

This commit is contained in:
alexpeshkoff 2011-10-31 18:35:59 +00:00
parent 99370a52ad
commit 84eedc8787
3 changed files with 13 additions and 150 deletions

View File

@ -13,6 +13,9 @@
#ifdef WIN_NT #ifdef WIN_NT
#include <windows.h> #include <windows.h>
#else
#include <pthread.h>
#include <signal.h>
#endif #endif
namespace { namespace {
@ -76,6 +79,15 @@ private:
thread = currTID; thread = currTID;
} }
} }
#else
if (thread != currTID)
{
if (pthread_kill(thread, 0) == ESRCH)
{
// Thread does not exist any more
thread = currTID;
}
}
#endif #endif
return thread == currTID; return thread == currTID;
@ -91,9 +103,7 @@ public:
explicit StringsBuffer(Firebird::MemoryPool& p) : processBuffer(p) { } explicit StringsBuffer(Firebird::MemoryPool& p) : processBuffer(p) { }
~StringsBuffer() ~StringsBuffer()
{ { }
ThreadCleanup::remove(cleanupAllStrings, this);
}
private: private:
size_t position(FB_THREAD_ID thr) size_t position(FB_THREAD_ID thr)
@ -126,29 +136,9 @@ private:
return b; return b;
} }
void cleanup()
{
Firebird::MutexLockGuard guard(mutex);
size_t p = position(getThreadId());
if (p >= processBuffer.getCount())
{
return;
}
delete processBuffer[p];
processBuffer.remove(p);
}
static void cleanupAllStrings(void* toClean)
{
static_cast<StringsBuffer*>(toClean)->cleanup();
}
public: public:
const char* alloc(const char* s, size_t& len, FB_THREAD_ID thr = getThreadId()) const char* alloc(const char* s, size_t& len, FB_THREAD_ID thr = getThreadId())
{ {
ThreadCleanup::add(cleanupAllStrings, this);
return getThreadBuffer(thr)->alloc(s, len); return getThreadBuffer(thr)->alloc(s, len);
} }
}; };

View File

@ -154,111 +154,3 @@ void THD_yield()
SleepEx(0, FALSE); SleepEx(0, FALSE);
#endif #endif
} }
// Cleanup on thread completion
#ifdef USE_POSIX_THREADS
namespace {
pthread_key_t key;
pthread_once_t keyOnce = PTHREAD_ONCE_INIT;
void makeKey()
{
int err = pthread_key_create(&key, ThreadCleanup::destructor);
if (err)
{
Firebird::system_call_failed("pthread_key_create", err);
}
}
void initThreadCleanup()
{
int err = pthread_once(&keyOnce, makeKey);
if (err)
{
Firebird::system_call_failed("pthread_once", err);
}
err = pthread_setspecific(key, &key);
if (err)
{
Firebird::system_call_failed("pthread_setspecific", err);
}
}
ThreadCleanup* chain = NULL;
Firebird::GlobalPtr<Firebird::Mutex> cleanupMutex;
} // anonymous namespace
ThreadCleanup** ThreadCleanup::findCleanup(FPTR_VOID_PTR cleanup, void* arg)
{
for (ThreadCleanup** ptr = &chain; *ptr; ptr = &((*ptr)->next))
{
if ((*ptr)->function == cleanup && (*ptr)->argument == arg)
{
return ptr;
}
}
return NULL;
}
void ThreadCleanup::destructor(void*)
{
Firebird::MutexLockGuard guard(cleanupMutex);
for (ThreadCleanup* ptr = chain; ptr; ptr = ptr->next)
{
ptr->function(ptr->argument);
}
}
void ThreadCleanup::add(FPTR_VOID_PTR cleanup, void* arg)
{
Firebird::MutexLockGuard guard(cleanupMutex);
initThreadCleanup();
if (findCleanup(cleanup, arg))
{
return;
}
chain = FB_NEW(*getDefaultMemoryPool()) ThreadCleanup(cleanup, arg, chain);
}
void ThreadCleanup::remove(FPTR_VOID_PTR cleanup, void* arg)
{
ThreadCleanup** ptr = findCleanup(cleanup, arg);
if (!ptr)
{
return;
}
ThreadCleanup* toDelete = *ptr;
*ptr = toDelete->next;
delete toDelete;
}
#else // USE_POSIX_THREADS
ThreadCleanup** ThreadCleanup::findCleanup(FPTR_VOID_PTR, void*)
{
return NULL;
}
void ThreadCleanup::destructor(void*)
{
}
void ThreadCleanup::add(FPTR_VOID_PTR, void*)
{
}
void ThreadCleanup::remove(FPTR_VOID_PTR, void*)
{
}
#endif // USE_POSIX_THREADS

View File

@ -37,23 +37,4 @@ void THD_yield();
// thread ID // thread ID
FB_THREAD_ID getThreadId() throw(); FB_THREAD_ID getThreadId() throw();
class ThreadCleanup
{
public:
static void add(FPTR_VOID_PTR cleanup, void* arg);
static void remove(FPTR_VOID_PTR cleanup, void* arg);
static void destructor(void*);
private:
FPTR_VOID_PTR function;
void* argument;
ThreadCleanup* next;
ThreadCleanup(FPTR_VOID_PTR cleanup, void* arg, ThreadCleanup* chain)
: function(cleanup), argument(arg), next(chain) { }
~ThreadCleanup() { }
static ThreadCleanup** findCleanup(FPTR_VOID_PTR cleanup, void* arg);
};
#endif // JRD_THD_H #endif // JRD_THD_H