system() using vfork() or posix_spawn() and libthr

Konstantin Belousov kostikbel at gmail.com
Fri Aug 10 10:13:08 UTC 2012


On Thu, Aug 09, 2012 at 02:08:50PM +0300, Konstantin Belousov wrote:
> Third alternative, which seems to be even better, is to restore
> single-threading of the parent for vfork().

I mean this patch.


diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 6cb95cd..e59ee21 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -756,7 +756,7 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp,
 	struct thread *td2;
 	struct vmspace *vm2;
 	vm_ooffset_t mem_charged;
-	int error;
+	int error, single_threaded;
 	static int curfail;
 	static struct timeval lastfail;
 #ifdef PROCDESC
@@ -815,6 +815,19 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp,
 	}
 #endif
 
+	if (((p1->p_flag & (P_HADTHREADS | P_SYSTEM)) == P_HADTHREADS) &&
+	    (flags & RFPPWAIT) != 0) {
+		PROC_LOCK(p1);
+		if (thread_single(SINGLE_BOUNDARY)) {
+			PROC_UNLOCK(p1);
+			error = ERESTART;
+			goto fail2;
+		}
+		PROC_UNLOCK(p1);
+		single_threaded = 1;
+	} else
+		single_threaded = 0;
+
 	mem_charged = 0;
 	vm2 = NULL;
 	if (pages == 0)
@@ -945,6 +958,12 @@ fail1:
 	if (vm2 != NULL)
 		vmspace_free(vm2);
 	uma_zfree(proc_zone, newproc);
+	if (single_threaded) {
+		PROC_LOCK(p1);
+		thread_single_end();
+		PROC_UNLOCK(p1);
+	}
+fail2:
 #ifdef PROCDESC
 	if (((flags & RFPROCDESC) != 0) && (fp_procdesc != NULL)) {
 		fdclose(td->td_proc->p_fd, fp_procdesc, *procdescp, td);
diff --git a/tools/test/pthread_vfork/pthread_vfork_test.c b/tools/test/pthread_vfork/pthread_vfork_test.c
index e004727..88956c2 100644
--- a/tools/test/pthread_vfork/pthread_vfork_test.c
+++ b/tools/test/pthread_vfork/pthread_vfork_test.c
@@ -29,6 +29,8 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <sys/types.h>
+#include <sys/wait.h>
 #include <err.h>
 #include <pthread.h>
 #include <signal.h>
@@ -39,10 +41,11 @@ __FBSDID("$FreeBSD$");
 
 #define NUM_THREADS 100
 
-void *
-vfork_test(void *threadid)
+static void *
+vfork_test(void *threadid __unused)
 {
-	pid_t pid;
+	pid_t pid, wpid;
+	int status;
 
 	for (;;) {
 		pid = vfork();
@@ -50,10 +53,20 @@ vfork_test(void *threadid)
 			_exit(0);
 		else if (pid == -1)
 			err(1, "Failed to vfork");
+		else {
+			wpid = waitpid(pid, &status, 0);
+			if (wpid == -1)
+				err(1, "waitpid");
+		}
 	}
 	return (NULL);
 }
 
+static void
+sighandler(int signo __unused)
+{
+}
+
 /*
  * This program invokes multiple threads and each thread calls
  * vfork() system call.
@@ -63,19 +76,24 @@ main(void)
 {
 	pthread_t threads[NUM_THREADS];
 	struct sigaction reapchildren;
+	sigset_t sigchld_mask;
 	int rc, t;
 
 	memset(&reapchildren, 0, sizeof(reapchildren));
-	reapchildren.sa_handler = SIG_IGN;
-
-	/* Automatically reap zombies. */
+	reapchildren.sa_handler = sighandler;
 	if (sigaction(SIGCHLD, &reapchildren, NULL) == -1)
 		err(1, "Could not sigaction(SIGCHLD)");
 
+	sigemptyset(&sigchld_mask);
+	sigaddset(&sigchld_mask, SIGCHLD);
+	if (sigprocmask(SIG_BLOCK, &sigchld_mask, NULL) == -1)
+		err(1, "sigprocmask");
+
 	for (t = 0; t < NUM_THREADS; t++) {
 		rc = pthread_create(&threads[t], NULL, vfork_test, (void *)t);
 		if (rc)
 			errc(1, rc, "pthread_create");
 	}
+	pause();
 	return (0);
 }
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 196 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-hackers/attachments/20120810/289919d0/attachment.pgp


More information about the freebsd-hackers mailing list