xref: /illumos-gate/usr/src/lib/libc/port/gen/atfork.c (revision 1da57d55)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52e145884Sraf  * Common Development and Distribution License (the "License").
62e145884Sraf  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
212e145884Sraf 
227c478bd9Sstevel@tonic-gate /*
238cd45542Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include "thr_uberdata.h"
287c478bd9Sstevel@tonic-gate #include "mtlib.h"
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * fork handlers are run in LIFO order.
327c478bd9Sstevel@tonic-gate  * The libc fork handler is expected to be the first handler installed,
337c478bd9Sstevel@tonic-gate  * hence would be the last fork handler run in preparation for fork1().
347c478bd9Sstevel@tonic-gate  * It is essential that this be so, for other libraries depend on libc
357c478bd9Sstevel@tonic-gate  * and may grab their own locks before calling into libc.  By special
367c478bd9Sstevel@tonic-gate  * arrangement, the loader runs libc's init section (libc_init()) first.
377c478bd9Sstevel@tonic-gate  */
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate  * pthread_atfork(): installs handlers to be called during fork1().
417c478bd9Sstevel@tonic-gate  * There is no POSIX API that provides for deletion of atfork handlers.
427c478bd9Sstevel@tonic-gate  * Collaboration between the loader and libc ensures that atfork
437c478bd9Sstevel@tonic-gate  * handlers installed by a library are deleted when that library
447c478bd9Sstevel@tonic-gate  * is unloaded (see _preexec_atfork_unload() in atexit.c).
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate int
pthread_atfork(void (* prepare)(void),void (* parent)(void),void (* child)(void))47*7257d1b4Sraf pthread_atfork(void (*prepare)(void),
487c478bd9Sstevel@tonic-gate 	void (*parent)(void), void (*child)(void))
497c478bd9Sstevel@tonic-gate {
507c478bd9Sstevel@tonic-gate 	ulwp_t *self = curthread;
517c478bd9Sstevel@tonic-gate 	uberdata_t *udp = self->ul_uberdata;
527c478bd9Sstevel@tonic-gate 	atfork_t *atfp;
537c478bd9Sstevel@tonic-gate 	atfork_t *head;
542e145884Sraf 	int error = 0;
557c478bd9Sstevel@tonic-gate 
568cd45542Sraf 	(void) mutex_lock(&udp->atfork_lock);
572e145884Sraf 	if (self->ul_fork) {
587c478bd9Sstevel@tonic-gate 		/*
597c478bd9Sstevel@tonic-gate 		 * Cannot call pthread_atfork() from a fork handler.
607c478bd9Sstevel@tonic-gate 		 */
612e145884Sraf 		error = EDEADLK;
622e145884Sraf 	} else if ((atfp = lmalloc(sizeof (atfork_t))) == NULL) {
632e145884Sraf 		error = ENOMEM;
647c478bd9Sstevel@tonic-gate 	} else {
652e145884Sraf 		atfp->prepare = prepare;
662e145884Sraf 		atfp->parent = parent;
672e145884Sraf 		atfp->child = child;
682e145884Sraf 		if ((head = udp->atforklist) == NULL) {
692e145884Sraf 			udp->atforklist = atfp;
702e145884Sraf 			atfp->forw = atfp->back = atfp;
712e145884Sraf 		} else {
722e145884Sraf 			head->back->forw = atfp;
732e145884Sraf 			atfp->forw = head;
742e145884Sraf 			atfp->back = head->back;
752e145884Sraf 			head->back = atfp;
762e145884Sraf 		}
777c478bd9Sstevel@tonic-gate 	}
782e145884Sraf 
798cd45542Sraf 	(void) mutex_unlock(&udp->atfork_lock);
802e145884Sraf 	return (error);
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * _prefork_handler() is called by fork1() before it starts processing.
857c478bd9Sstevel@tonic-gate  * It executes the user installed "prepare" routines in LIFO order (POSIX)
867c478bd9Sstevel@tonic-gate  */
877c478bd9Sstevel@tonic-gate void
_prefork_handler(void)887c478bd9Sstevel@tonic-gate _prefork_handler(void)
897c478bd9Sstevel@tonic-gate {
907c478bd9Sstevel@tonic-gate 	uberdata_t *udp = curthread->ul_uberdata;
917c478bd9Sstevel@tonic-gate 	atfork_t *atfork_q;
927c478bd9Sstevel@tonic-gate 	atfork_t *atfp;
937c478bd9Sstevel@tonic-gate 
942e145884Sraf 	ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread));
957c478bd9Sstevel@tonic-gate 	if ((atfork_q = udp->atforklist) != NULL) {
967c478bd9Sstevel@tonic-gate 		atfp = atfork_q = atfork_q->back;
977c478bd9Sstevel@tonic-gate 		do {
987c478bd9Sstevel@tonic-gate 			if (atfp->prepare)
997c478bd9Sstevel@tonic-gate 				(*atfp->prepare)();
1007c478bd9Sstevel@tonic-gate 		} while ((atfp = atfp->back) != atfork_q);
1017c478bd9Sstevel@tonic-gate 	}
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate  * _postfork_parent_handler() is called by fork1() after it retuns as parent.
1067c478bd9Sstevel@tonic-gate  * It executes the user installed "parent" routines in FIFO order (POSIX).
1077c478bd9Sstevel@tonic-gate  */
1087c478bd9Sstevel@tonic-gate void
_postfork_parent_handler(void)1097c478bd9Sstevel@tonic-gate _postfork_parent_handler(void)
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate 	uberdata_t *udp = curthread->ul_uberdata;
1127c478bd9Sstevel@tonic-gate 	atfork_t *atfork_q;
1137c478bd9Sstevel@tonic-gate 	atfork_t *atfp;
1147c478bd9Sstevel@tonic-gate 
1152e145884Sraf 	ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread));
1167c478bd9Sstevel@tonic-gate 	if ((atfork_q = udp->atforklist) != NULL) {
1177c478bd9Sstevel@tonic-gate 		atfp = atfork_q;
1187c478bd9Sstevel@tonic-gate 		do {
1197c478bd9Sstevel@tonic-gate 			if (atfp->parent)
1207c478bd9Sstevel@tonic-gate 				(*atfp->parent)();
1217c478bd9Sstevel@tonic-gate 		} while ((atfp = atfp->forw) != atfork_q);
1227c478bd9Sstevel@tonic-gate 	}
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * _postfork_child_handler() is called by fork1() after it returns as child.
1277c478bd9Sstevel@tonic-gate  * It executes the user installed "child" routines in FIFO order (POSIX).
1287c478bd9Sstevel@tonic-gate  */
1297c478bd9Sstevel@tonic-gate void
_postfork_child_handler(void)1307c478bd9Sstevel@tonic-gate _postfork_child_handler(void)
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate 	uberdata_t *udp = curthread->ul_uberdata;
1337c478bd9Sstevel@tonic-gate 	atfork_t *atfork_q;
1347c478bd9Sstevel@tonic-gate 	atfork_t *atfp;
1357c478bd9Sstevel@tonic-gate 
1362e145884Sraf 	ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread));
1377c478bd9Sstevel@tonic-gate 	if ((atfork_q = udp->atforklist) != NULL) {
1387c478bd9Sstevel@tonic-gate 		atfp = atfork_q;
1397c478bd9Sstevel@tonic-gate 		do {
1407c478bd9Sstevel@tonic-gate 			if (atfp->child)
1417c478bd9Sstevel@tonic-gate 				(*atfp->child)();
1427c478bd9Sstevel@tonic-gate 		} while ((atfp = atfp->forw) != atfork_q);
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate }
145