xref: /onnv-gate/usr/src/lib/libc/port/gen/atfork.c (revision 6812:febeba71273d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54843Sraf  * Common Development and Distribution License (the "License").
64843Sraf  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
214843Sraf 
220Sstevel@tonic-gate /*
236515Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include "thr_uberdata.h"
300Sstevel@tonic-gate #include "mtlib.h"
310Sstevel@tonic-gate 
320Sstevel@tonic-gate /*
330Sstevel@tonic-gate  * fork handlers are run in LIFO order.
340Sstevel@tonic-gate  * The libc fork handler is expected to be the first handler installed,
350Sstevel@tonic-gate  * hence would be the last fork handler run in preparation for fork1().
360Sstevel@tonic-gate  * It is essential that this be so, for other libraries depend on libc
370Sstevel@tonic-gate  * and may grab their own locks before calling into libc.  By special
380Sstevel@tonic-gate  * arrangement, the loader runs libc's init section (libc_init()) first.
390Sstevel@tonic-gate  */
400Sstevel@tonic-gate 
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate  * pthread_atfork(): installs handlers to be called during fork1().
430Sstevel@tonic-gate  * There is no POSIX API that provides for deletion of atfork handlers.
440Sstevel@tonic-gate  * Collaboration between the loader and libc ensures that atfork
450Sstevel@tonic-gate  * handlers installed by a library are deleted when that library
460Sstevel@tonic-gate  * is unloaded (see _preexec_atfork_unload() in atexit.c).
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate int
pthread_atfork(void (* prepare)(void),void (* parent)(void),void (* child)(void))49*6812Sraf pthread_atfork(void (*prepare)(void),
500Sstevel@tonic-gate 	void (*parent)(void), void (*child)(void))
510Sstevel@tonic-gate {
520Sstevel@tonic-gate 	ulwp_t *self = curthread;
530Sstevel@tonic-gate 	uberdata_t *udp = self->ul_uberdata;
540Sstevel@tonic-gate 	atfork_t *atfp;
550Sstevel@tonic-gate 	atfork_t *head;
564843Sraf 	int error = 0;
570Sstevel@tonic-gate 
586515Sraf 	(void) mutex_lock(&udp->atfork_lock);
594843Sraf 	if (self->ul_fork) {
600Sstevel@tonic-gate 		/*
610Sstevel@tonic-gate 		 * Cannot call pthread_atfork() from a fork handler.
620Sstevel@tonic-gate 		 */
634843Sraf 		error = EDEADLK;
644843Sraf 	} else if ((atfp = lmalloc(sizeof (atfork_t))) == NULL) {
654843Sraf 		error = ENOMEM;
664843Sraf 	} else {
674843Sraf 		atfp->prepare = prepare;
684843Sraf 		atfp->parent = parent;
694843Sraf 		atfp->child = child;
704843Sraf 		if ((head = udp->atforklist) == NULL) {
714843Sraf 			udp->atforklist = atfp;
724843Sraf 			atfp->forw = atfp->back = atfp;
734843Sraf 		} else {
744843Sraf 			head->back->forw = atfp;
754843Sraf 			atfp->forw = head;
764843Sraf 			atfp->back = head->back;
774843Sraf 			head->back = atfp;
784843Sraf 		}
790Sstevel@tonic-gate 	}
804843Sraf 
816515Sraf 	(void) mutex_unlock(&udp->atfork_lock);
824843Sraf 	return (error);
830Sstevel@tonic-gate }
840Sstevel@tonic-gate 
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate  * _prefork_handler() is called by fork1() before it starts processing.
870Sstevel@tonic-gate  * It executes the user installed "prepare" routines in LIFO order (POSIX)
880Sstevel@tonic-gate  */
890Sstevel@tonic-gate void
_prefork_handler(void)900Sstevel@tonic-gate _prefork_handler(void)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate 	uberdata_t *udp = curthread->ul_uberdata;
930Sstevel@tonic-gate 	atfork_t *atfork_q;
940Sstevel@tonic-gate 	atfork_t *atfp;
950Sstevel@tonic-gate 
964843Sraf 	ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread));
970Sstevel@tonic-gate 	if ((atfork_q = udp->atforklist) != NULL) {
980Sstevel@tonic-gate 		atfp = atfork_q = atfork_q->back;
990Sstevel@tonic-gate 		do {
1000Sstevel@tonic-gate 			if (atfp->prepare)
1010Sstevel@tonic-gate 				(*atfp->prepare)();
1020Sstevel@tonic-gate 		} while ((atfp = atfp->back) != atfork_q);
1030Sstevel@tonic-gate 	}
1040Sstevel@tonic-gate }
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate /*
1070Sstevel@tonic-gate  * _postfork_parent_handler() is called by fork1() after it retuns as parent.
1080Sstevel@tonic-gate  * It executes the user installed "parent" routines in FIFO order (POSIX).
1090Sstevel@tonic-gate  */
1100Sstevel@tonic-gate void
_postfork_parent_handler(void)1110Sstevel@tonic-gate _postfork_parent_handler(void)
1120Sstevel@tonic-gate {
1130Sstevel@tonic-gate 	uberdata_t *udp = curthread->ul_uberdata;
1140Sstevel@tonic-gate 	atfork_t *atfork_q;
1150Sstevel@tonic-gate 	atfork_t *atfp;
1160Sstevel@tonic-gate 
1174843Sraf 	ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread));
1180Sstevel@tonic-gate 	if ((atfork_q = udp->atforklist) != NULL) {
1190Sstevel@tonic-gate 		atfp = atfork_q;
1200Sstevel@tonic-gate 		do {
1210Sstevel@tonic-gate 			if (atfp->parent)
1220Sstevel@tonic-gate 				(*atfp->parent)();
1230Sstevel@tonic-gate 		} while ((atfp = atfp->forw) != atfork_q);
1240Sstevel@tonic-gate 	}
1250Sstevel@tonic-gate }
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate /*
1280Sstevel@tonic-gate  * _postfork_child_handler() is called by fork1() after it returns as child.
1290Sstevel@tonic-gate  * It executes the user installed "child" routines in FIFO order (POSIX).
1300Sstevel@tonic-gate  */
1310Sstevel@tonic-gate void
_postfork_child_handler(void)1320Sstevel@tonic-gate _postfork_child_handler(void)
1330Sstevel@tonic-gate {
1340Sstevel@tonic-gate 	uberdata_t *udp = curthread->ul_uberdata;
1350Sstevel@tonic-gate 	atfork_t *atfork_q;
1360Sstevel@tonic-gate 	atfork_t *atfp;
1370Sstevel@tonic-gate 
1384843Sraf 	ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread));
1390Sstevel@tonic-gate 	if ((atfork_q = udp->atforklist) != NULL) {
1400Sstevel@tonic-gate 		atfp = atfork_q;
1410Sstevel@tonic-gate 		do {
1420Sstevel@tonic-gate 			if (atfp->child)
1430Sstevel@tonic-gate 				(*atfp->child)();
1440Sstevel@tonic-gate 		} while ((atfp = atfp->forw) != atfork_q);
1450Sstevel@tonic-gate 	}
1460Sstevel@tonic-gate }
147