Keep one builtin slot so that pthread initialization doesn't need to use

malloc().
This commit is contained in:
ad 2008-03-07 17:56:39 +00:00
parent 8ecf8999bf
commit 1046045268
1 changed files with 33 additions and 10 deletions

View File

@ -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. * Copyright (c) 2002 The NetBSD Foundation, Inc.
@ -38,7 +38,7 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint) #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 */ #endif /* LIBC_SCCS and not lint */
#include "namespace.h" #include "namespace.h"
@ -67,6 +67,7 @@ struct atfork_callback {
* since the intended use of the functions is obtaining locks to hold * since the intended use of the functions is obtaining locks to hold
* across the fork, forking is going to be serialized anyway. * across the fork, forking is going to be serialized anyway.
*/ */
static struct atfork_callback atfork_builtin;
static mutex_t atfork_lock = MUTEX_INITIALIZER; static mutex_t atfork_lock = MUTEX_INITIALIZER;
SIMPLEQ_HEAD(atfork_callback_q, atfork_callback); 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 parentq = SIMPLEQ_HEAD_INITIALIZER(parentq);
static struct atfork_callback_q childq = SIMPLEQ_HEAD_INITIALIZER(childq); 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 int
pthread_atfork(void (*prepare)(void), void (*parent)(void), pthread_atfork(void (*prepare)(void), void (*parent)(void),
void (*child)(void)) void (*child)(void))
@ -82,36 +101,40 @@ pthread_atfork(void (*prepare)(void), void (*parent)(void),
newprepare = newparent = newchild = NULL; newprepare = newparent = newchild = NULL;
mutex_lock(&atfork_lock);
if (prepare != NULL) { if (prepare != NULL) {
newprepare = malloc(sizeof(struct atfork_callback)); newprepare = af_alloc();
if (newprepare == NULL) if (newprepare == NULL) {
mutex_unlock(&atfork_lock);
return ENOMEM; return ENOMEM;
}
newprepare->fn = prepare; newprepare->fn = prepare;
} }
if (parent != NULL) { if (parent != NULL) {
newparent = malloc(sizeof(struct atfork_callback)); newparent = af_alloc();
if (newparent == NULL) { if (newparent == NULL) {
if (newprepare != NULL) if (newprepare != NULL)
free(newprepare); af_free(newprepare);
mutex_unlock(&atfork_lock);
return ENOMEM; return ENOMEM;
} }
newparent->fn = parent; newparent->fn = parent;
} }
if (child != NULL) { if (child != NULL) {
newchild = malloc(sizeof(struct atfork_callback)); newchild = af_alloc();
if (newchild == NULL) { if (newchild == NULL) {
if (newprepare != NULL) if (newprepare != NULL)
free(newprepare); af_free(newprepare);
if (newparent != NULL) if (newparent != NULL)
free(newparent); af_free(newparent);
mutex_unlock(&atfork_lock);
return ENOMEM; return ENOMEM;
} }
newchild->fn = child; newchild->fn = child;
} }
mutex_lock(&atfork_lock);
/* /*
* The order in which the functions are called is specified as * The order in which the functions are called is specified as
* LIFO for the prepare handler and FIFO for the others; insert * LIFO for the prepare handler and FIFO for the others; insert