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