system() using vfork() or posix_spawn() and libthr
David Xu
listlog2011 at gmail.com
Sun Aug 12 00:11:41 UTC 2012
On 2012/08/10 18:13, Konstantin Belousov wrote:
> 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().
single-threading is slow for large threaded process, don't know if it
is necessary for vfork(), POSIX says nothing about threaded process.
> 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);
> }
More information about the freebsd-hackers
mailing list