perl built with USE_ITHREADS can deadlock during fork() or backticks
Gurusamy Sarathy [Thu, 5 Jul 2001 00:42:49 +0000 (00:42 +0000)]
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

perl.c
thread.h
win32/win32thread.h

diff --git a/perl.c b/perl.c
index 935ab3d..cef5c47 100644 (file)
--- 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);              \
index 87fcdbe..a1e8fdc 100644 (file)
--- a/thread.h
+++ b/thread.h
     } 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
index 1f8840c..7105eca 100644 (file)
@@ -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 {                                                       \