1*0a6a1f1dSLionel Sambuc /* $NetBSD: pthread_atfork.c,v 1.10 2015/01/20 18:31:25 christos Exp $ */
22fe8fb19SBen Gras
32fe8fb19SBen Gras /*-
42fe8fb19SBen Gras * Copyright (c) 2002 The NetBSD Foundation, Inc.
52fe8fb19SBen Gras * All rights reserved.
62fe8fb19SBen Gras *
72fe8fb19SBen Gras * This code is derived from software contributed to The NetBSD Foundation
82fe8fb19SBen Gras * by Nathan J. Williams.
92fe8fb19SBen Gras *
102fe8fb19SBen Gras * Redistribution and use in source and binary forms, with or without
112fe8fb19SBen Gras * modification, are permitted provided that the following conditions
122fe8fb19SBen Gras * are met:
132fe8fb19SBen Gras * 1. Redistributions of source code must retain the above copyright
142fe8fb19SBen Gras * notice, this list of conditions and the following disclaimer.
152fe8fb19SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
162fe8fb19SBen Gras * notice, this list of conditions and the following disclaimer in the
172fe8fb19SBen Gras * documentation and/or other materials provided with the distribution.
182fe8fb19SBen Gras *
192fe8fb19SBen Gras * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
202fe8fb19SBen Gras * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
212fe8fb19SBen Gras * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
222fe8fb19SBen Gras * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
232fe8fb19SBen Gras * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
242fe8fb19SBen Gras * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
252fe8fb19SBen Gras * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
262fe8fb19SBen Gras * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
272fe8fb19SBen Gras * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
282fe8fb19SBen Gras * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
292fe8fb19SBen Gras * POSSIBILITY OF SUCH DAMAGE.
302fe8fb19SBen Gras */
312fe8fb19SBen Gras
322fe8fb19SBen Gras #include <sys/cdefs.h>
332fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
34*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: pthread_atfork.c,v 1.10 2015/01/20 18:31:25 christos Exp $");
352fe8fb19SBen Gras #endif /* LIBC_SCCS and not lint */
362fe8fb19SBen Gras
372fe8fb19SBen Gras #include "namespace.h"
382fe8fb19SBen Gras
392fe8fb19SBen Gras #include <errno.h>
402fe8fb19SBen Gras #include <stdlib.h>
412fe8fb19SBen Gras #include <unistd.h>
422fe8fb19SBen Gras #include <sys/queue.h>
432fe8fb19SBen Gras #include "reentrant.h"
442fe8fb19SBen Gras
452fe8fb19SBen Gras #ifdef __weak_alias
462fe8fb19SBen Gras __weak_alias(pthread_atfork, _pthread_atfork)
472fe8fb19SBen Gras __weak_alias(fork, _fork)
482fe8fb19SBen Gras #endif /* __weak_alias */
492fe8fb19SBen Gras
50f14fb602SLionel Sambuc pid_t __fork(void); /* XXX */
512fe8fb19SBen Gras
522fe8fb19SBen Gras struct atfork_callback {
532fe8fb19SBen Gras SIMPLEQ_ENTRY(atfork_callback) next;
542fe8fb19SBen Gras void (*fn)(void);
552fe8fb19SBen Gras };
562fe8fb19SBen Gras
572fe8fb19SBen Gras /*
582fe8fb19SBen Gras * Hypothetically, we could protect the queues with a rwlock which is
592fe8fb19SBen Gras * write-locked by pthread_atfork() and read-locked by fork(), but
602fe8fb19SBen Gras * since the intended use of the functions is obtaining locks to hold
612fe8fb19SBen Gras * across the fork, forking is going to be serialized anyway.
622fe8fb19SBen Gras */
632fe8fb19SBen Gras static struct atfork_callback atfork_builtin;
64*0a6a1f1dSLionel Sambuc #ifdef _REENTRANT
652fe8fb19SBen Gras static mutex_t atfork_lock = MUTEX_INITIALIZER;
66*0a6a1f1dSLionel Sambuc #endif
672fe8fb19SBen Gras SIMPLEQ_HEAD(atfork_callback_q, atfork_callback);
682fe8fb19SBen Gras
692fe8fb19SBen Gras static struct atfork_callback_q prepareq = SIMPLEQ_HEAD_INITIALIZER(prepareq);
702fe8fb19SBen Gras static struct atfork_callback_q parentq = SIMPLEQ_HEAD_INITIALIZER(parentq);
712fe8fb19SBen Gras static struct atfork_callback_q childq = SIMPLEQ_HEAD_INITIALIZER(childq);
722fe8fb19SBen Gras
732fe8fb19SBen Gras static struct atfork_callback *
af_alloc(void)742fe8fb19SBen Gras af_alloc(void)
752fe8fb19SBen Gras {
762fe8fb19SBen Gras
772fe8fb19SBen Gras if (atfork_builtin.fn == NULL)
782fe8fb19SBen Gras return &atfork_builtin;
792fe8fb19SBen Gras
802fe8fb19SBen Gras return malloc(sizeof(atfork_builtin));
812fe8fb19SBen Gras }
822fe8fb19SBen Gras
832fe8fb19SBen Gras static void
af_free(struct atfork_callback * af)842fe8fb19SBen Gras af_free(struct atfork_callback *af)
852fe8fb19SBen Gras {
862fe8fb19SBen Gras
872fe8fb19SBen Gras if (af != &atfork_builtin)
882fe8fb19SBen Gras free(af);
892fe8fb19SBen Gras }
902fe8fb19SBen Gras
912fe8fb19SBen Gras int
pthread_atfork(void (* prepare)(void),void (* parent)(void),void (* child)(void))922fe8fb19SBen Gras pthread_atfork(void (*prepare)(void), void (*parent)(void),
932fe8fb19SBen Gras void (*child)(void))
942fe8fb19SBen Gras {
952fe8fb19SBen Gras struct atfork_callback *newprepare, *newparent, *newchild;
962fe8fb19SBen Gras
972fe8fb19SBen Gras newprepare = newparent = newchild = NULL;
982fe8fb19SBen Gras
992fe8fb19SBen Gras mutex_lock(&atfork_lock);
1002fe8fb19SBen Gras if (prepare != NULL) {
1012fe8fb19SBen Gras newprepare = af_alloc();
1022fe8fb19SBen Gras if (newprepare == NULL) {
1032fe8fb19SBen Gras mutex_unlock(&atfork_lock);
1042fe8fb19SBen Gras return ENOMEM;
1052fe8fb19SBen Gras }
1062fe8fb19SBen Gras newprepare->fn = prepare;
1072fe8fb19SBen Gras }
1082fe8fb19SBen Gras
1092fe8fb19SBen Gras if (parent != NULL) {
1102fe8fb19SBen Gras newparent = af_alloc();
1112fe8fb19SBen Gras if (newparent == NULL) {
1122fe8fb19SBen Gras if (newprepare != NULL)
1132fe8fb19SBen Gras af_free(newprepare);
1142fe8fb19SBen Gras mutex_unlock(&atfork_lock);
1152fe8fb19SBen Gras return ENOMEM;
1162fe8fb19SBen Gras }
1172fe8fb19SBen Gras newparent->fn = parent;
1182fe8fb19SBen Gras }
1192fe8fb19SBen Gras
1202fe8fb19SBen Gras if (child != NULL) {
1212fe8fb19SBen Gras newchild = af_alloc();
1222fe8fb19SBen Gras if (newchild == NULL) {
1232fe8fb19SBen Gras if (newprepare != NULL)
1242fe8fb19SBen Gras af_free(newprepare);
1252fe8fb19SBen Gras if (newparent != NULL)
1262fe8fb19SBen Gras af_free(newparent);
1272fe8fb19SBen Gras mutex_unlock(&atfork_lock);
1282fe8fb19SBen Gras return ENOMEM;
1292fe8fb19SBen Gras }
1302fe8fb19SBen Gras newchild->fn = child;
1312fe8fb19SBen Gras }
1322fe8fb19SBen Gras
1332fe8fb19SBen Gras /*
1342fe8fb19SBen Gras * The order in which the functions are called is specified as
1352fe8fb19SBen Gras * LIFO for the prepare handler and FIFO for the others; insert
1362fe8fb19SBen Gras * at the head and tail as appropriate so that SIMPLEQ_FOREACH()
1372fe8fb19SBen Gras * produces the right order.
1382fe8fb19SBen Gras */
1392fe8fb19SBen Gras if (prepare)
1402fe8fb19SBen Gras SIMPLEQ_INSERT_HEAD(&prepareq, newprepare, next);
1412fe8fb19SBen Gras if (parent)
1422fe8fb19SBen Gras SIMPLEQ_INSERT_TAIL(&parentq, newparent, next);
1432fe8fb19SBen Gras if (child)
1442fe8fb19SBen Gras SIMPLEQ_INSERT_TAIL(&childq, newchild, next);
1452fe8fb19SBen Gras mutex_unlock(&atfork_lock);
1462fe8fb19SBen Gras
1472fe8fb19SBen Gras return 0;
1482fe8fb19SBen Gras }
1492fe8fb19SBen Gras
1502fe8fb19SBen Gras pid_t
fork(void)1512fe8fb19SBen Gras fork(void)
1522fe8fb19SBen Gras {
1532fe8fb19SBen Gras struct atfork_callback *iter;
1542fe8fb19SBen Gras pid_t ret;
1552fe8fb19SBen Gras
1562fe8fb19SBen Gras mutex_lock(&atfork_lock);
1572fe8fb19SBen Gras SIMPLEQ_FOREACH(iter, &prepareq, next)
1582fe8fb19SBen Gras (*iter->fn)();
1592fe8fb19SBen Gras
1602fe8fb19SBen Gras ret = __fork();
1612fe8fb19SBen Gras
1622fe8fb19SBen Gras if (ret != 0) {
1632fe8fb19SBen Gras /*
1642fe8fb19SBen Gras * We are the parent. It doesn't matter here whether
1652fe8fb19SBen Gras * the fork call succeeded or failed.
1662fe8fb19SBen Gras */
1672fe8fb19SBen Gras SIMPLEQ_FOREACH(iter, &parentq, next)
1682fe8fb19SBen Gras (*iter->fn)();
1692fe8fb19SBen Gras mutex_unlock(&atfork_lock);
1702fe8fb19SBen Gras } else {
1712fe8fb19SBen Gras /* We are the child */
1722fe8fb19SBen Gras SIMPLEQ_FOREACH(iter, &childq, next)
1732fe8fb19SBen Gras (*iter->fn)();
1742fe8fb19SBen Gras /*
1752fe8fb19SBen Gras * Note: We are explicitly *not* unlocking
1762fe8fb19SBen Gras * atfork_lock. Unlocking atfork_lock is problematic,
1772fe8fb19SBen Gras * because if any threads in the parent blocked on it
1782fe8fb19SBen Gras * between the initial lock and the fork() syscall,
1792fe8fb19SBen Gras * unlocking in the child will try to schedule
1802fe8fb19SBen Gras * threads, and either the internal mutex interlock or
1812fe8fb19SBen Gras * the runqueue spinlock could have been held at the
1822fe8fb19SBen Gras * moment of fork(). Since the other threads do not
1832fe8fb19SBen Gras * exist in this process, the spinlock will never be
1842fe8fb19SBen Gras * unlocked, and we would wedge.
1852fe8fb19SBen Gras * Instead, we reinitialize atfork_lock, since we know
1862fe8fb19SBen Gras * that the state of the atfork lists is consistent here,
1872fe8fb19SBen Gras * and that there are no other threads to be affected by
1882fe8fb19SBen Gras * the forcible cleaning of the queue.
1892fe8fb19SBen Gras * This permits double-forking to work, although
1902fe8fb19SBen Gras * it requires knowing that it's "safe" to initialize
1912fe8fb19SBen Gras * a locked mutex in this context.
1922fe8fb19SBen Gras *
1932fe8fb19SBen Gras * The problem exists for users of this interface,
1942fe8fb19SBen Gras * too, since the intented use of pthread_atfork() is
1952fe8fb19SBen Gras * to acquire locks across the fork call to ensure
1962fe8fb19SBen Gras * that the child sees consistent state. There's not
1972fe8fb19SBen Gras * much that can usefully be done in a child handler,
1982fe8fb19SBen Gras * and conventional wisdom discourages using them, but
1992fe8fb19SBen Gras * they're part of the interface, so here we are...
2002fe8fb19SBen Gras */
2012fe8fb19SBen Gras mutex_init(&atfork_lock, NULL);
2022fe8fb19SBen Gras }
2032fe8fb19SBen Gras
2042fe8fb19SBen Gras return ret;
2052fe8fb19SBen Gras }
206