Tcl Source Code

Artifact [faf7d48e82]
Login

Artifact faf7d48e82d1b2012d2858f5495d19c913044e86:

Attachment "atfork.diff" to ticket [923072ffff] added by davidw 2004-03-25 19:25:40.
Index: tests//thread.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/thread.test,v
retrieving revision 1.10
diff -u -r1.10 thread.test
--- tests//thread.test	2 May 2000 22:02:36 -0000	1.10
+++ tests//thread.test	25 Mar 2004 11:29:20 -0000
@@ -258,6 +260,29 @@
     threadReap
     lrange $msg 0 2
 } {cannot join thread}
+
+test thread-6.0 {See if tcl and threads survive a fork()} {testthread unixOnly} {
+    set pid [testfork]
+    if {$pid == 0} {
+	exit 0
+    } else {
+	set retpid [testwaitpid $pid]
+    }
+    expr $pid == $retpid
+} {1}
+
+test thread-6.1 {See if tcl, threads, and an event survive a fork()} {testthread unixOnly} {
+    after 1000 [list set foo 1]
+    set pid [testfork]
+    if {$pid == 0} {
+	vwait foo
+	exit 0
+    } else {
+	testwaitpid $pid
+    }
+    vwait foo
+    set foo
+} {1}
 
 # cleanup
 ::tcltest::cleanupTests
Index: unix//tcl.m4
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tcl.m4,v
retrieving revision 1.114
diff -u -r1.114 tcl.m4
--- unix//tcl.m4	18 Mar 2004 19:01:43 -0000	1.114
+++ unix//tcl.m4	25 Mar 2004 11:29:23 -0000
@@ -469,6 +469,7 @@
 	ac_saved_libs=$LIBS
 	LIBS="$LIBS $THREADS_LIBS"
 	AC_CHECK_FUNCS(pthread_attr_setstacksize)
+	AC_CHECK_FUNCS(pthread_atfork)
 	LIBS=$ac_saved_libs
 	AC_CHECK_FUNCS(readdir_r)
     else
Index: unix//tclUnixInit.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixInit.c,v
retrieving revision 1.39
diff -u -r1.39 tclUnixInit.c
--- unix//tclUnixInit.c	9 Mar 2004 13:34:45 -0000	1.39
+++ unix//tclUnixInit.c	25 Mar 2004 11:29:23 -0000
@@ -935,6 +935,15 @@
     return result;
 }
 
+#if defined(TCL_THREADS) && defined(HAVE_PTHREAD_ATFORK)
+static pthread_once_t	once = PTHREAD_ONCE_INIT;
+ 
+static void
+InitAtfork(void)
+{
+    pthread_atfork(TclpAtforkLock, TclpAtForkParent, TclpAtForkChild);
+}
+#endif
 /*
  *----------------------------------------------------------------------
  *
@@ -965,12 +974,17 @@
 	    return (TCL_ERROR);
 	};
     }
-    
+
+#if defined(TCL_THREADS) && defined(HAVE_PTHREAD_ATFORK)
+    pthread_once(&once, InitAtfork);
+#endif
+
     pathPtr = TclGetLibraryPath();
     if (pathPtr == NULL) {
 	pathPtr = Tcl_NewObj();
     }
     Tcl_SetVar2Ex(interp, "tcl_libPath", NULL, pathPtr, TCL_GLOBAL_ONLY);
+
     return Tcl_Eval(interp, initScript);
 }
 
Index: unix//tclUnixPort.h
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixPort.h,v
retrieving revision 1.34
diff -u -r1.34 tclUnixPort.h
--- unix//tclUnixPort.h	9 Mar 2004 13:32:26 -0000	1.34
+++ unix//tclUnixPort.h	25 Mar 2004 11:29:24 -0000
@@ -578,6 +578,10 @@
  */
 #define NO_REALPATH
 #endif
+EXTERN void		TclpAtforkLock(void);
+EXTERN void		TclpAtforkUnlock(void);
+EXTERN void		TclpAtForkChild(void);
+EXTERN void		TclpAtForkParent(void);
 #else
 typedef int TclpMutex;
 #define	TclpMutexInit(a)
Index: unix//tclUnixTest.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixTest.c,v
retrieving revision 1.15
diff -u -r1.15 tclUnixTest.c
--- unix//tclUnixTest.c	13 Oct 2003 00:59:48 -0000	1.15
+++ unix//tclUnixTest.c	25 Mar 2004 11:29:24 -0000
@@ -82,6 +82,10 @@
 			    Tcl_Interp *interp, int argc, CONST char **argv));
 static int		TestgotsigCmd _ANSI_ARGS_((ClientData dummy,
 			    Tcl_Interp *interp, int argc, CONST char **argv));
+static int		TestforkCmd _ANSI_ARGS_((ClientData dummy,
+			    Tcl_Interp *interp, int argc, CONST char **argv));
+static int		TestwaitpidCmd _ANSI_ARGS_((ClientData dummy,
+			    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
 static void 		AlarmHandler _ANSI_ARGS_(());
 
 /*
@@ -121,6 +125,10 @@
             (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
     Tcl_CreateCommand(interp, "testgotsig", TestgotsigCmd,
             (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
+    Tcl_CreateCommand(interp, "testfork", TestforkCmd,
+            (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
+    Tcl_CreateObjCommand(interp, "testwaitpid", TestwaitpidCmd,
+			 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
     return TCL_OK;
 }
 
@@ -701,5 +709,82 @@
 {
     Tcl_AppendResult(interp, gotsig, (char *) NULL);
     gotsig = "0";
+    return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ * TestforkCmd --
+ *
+ * 	Implementation of fork().
+ *
+ * Results:
+ *	In the parent process, the child process' pid, in the child, 0.
+ *
+ * Side Effects:
+ *	Creates a new process.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+TestforkCmd(clientData, interp, argc, argv)
+    ClientData clientData;		/* Not used. */
+    Tcl_Interp *interp;			/* Current interpreter. */
+    int argc;				/* Number of arguments. */
+    CONST char **argv;			/* Argument strings. */
+{
+    pid_t pid;
+
+    pid = fork();
+    if (pid < 0) {
+	Tcl_AppendResult(interp, "fork failed: ",
+			 Tcl_PosixError(interp),
+			 (char *)NULL);
+	return TCL_ERROR;
+    }
+    Tcl_SetIntObj (Tcl_GetObjResult (interp), (int)pid);
+    return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ * TestwaitpidCmd --
+ *
+ * 	Implementation of waitpid().
+ *
+ * Results:
+ *	Returns the PID of the process we waited on.
+ *
+ * Side Effects:
+ *	Waits untill the process in question exits.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+TestwaitpidCmd(clientData, interp, objc, objv)
+    ClientData clientData;		/* Not used. */
+    Tcl_Interp *interp;			/* Current interpreter. */
+    int objc;				/* Number of arguments. */
+    Tcl_Obj *CONST objv[];			/* Argument strings. */
+{
+    pid_t pid = 0;
+    pid_t returnPid = 0;
+    int status = 0;
+
+    if (Tcl_GetIntFromObj(interp, objv[1], &pid) != TCL_OK) {
+	return TCL_ERROR;
+    }
+
+    returnPid = waitpid(pid, &status, 0);
+    if (returnPid < 0) {
+	Tcl_AppendResult(interp, "wait failed: ",
+			 Tcl_PosixError(interp),
+			 (char *)NULL);
+	return TCL_ERROR;
+    }
+    Tcl_SetObjResult(interp, Tcl_NewIntObj(returnPid));
+
     return TCL_OK;
 }