From: Gurusamy Sarathy Date: Thu, 5 Jul 2001 00:42:49 +0000 (+0000) Subject: perl built with USE_ITHREADS can deadlock during fork() or backticks X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=50dd6e574ff39b609595ddb16b2fe9f625a26f8c;p=p5sagit%2Fp5-mst-13.2.git perl built with USE_ITHREADS can deadlock during fork() or backticks since it doesn't ensure threads other than the one calling fork() aren't holding any locks; the fix is to use pthread_atfork() to hold global locks building perl with -Dusemymalloc exacerbates the problem since Perl_malloc() holds a mutex, and perl's exec() calls New() XXX the code in win32thread.h may be needed on platforms that have no pthread_atfork() p4raw-id: //depot/perl@11151 --- diff --git a/perl.c b/perl.c index 935ab3d..cef5c47 100644 --- a/perl.c +++ b/perl.c @@ -58,6 +58,32 @@ static I32 read_e_script(pTHXo_ int idx, SV *buf_sv, int maxlen); } STMT_END #else # if defined(USE_ITHREADS) + +static void S_atfork_lock(void); +static void S_atfork_unlock(void); + +/* this is called in parent before the fork() */ +static void +S_atfork_lock(void) +{ + /* locks must be held in locking order (if any) */ +#ifdef MYMALLOC + MUTEX_LOCK(&PL_malloc_mutex); +#endif + OP_REFCNT_LOCK; +} + +/* this is called in both parent and child after the fork() */ +static void +S_atfork_unlock(void) +{ + /* locks must be released in same order as in S_atfork_lock() */ +#ifdef MYMALLOC + MUTEX_UNLOCK(&PL_malloc_mutex); +#endif + OP_REFCNT_UNLOCK; +} + # define INIT_TLS_AND_INTERP \ STMT_START { \ if (!PL_curinterp) { \ @@ -66,6 +92,9 @@ static I32 read_e_script(pTHXo_ int idx, SV *buf_sv, int maxlen); ALLOC_THREAD_KEY; \ PERL_SET_THX(my_perl); \ OP_REFCNT_INIT; \ + PTHREAD_ATFORK(S_atfork_lock, \ + S_atfork_unlock, \ + S_atfork_unlock); \ } \ else { \ PERL_SET_THX(my_perl); \ diff --git a/thread.h b/thread.h index 87fcdbe1..a1e8fdc 100644 --- a/thread.h +++ b/thread.h @@ -302,6 +302,11 @@ } STMT_END #endif +#ifndef PTHREAD_ATFORK +# define PTHREAD_ATFORK(prepare,parent,child) \ + pthread_atfork(prepare,parent,child) +#endif + #ifndef THREAD_RET_TYPE # define THREAD_RET_TYPE void * # define THREAD_RET_CAST(p) ((void *)(p)) @@ -456,3 +461,7 @@ typedef struct condpair { #ifndef INIT_THREADS # define INIT_THREADS NOOP #endif + +#ifndef PTHREAD_ATFORK +# define PTHREAD_ATFORK(prepare,parent,child) NOOP +#endif diff --git a/win32/win32thread.h b/win32/win32thread.h index 1f8840c..7105eca 100644 --- a/win32/win32thread.h +++ b/win32/win32thread.h @@ -180,6 +180,8 @@ END_EXTERN_C TlsFree(PL_thr_key); \ } STMT_END +#define PTHREAD_ATFORK(prepare,parent,child) NOOP + #if defined(USE_RTL_THREAD_API) && !defined(_MSC_VER) #define JOIN(t, avp) \ STMT_START { \