Blame SOURCES/tcl-8.5.13-notifier-thread-fork-fix.patch

2e5d8e
diff --git a/unix/configure.in b/unix/configure.in
2e5d8e
index b606b74..46dec02 100755
2e5d8e
--- a/unix/configure.in
2e5d8e
+++ b/unix/configure.in
2e5d8e
@@ -491,6 +491,12 @@ SC_ENABLE_LANGINFO
2e5d8e
 AC_CHECK_FUNCS(chflags)
2e5d8e
 
2e5d8e
 #--------------------------------------------------------------------
2e5d8e
+# Check for support of pthread_atfork function
2e5d8e
+#--------------------------------------------------------------------
2e5d8e
+
2e5d8e
+AC_CHECK_FUNCS(pthread_atfork)
2e5d8e
+
2e5d8e
+#--------------------------------------------------------------------
2e5d8e
 # Check for support of isnan() function or macro
2e5d8e
 #--------------------------------------------------------------------
2e5d8e
 
2e5d8e
@@ -513,7 +519,6 @@ if test "`uname -s`" = "Darwin" ; then
2e5d8e
     if test $tcl_corefoundation = yes; then
2e5d8e
 	AC_CHECK_HEADERS(libkern/OSAtomic.h)
2e5d8e
 	AC_CHECK_FUNCS(OSSpinLockLock)
2e5d8e
-	AC_CHECK_FUNCS(pthread_atfork)
2e5d8e
     fi
2e5d8e
     AC_DEFINE(USE_VFORK, 1, [Should we use vfork() instead of fork()?])
2e5d8e
     AC_DEFINE(TCL_DEFAULT_ENCODING, "utf-8",
2e5d8e
diff --git a/unix/tclUnixNotfy.c b/unix/tclUnixNotfy.c
2e5d8e
index 51f0b1f..9006906 100644
2e5d8e
--- a/unix/tclUnixNotfy.c
2e5d8e
+++ b/unix/tclUnixNotfy.c
2e5d8e
@@ -128,6 +128,15 @@ static Tcl_ThreadDataKey dataKey;
2e5d8e
 static int notifierCount = 0;
2e5d8e
 
2e5d8e
 /*
2e5d8e
+ * The following static stores the process ID of the initialized notifier
2e5d8e
+ * thread. If it changes, we have passed a fork and we should start a new
2e5d8e
+ * notifier thread.
2e5d8e
+ *
2e5d8e
+ * You must hold the notifierMutex lock before accessing this variable.
2e5d8e
+ */
2e5d8e
+static pid_t processIDInitialized = 0;
2e5d8e
+
2e5d8e
+/*
2e5d8e
  * The following variable points to the head of a doubly-linked list of
2e5d8e
  * ThreadSpecificData structures for all threads that are currently waiting on
2e5d8e
  * an event.
2e5d8e
@@ -193,7 +202,13 @@ static Tcl_ThreadId notifierThread;
2e5d8e
 
2e5d8e
 #ifdef TCL_THREADS
2e5d8e
 static void	NotifierThreadProc(ClientData clientData);
2e5d8e
-#endif
2e5d8e
+#ifdef HAVE_PTHREAD_ATFORK
2e5d8e
+static int	atForkInit = 0;
2e5d8e
+static void	AtForkPrepare(void);
2e5d8e
+static void	AtForkParent(void);
2e5d8e
+static void	AtForkChild(void);
2e5d8e
+#endif /* HAVE_PTHREAD_ATFORK */
2e5d8e
+#endif /* TCL_THREADS */
2e5d8e
 static int	FileHandlerEventProc(Tcl_Event *evPtr, int flags);
2e5d8e
 
2e5d8e
 /*
2e5d8e
@@ -267,11 +282,38 @@ Tcl_InitNotifier(void)
2e5d8e
      */
2e5d8e
 
2e5d8e
     Tcl_MutexLock(&notifierMutex);
2e5d8e
+#ifdef HAVE_PTHREAD_ATFORK
2e5d8e
+    /*
2e5d8e
+     * Install pthread_atfork handlers to reinitialize the notifier in the
2e5d8e
+     * child of a fork.
2e5d8e
+     */
2e5d8e
+
2e5d8e
+    if (!atForkInit) {
2e5d8e
+	int result = pthread_atfork(AtForkPrepare, AtForkParent, AtForkChild);
2e5d8e
+
2e5d8e
+	if (result) {
2e5d8e
+	    Tcl_Panic("Tcl_InitNotifier: pthread_atfork failed");
2e5d8e
+	}
2e5d8e
+	atForkInit = 1;
2e5d8e
+    }
2e5d8e
+#endif
2e5d8e
+    /*
2e5d8e
+     * Check if my process id changed, e.g. I was forked
2e5d8e
+     * In this case, restart the notifier thread and close the
2e5d8e
+     * pipe to the original notifier thread
2e5d8e
+     */
2e5d8e
+    if (notifierCount > 0 && processIDInitialized != getpid()) {
2e5d8e
+        notifierCount = 0;
2e5d8e
+        processIDInitialized = 0;
2e5d8e
+        close(triggerPipe);
2e5d8e
+        triggerPipe = -1;
2e5d8e
+    }
2e5d8e
     if (notifierCount == 0) {
2e5d8e
 	if (TclpThreadCreate(&notifierThread, NotifierThreadProc, NULL,
2e5d8e
 		TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE) != TCL_OK) {
2e5d8e
 	    Tcl_Panic("Tcl_InitNotifier: unable to start notifier thread");
2e5d8e
 	}
2e5d8e
+	processIDInitialized = getpid();
2e5d8e
     }
2e5d8e
     notifierCount++;
2e5d8e
 
2e5d8e
@@ -1230,6 +1272,73 @@ NotifierThreadProc(
2e5d8e
 
2e5d8e
     TclpThreadExit (0);
2e5d8e
 }
2e5d8e
+
2e5d8e
+#ifdef HAVE_PTHREAD_ATFORK
2e5d8e
+/*
2e5d8e
+ *----------------------------------------------------------------------
2e5d8e
+ *
2e5d8e
+ * AtForkPrepare --
2e5d8e
+ *
2e5d8e
+ *	Lock the notifier in preparation for a fork.
2e5d8e
+ *
2e5d8e
+ * Results:
2e5d8e
+ *	None.
2e5d8e
+ *
2e5d8e
+ * Side effects:
2e5d8e
+ *	None.
2e5d8e
+ *
2e5d8e
+ *----------------------------------------------------------------------
2e5d8e
+ */
2e5d8e
+
2e5d8e
+static void
2e5d8e
+AtForkPrepare(void)
2e5d8e
+{
2e5d8e
+}
2e5d8e
+
2e5d8e
+/*
2e5d8e
+ *----------------------------------------------------------------------
2e5d8e
+ *
2e5d8e
+ * AtForkParent --
2e5d8e
+ *
2e5d8e
+ *	Unlock the notifier in the parent after a fork.
2e5d8e
+ *
2e5d8e
+ * Results:
2e5d8e
+ *	None.
2e5d8e
+ *
2e5d8e
+ * Side effects:
2e5d8e
+ *	None.
2e5d8e
+ *
2e5d8e
+ *----------------------------------------------------------------------
2e5d8e
+ */
2e5d8e
+
2e5d8e
+static void
2e5d8e
+AtForkParent(void)
2e5d8e
+{
2e5d8e
+}
2e5d8e
+
2e5d8e
+/*
2e5d8e
+ *----------------------------------------------------------------------
2e5d8e
+ *
2e5d8e
+ * AtForkChild --
2e5d8e
+ *
2e5d8e
+ *	Unlock and reinstall the notifier in the child after a fork.
2e5d8e
+ *
2e5d8e
+ * Results:
2e5d8e
+ *	None.
2e5d8e
+ *
2e5d8e
+ * Side effects:
2e5d8e
+ *	None.
2e5d8e
+ *
2e5d8e
+ *----------------------------------------------------------------------
2e5d8e
+ */
2e5d8e
+
2e5d8e
+static void
2e5d8e
+AtForkChild(void)
2e5d8e
+{
2e5d8e
+    Tcl_InitNotifier();
2e5d8e
+}
2e5d8e
+#endif /* HAVE_PTHREAD_ATFORK */
2e5d8e
+
2e5d8e
 #endif /* TCL_THREADS */
2e5d8e
 
2e5d8e
 #endif /* HAVE_COREFOUNDATION */