mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 18:03:04 +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:
parent
99370a52ad
commit
84eedc8787
@ -13,6 +13,9 @@
|
||||
|
||||
#ifdef WIN_NT
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
@ -76,6 +79,15 @@ private:
|
||||
thread = currTID;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (thread != currTID)
|
||||
{
|
||||
if (pthread_kill(thread, 0) == ESRCH)
|
||||
{
|
||||
// Thread does not exist any more
|
||||
thread = currTID;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return thread == currTID;
|
||||
@ -91,9 +103,7 @@ public:
|
||||
explicit StringsBuffer(Firebird::MemoryPool& p) : processBuffer(p) { }
|
||||
|
||||
~StringsBuffer()
|
||||
{
|
||||
ThreadCleanup::remove(cleanupAllStrings, this);
|
||||
}
|
||||
{ }
|
||||
|
||||
private:
|
||||
size_t position(FB_THREAD_ID thr)
|
||||
@ -126,29 +136,9 @@ private:
|
||||
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:
|
||||
const char* alloc(const char* s, size_t& len, FB_THREAD_ID thr = getThreadId())
|
||||
{
|
||||
ThreadCleanup::add(cleanupAllStrings, this);
|
||||
return getThreadBuffer(thr)->alloc(s, len);
|
||||
}
|
||||
};
|
||||
|
@ -154,111 +154,3 @@ void THD_yield()
|
||||
SleepEx(0, FALSE);
|
||||
#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
|
||||
|
@ -37,23 +37,4 @@ void THD_yield();
|
||||
// thread ID
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user