NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: lib/47428: malloc locking is trouble with threads anad fork



The following reply was made to PR lib/47428; it has been noted by GNATS.

From: Taylor R Campbell <campbell+netbsd%mumble.net@localhost>
To: gnats-bugs%NetBSD.org@localhost
Cc: 
Subject: Re: lib/47428: malloc locking is trouble with threads anad fork
Date: Wed, 25 Jun 2014 00:04:13 +0000

 This is a multi-part message in MIME format.
 --=_nXJoC1A/QFB8fYHpRw1+roM0kwFmhARk
 
 Here's a test program, attached.
 
 As is, it timed out in 93 of 100 trials on my 8-thread Ivy Bridge i7
 laptop and 91 of 100 trials on my 8-thread Ivy Bridge i7 desktop.
 
 When I changed the `#if 0' to `#if 1', so that it installs the malloc
 atfork handlers first, it timed out in only 27 of 100 trials on my
 laptop and only 26 of 100 trials on my desktop.
 
 When I changed the `#if 0' to `#if 1' and modified _malloc_prefork and
 _malloc_postfork to avoid dropping arenas_mtx pre-fork and regrabbing
 it post-fork, it timed out in 0 of 100 trials on my desktop.
 
 (I didn't much feel like messing with libc on my laptop because I am
 using it to type this message.  I could probably make the timeout more
 reliable with the arenas_mtx locking bug, but I spent too much time
 doing this experiment already.)
 
 --=_nXJoC1A/QFB8fYHpRw1+roM0kwFmhARk
 Content-Type: text/plain; charset="ISO-8859-1"; name="mallocfork"
 Content-Transfer-Encoding: quoted-printable
 Content-Disposition: attachment; filename="mallocfork.c"
 
 #include <sys/cdefs.h>
 #include <sys/sysctl.h>
 #include <sys/wait.h>
 
 #include <err.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <pthread.h>
 #include <signal.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 static void *
 mallocloop_thread(void *arg __unused)
 {
 
        for (;;) {
                free(malloc(1));
                pthread_testcancel();
        }
 
        return NULL;
 }
 
 static bool    timed_out =3D false;
 static pid_t   child_pid =3D 0;
 
 static void
 alarm_handler(int signo __unused)
 {
 
        if (child_pid) {
                timed_out =3D true;
                if (kill(child_pid, SIGKILL) =3D=3D -1)
                        warn("kill(%"PRIdMAX", SIGKILL)", (intmax_t)child_pid);
        } else {
                errx(1, "timed out waiting for threads");
        }
 }
 
 extern void    _malloc_prefork(void);
 extern void    _malloc_postfork(void);
 
 int
 main(int argc __unused, char **argv __unused)
 {
        const int mib[] =3D { CTL_HW, HW_NCPU };
        unsigned ncpu;
        size_t len;
        pthread_t *threads;
        unsigned t, i;
        int status;
        int error;
 
 #if 0
        error =3D pthread_atfork(_malloc_prefork, _malloc_postfork,
            _malloc_postfork);
        if (error) {
                errno =3D error;
                err(1, "pthread_atfork");
        }
 #endif
 
        if (signal(SIGALRM, &alarm_handler) =3D=3D SIG_ERR)
                err(1, "signal(SIGALRM)");
 
        len =3D sizeof ncpu;
        if (sysctl(mib, __arraycount(mib), &ncpu, &len, NULL, 0) =3D=3D -1)
                err(1, "sysctl(hw.ncpu)");
 
        threads =3D calloc(ncpu, sizeof threads[0]);
        if (threads =3D=3D NULL)
                err(1, "calloc");
 
        for (t =3D 0; t < ncpu; t++) {
                error =3D pthread_create(&threads[t], NULL, &mallocloop_thread,
                    NULL);
                if (error) {
                        errno =3D error;
                        err(1, "pthread_create");
                }
        }
 
        for (i =3D 0; i < 100; i++) {
                child_pid =3D fork();
                switch (child_pid) {
                case -1:
                        err(1, "fork");
                case 0:         /* child */
                        free(malloc(1));
                        _exit(0);
                default:        /* parent */
                        break;
                }
                if (alarm(3) =3D=3D (unsigned)-1)
                        err(1, "alarm");
                if (waitpid(child_pid, &status, 0) =3D=3D -1)
                        err(1, "waitpid");
                child_pid =3D 0;
                if (alarm(0) =3D=3D (unsigned)-1)
                        err(1, "alarm");
                if (timed_out)
                        errx(1, "timed out waiting for child");
                if (WIFEXITED(status)) {
                        if (WEXITSTATUS(status) !=3D 0) {
                                errx(1, "child exited with %d",
                                    WEXITSTATUS(status));
                        }
                        continue;
                }
                if (WIFSIGNALED(status)) {
                        errx(1, "child terminated on signal %d",
                            WTERMSIG(status));
                }
        }
 
        for (t =3D 0; t < ncpu; t++) {
                error =3D pthread_cancel(threads[t]);
                if (error) {
                        errno =3D error;
                        err(1, "pthread_cancel");
                }
 
                if (alarm(3) =3D=3D (unsigned)-1)
                        err(1, "alarm");
                error =3D pthread_join(threads[t], NULL);
                if (error) {
                        errno =3D error;
                        err(1, "pthread_join");
                }
                if (alarm(0) =3D=3D (unsigned)-1)
                        err(1, "alarm");
        }
 
        return 0;
 }
 
 --=_nXJoC1A/QFB8fYHpRw1+roM0kwFmhARk--
 


Home | Main Index | Thread Index | Old Index