Home | History | Annotate | Download | only in gen
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include "thr_uberdata.h"
     30 #include "mtlib.h"
     31 
     32 /*
     33  * fork handlers are run in LIFO order.
     34  * The libc fork handler is expected to be the first handler installed,
     35  * hence would be the last fork handler run in preparation for fork1().
     36  * It is essential that this be so, for other libraries depend on libc
     37  * and may grab their own locks before calling into libc.  By special
     38  * arrangement, the loader runs libc's init section (libc_init()) first.
     39  */
     40 
     41 /*
     42  * pthread_atfork(): installs handlers to be called during fork1().
     43  * There is no POSIX API that provides for deletion of atfork handlers.
     44  * Collaboration between the loader and libc ensures that atfork
     45  * handlers installed by a library are deleted when that library
     46  * is unloaded (see _preexec_atfork_unload() in atexit.c).
     47  */
     48 int
     49 pthread_atfork(void (*prepare)(void),
     50 	void (*parent)(void), void (*child)(void))
     51 {
     52 	ulwp_t *self = curthread;
     53 	uberdata_t *udp = self->ul_uberdata;
     54 	atfork_t *atfp;
     55 	atfork_t *head;
     56 	int error = 0;
     57 
     58 	(void) mutex_lock(&udp->atfork_lock);
     59 	if (self->ul_fork) {
     60 		/*
     61 		 * Cannot call pthread_atfork() from a fork handler.
     62 		 */
     63 		error = EDEADLK;
     64 	} else if ((atfp = lmalloc(sizeof (atfork_t))) == NULL) {
     65 		error = ENOMEM;
     66 	} else {
     67 		atfp->prepare = prepare;
     68 		atfp->parent = parent;
     69 		atfp->child = child;
     70 		if ((head = udp->atforklist) == NULL) {
     71 			udp->atforklist = atfp;
     72 			atfp->forw = atfp->back = atfp;
     73 		} else {
     74 			head->back->forw = atfp;
     75 			atfp->forw = head;
     76 			atfp->back = head->back;
     77 			head->back = atfp;
     78 		}
     79 	}
     80 
     81 	(void) mutex_unlock(&udp->atfork_lock);
     82 	return (error);
     83 }
     84 
     85 /*
     86  * _prefork_handler() is called by fork1() before it starts processing.
     87  * It executes the user installed "prepare" routines in LIFO order (POSIX)
     88  */
     89 void
     90 _prefork_handler(void)
     91 {
     92 	uberdata_t *udp = curthread->ul_uberdata;
     93 	atfork_t *atfork_q;
     94 	atfork_t *atfp;
     95 
     96 	ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread));
     97 	if ((atfork_q = udp->atforklist) != NULL) {
     98 		atfp = atfork_q = atfork_q->back;
     99 		do {
    100 			if (atfp->prepare)
    101 				(*atfp->prepare)();
    102 		} while ((atfp = atfp->back) != atfork_q);
    103 	}
    104 }
    105 
    106 /*
    107  * _postfork_parent_handler() is called by fork1() after it retuns as parent.
    108  * It executes the user installed "parent" routines in FIFO order (POSIX).
    109  */
    110 void
    111 _postfork_parent_handler(void)
    112 {
    113 	uberdata_t *udp = curthread->ul_uberdata;
    114 	atfork_t *atfork_q;
    115 	atfork_t *atfp;
    116 
    117 	ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread));
    118 	if ((atfork_q = udp->atforklist) != NULL) {
    119 		atfp = atfork_q;
    120 		do {
    121 			if (atfp->parent)
    122 				(*atfp->parent)();
    123 		} while ((atfp = atfp->forw) != atfork_q);
    124 	}
    125 }
    126 
    127 /*
    128  * _postfork_child_handler() is called by fork1() after it returns as child.
    129  * It executes the user installed "child" routines in FIFO order (POSIX).
    130  */
    131 void
    132 _postfork_child_handler(void)
    133 {
    134 	uberdata_t *udp = curthread->ul_uberdata;
    135 	atfork_t *atfork_q;
    136 	atfork_t *atfp;
    137 
    138 	ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread));
    139 	if ((atfork_q = udp->atforklist) != NULL) {
    140 		atfp = atfork_q;
    141 		do {
    142 			if (atfp->child)
    143 				(*atfp->child)();
    144 		} while ((atfp = atfp->forw) != atfork_q);
    145 	}
    146 }
    147