diff --git a/lib/libc/gen/pthread_atfork.c b/lib/libc/gen/pthread_atfork.c index 8d66e74e83a2..18c8e3db9ad1 100644 --- a/lib/libc/gen/pthread_atfork.c +++ b/lib/libc/gen/pthread_atfork.c @@ -1,4 +1,4 @@ -/* $NetBSD: pthread_atfork.c,v 1.6 2007/12/14 19:51:37 yamt Exp $ */ +/* $NetBSD: pthread_atfork.c,v 1.7 2008/03/07 17:56:39 ad Exp $ */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. @@ -38,7 +38,7 @@ #include #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: pthread_atfork.c,v 1.6 2007/12/14 19:51:37 yamt Exp $"); +__RCSID("$NetBSD: pthread_atfork.c,v 1.7 2008/03/07 17:56:39 ad Exp $"); #endif /* LIBC_SCCS and not lint */ #include "namespace.h" @@ -67,6 +67,7 @@ struct atfork_callback { * since the intended use of the functions is obtaining locks to hold * across the fork, forking is going to be serialized anyway. */ +static struct atfork_callback atfork_builtin; static mutex_t atfork_lock = MUTEX_INITIALIZER; SIMPLEQ_HEAD(atfork_callback_q, atfork_callback); @@ -74,6 +75,24 @@ static struct atfork_callback_q prepareq = SIMPLEQ_HEAD_INITIALIZER(prepareq); static struct atfork_callback_q parentq = SIMPLEQ_HEAD_INITIALIZER(parentq); static struct atfork_callback_q childq = SIMPLEQ_HEAD_INITIALIZER(childq); +static struct atfork_callback * +af_alloc(void) +{ + + if (atfork_builtin.fn == NULL) + return &atfork_builtin; + + return malloc(sizeof(atfork_builtin)); +} + +static void +af_free(struct atfork_callback *af) +{ + + if (af != &atfork_builtin) + free(af); +} + int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) @@ -82,36 +101,40 @@ pthread_atfork(void (*prepare)(void), void (*parent)(void), newprepare = newparent = newchild = NULL; + mutex_lock(&atfork_lock); if (prepare != NULL) { - newprepare = malloc(sizeof(struct atfork_callback)); - if (newprepare == NULL) + newprepare = af_alloc(); + if (newprepare == NULL) { + mutex_unlock(&atfork_lock); return ENOMEM; + } newprepare->fn = prepare; } if (parent != NULL) { - newparent = malloc(sizeof(struct atfork_callback)); + newparent = af_alloc(); if (newparent == NULL) { if (newprepare != NULL) - free(newprepare); + af_free(newprepare); + mutex_unlock(&atfork_lock); return ENOMEM; } newparent->fn = parent; } if (child != NULL) { - newchild = malloc(sizeof(struct atfork_callback)); + newchild = af_alloc(); if (newchild == NULL) { if (newprepare != NULL) - free(newprepare); + af_free(newprepare); if (newparent != NULL) - free(newparent); + af_free(newparent); + mutex_unlock(&atfork_lock); return ENOMEM; } newchild->fn = child; } - mutex_lock(&atfork_lock); /* * The order in which the functions are called is specified as * LIFO for the prepare handler and FIFO for the others; insert