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