issue-496: Fix possible deadlock in thread+fork
This patch adds a pthread_atfork handler to set the internal locks in consistent state.
This commit is contained in:
parent
73ccf4d1b9
commit
05c33f5308
|
@ -15114,6 +15114,17 @@ _ACEOF
|
|||
fi
|
||||
done
|
||||
# for turning off services when run as root
|
||||
for ac_func in fork
|
||||
do :
|
||||
ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork"
|
||||
if test "x$ac_cv_func_fork" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_FORK 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
done
|
||||
# for the pthread_atfork setup
|
||||
for ac_header in features.h
|
||||
do :
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "features.h" "ac_cv_header_features_h" "$ac_includes_default"
|
||||
|
|
|
@ -134,6 +134,7 @@ AC_CHECK_TYPES([struct mallinfo],,, [#include <malloc.h>])
|
|||
AC_CHECK_TYPES([Elf32_Versym],,, [#include <elf.h>]) # for vdso_support.h
|
||||
AC_CHECK_FUNCS(sbrk) # for tcmalloc to get memory
|
||||
AC_CHECK_FUNCS(geteuid) # for turning off services when run as root
|
||||
AC_CHECK_FUNCS(fork) # for the pthread_atfork setup
|
||||
AC_CHECK_HEADERS(features.h) # for vdso_support.h
|
||||
AC_CHECK_HEADERS(malloc.h) # some systems define stuff there, others not
|
||||
AC_CHECK_HEADERS(sys/malloc.h) # where some versions of OS X put malloc.h
|
||||
|
|
|
@ -79,6 +79,16 @@ class CentralFreeList {
|
|||
// page full of 5-byte objects would have 2 bytes memory overhead).
|
||||
size_t OverheadBytes();
|
||||
|
||||
// Lock/Unlock the internal SpinLock. Used on the pthread_atfork call
|
||||
// to set the lock in a consistent state before the fork.
|
||||
void Lock() {
|
||||
lock_.Lock();
|
||||
}
|
||||
|
||||
void Unlock() {
|
||||
lock_.Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
// TransferCache is used to cache transfers of
|
||||
// sizemap.num_objects_to_move(size_class) back and forth between
|
||||
|
|
|
@ -56,6 +56,9 @@
|
|||
/* Define to 1 if you have the <features.h> header file. */
|
||||
#undef HAVE_FEATURES_H
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#undef HAVE_FORK
|
||||
|
||||
/* Define to 1 if you have the `geteuid' function. */
|
||||
#undef HAVE_GETEUID
|
||||
|
||||
|
|
|
@ -39,6 +39,36 @@
|
|||
|
||||
namespace tcmalloc {
|
||||
|
||||
#if defined(HAVE_FORK) && defined(HAVE_PTHREAD)
|
||||
// These following two functions are registered via pthread_atfork to make
|
||||
// sure the central_cache locks remain in a consisten state in the forked
|
||||
// version of the thread.
|
||||
|
||||
static void CentralCacheLockAll()
|
||||
{
|
||||
Static::pageheap_lock()->Lock();
|
||||
for (int i = 0; i < kNumClasses; ++i)
|
||||
Static::central_cache()[i].Lock();
|
||||
}
|
||||
|
||||
static void CentralCacheUnlockAll()
|
||||
{
|
||||
for (int i = 0; i < kNumClasses; ++i)
|
||||
Static::central_cache()[i].Unlock();
|
||||
Static::pageheap_lock()->Unlock();
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void SetupAtForkLocksHandler()
|
||||
{
|
||||
#if defined(HAVE_FORK) && defined(HAVE_PTHREAD)
|
||||
pthread_atfork(CentralCacheLockAll, // parent calls before fork
|
||||
CentralCacheUnlockAll, // parent calls after fork
|
||||
CentralCacheUnlockAll); // child calls after fork
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
SpinLock Static::pageheap_lock_(SpinLock::LINKER_INITIALIZED);
|
||||
SizeMap Static::sizemap_;
|
||||
CentralFreeListPadded Static::central_cache_[kNumClasses];
|
||||
|
@ -49,6 +79,7 @@ PageHeapAllocator<StackTraceTable::Bucket> Static::bucket_allocator_;
|
|||
StackTrace* Static::growth_stacks_ = NULL;
|
||||
PageHeap* Static::pageheap_ = NULL;
|
||||
|
||||
|
||||
void Static::InitStaticVars() {
|
||||
sizemap_.Init();
|
||||
span_allocator_.Init();
|
||||
|
@ -61,6 +92,8 @@ void Static::InitStaticVars() {
|
|||
for (int i = 0; i < kNumClasses; ++i) {
|
||||
central_cache_[i].Init(i);
|
||||
}
|
||||
SetupAtForkLocksHandler();
|
||||
|
||||
// It's important to have PageHeap allocated, not in static storage,
|
||||
// so that HeapLeakChecker does not consider all the byte patterns stored
|
||||
// in is caches as pointers that are sources of heap object liveness,
|
||||
|
|
Loading…
Reference in New Issue