Home | History | Annotate | Download | only in threads
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include "lint.h"
     28 #include "thr_uberdata.h"
     29 #include "libc.h"
     30 
     31 #include <alloca.h>
     32 #include <unistd.h>
     33 #include <thread.h>
     34 #include <pthread.h>
     35 #include <stdio.h>
     36 #include <errno.h>
     37 #include <door.h>
     38 #include <signal.h>
     39 #include <ucred.h>
     40 #include <strings.h>
     41 #include <ucontext.h>
     42 #include <sys/ucred.h>
     43 #include <atomic.h>
     44 
     45 static door_server_func_t door_create_server;
     46 
     47 /*
     48  * Global state -- the non-statics are accessed from the __door_return()
     49  * syscall wrapper.
     50  */
     51 static mutex_t		door_state_lock = DEFAULTMUTEX;
     52 door_server_func_t	*door_server_func = door_create_server;
     53 pid_t			door_create_pid = 0;
     54 static pid_t		door_create_first_pid = 0;
     55 static pid_t		door_create_unref_pid = 0;
     56 
     57 /*
     58  * The raw system call interfaces
     59  */
     60 extern int __door_create(void (*)(void *, char *, size_t, door_desc_t *,
     61     uint_t), void *, uint_t);
     62 extern int __door_return(caddr_t, size_t, door_return_desc_t *, caddr_t,
     63     size_t);
     64 extern int __door_ucred(ucred_t *);
     65 extern int __door_unref(void);
     66 extern int __door_unbind(void);
     67 
     68 /*
     69  * Key for per-door data for doors created with door_xcreate.
     70  */
     71 static pthread_key_t privdoor_key = PTHREAD_ONCE_KEY_NP;
     72 
     73 /*
     74  * Each door_xcreate'd door has a struct privdoor_data allocated for it,
     75  * and each of the initial pool of service threads for the door
     76  * has TSD for the privdoor_key set to point to this structure.
     77  * When a thread in door_return decides it is time to perform a
     78  * thread depletion callback we can retrieve this door information
     79  * via a TSD lookup on the privdoor key.
     80  */
     81 struct privdoor_data {
     82 	int pd_dfd;
     83 	door_id_t pd_uniqid;
     84 	volatile uint32_t pd_refcnt;
     85 	door_xcreate_server_func_t *pd_crf;
     86 	void *pd_crcookie;
     87 	door_xcreate_thrsetup_func_t *pd_setupf;
     88 };
     89 
     90 static int door_xcreate_n(door_info_t *, struct privdoor_data *, int);
     91 
     92 /*
     93  * door_create_cmn holds the privdoor data before kicking off server
     94  * thread creation, all of which must succeed; if they don't then
     95  * they return leaving the refcnt unchanged overall, and door_create_cmn
     96  * releases its hold after revoking the door and we're done.  Otherwise
     97  * all n threads created add one each to the refcnt, and door_create_cmn
     98  * drops its hold.  If and when a server thread exits the key destructor
     99  * function will be called, and we use that to decrement the reference
    100  * count.  We also decrement the reference count on door_unbind().
    101  * If ever we get the reference count to 0 then we will free that data.
    102  */
    103 static void
    104 privdoor_data_hold(struct privdoor_data *pdd)
    105 {
    106 	atomic_inc_32(&pdd->pd_refcnt);
    107 }
    108 
    109 static void
    110 privdoor_data_rele(struct privdoor_data *pdd)
    111 {
    112 	if (atomic_dec_32_nv(&pdd->pd_refcnt) == 0)
    113 		free(pdd);
    114 }
    115 
    116 void
    117 privdoor_destructor(void *data)
    118 {
    119 	privdoor_data_rele((struct privdoor_data *)data);
    120 }
    121 
    122 /*
    123  * We park the ourselves in the kernel to serve as the "caller" for
    124  * unreferenced upcalls for this process.  If the call returns with
    125  * EINTR (e.g., someone did a forkall), we repeat as long as we're still
    126  * in the parent.  If the child creates an unref door it will create
    127  * a new thread.
    128  */
    129 static void *
    130 door_unref_func(void *arg)
    131 {
    132 	pid_t mypid = (pid_t)(uintptr_t)arg;
    133 
    134 	sigset_t fillset;
    135 
    136 	/* mask signals before diving into the kernel */
    137 	(void) sigfillset(&fillset);
    138 	(void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
    139 
    140 	while (getpid() == mypid && __door_unref() && errno == EINTR)
    141 		continue;
    142 
    143 	return (NULL);
    144 }
    145 
    146 static int
    147 door_create_cmn(door_server_procedure_t *f, void *cookie, uint_t flags,
    148     door_xcreate_server_func_t *crf, door_xcreate_thrsetup_func_t *setupf,
    149     void *crcookie, int nthread)
    150 {
    151 	int d;
    152 
    153 	int is_private = (flags & DOOR_PRIVATE);
    154 	int is_unref = (flags & (DOOR_UNREF | DOOR_UNREF_MULTI));
    155 	int do_create_first = 0;
    156 	int do_create_unref = 0;
    157 
    158 	ulwp_t *self = curthread;
    159 
    160 	pid_t mypid;
    161 
    162 	if (self->ul_vfork) {
    163 		errno = ENOTSUP;
    164 		return (-1);
    165 	}
    166 
    167 	if (crf)
    168 		flags |= DOOR_PRIVCREATE;
    169 
    170 	/*
    171 	 * Doors are associated with the processes which created them.  In
    172 	 * the face of forkall(), this gets quite complicated.  To simplify
    173 	 * it somewhat, we include the call to __door_create() in a critical
    174 	 * section, and figure out what additional actions to take while
    175 	 * still in the critical section.
    176 	 */
    177 	enter_critical(self);
    178 	if ((d = __door_create(f, cookie, flags)) < 0) {
    179 		exit_critical(self);
    180 		return (-1);	/* errno is set */
    181 	}
    182 	mypid = getpid();
    183 	if (mypid != door_create_pid ||
    184 	    (!is_private && mypid != door_create_first_pid) ||
    185 	    (is_unref && mypid != door_create_unref_pid)) {
    186 
    187 		lmutex_lock(&door_state_lock);
    188 		door_create_pid = mypid;
    189 
    190 		if (!is_private && mypid != door_create_first_pid) {
    191 			do_create_first = 1;
    192 			door_create_first_pid = mypid;
    193 		}
    194 		if (is_unref && mypid != door_create_unref_pid) {
    195 			do_create_unref = 1;
    196 			door_create_unref_pid = mypid;
    197 		}
    198 		lmutex_unlock(&door_state_lock);
    199 	}
    200 	exit_critical(self);
    201 
    202 	if (do_create_unref) {
    203 		/*
    204 		 * Create an unref thread the first time we create an
    205 		 * unref door for this process.  Create it as a daemon
    206 		 * thread, so that it doesn't interfere with normal exit
    207 		 * processing.
    208 		 */
    209 		(void) thr_create(NULL, 0, door_unref_func,
    210 		    (void *)(uintptr_t)mypid, THR_DAEMON, NULL);
    211 	}
    212 
    213 	if (is_private) {
    214 		door_info_t di;
    215 
    216 		/*
    217 		 * Create the first thread(s) for this private door.
    218 		 */
    219 		if (__door_info(d, &di) < 0)
    220 			return (-1);	/* errno is set */
    221 
    222 		/*
    223 		 * This key must be available for lookup for all private
    224 		 * door threads, whether associated with a door created via
    225 		 * door_create or door_xcreate.
    226 		 */
    227 		(void) pthread_key_create_once_np(&privdoor_key,
    228 		    privdoor_destructor);
    229 
    230 		if (crf == NULL) {
    231 			(*door_server_func)(&di);
    232 		} else {
    233 			struct privdoor_data *pdd = malloc(sizeof (*pdd));
    234 
    235 			if (pdd == NULL) {
    236 				(void) door_revoke(d);
    237 				errno = ENOMEM;
    238 				return (-1);
    239 			}
    240 
    241 			pdd->pd_dfd = d;
    242 			pdd->pd_uniqid = di.di_uniquifier;
    243 			pdd->pd_refcnt = 1; /* prevent free during xcreate_n */
    244 			pdd->pd_crf = crf;
    245 			pdd->pd_crcookie = crcookie;
    246 			pdd->pd_setupf = setupf;
    247 
    248 			if (!door_xcreate_n(&di, pdd, nthread)) {
    249 				int errnocp = errno;
    250 
    251 				(void) door_revoke(d);
    252 				privdoor_data_rele(pdd);
    253 				errno = errnocp;
    254 				return (-1);
    255 			} else {
    256 				privdoor_data_rele(pdd);
    257 			}
    258 		}
    259 	} else if (do_create_first) {
    260 		/* First non-private door created in the process */
    261 		(*door_server_func)(NULL);
    262 	}
    263 
    264 	return (d);
    265 }
    266 
    267 int
    268 door_create(door_server_procedure_t *f, void *cookie, uint_t flags)
    269 {
    270 	if (flags & (DOOR_NO_DEPLETION_CB | DOOR_PRIVCREATE)) {
    271 		errno = EINVAL;
    272 		return (-1);
    273 	}
    274 
    275 	return (door_create_cmn(f, cookie, flags, NULL, NULL, NULL, 1));
    276 }
    277 
    278 int
    279 door_xcreate(door_server_procedure_t *f, void *cookie, uint_t flags,
    280     door_xcreate_server_func_t *crf, door_xcreate_thrsetup_func_t *setupf,
    281     void *crcookie, int nthread)
    282 {
    283 	if (flags & DOOR_PRIVCREATE || nthread < 1 || crf == NULL) {
    284 		errno = EINVAL;
    285 		return (-1);
    286 	}
    287 
    288 	return (door_create_cmn(f, cookie, flags | DOOR_PRIVATE,
    289 	    crf, setupf, crcookie, nthread));
    290 }
    291 
    292 int
    293 door_ucred(ucred_t **uc)
    294 {
    295 	ucred_t *ucp = *uc;
    296 
    297 	if (ucp == NULL) {
    298 		ucp = _ucred_alloc();
    299 		if (ucp == NULL)
    300 			return (-1);
    301 	}
    302 
    303 	if (__door_ucred(ucp) != 0) {
    304 		if (*uc == NULL)
    305 			ucred_free(ucp);
    306 		return (-1);
    307 	}
    308 
    309 	*uc = ucp;
    310 
    311 	return (0);
    312 }
    313 
    314 int
    315 door_cred(door_cred_t *dc)
    316 {
    317 	/*
    318 	 * Ucred size is small and alloca is fast
    319 	 * and cannot fail.
    320 	 */
    321 	ucred_t *ucp = alloca(ucred_size());
    322 	int ret;
    323 
    324 	if ((ret = __door_ucred(ucp)) == 0) {
    325 		dc->dc_euid = ucred_geteuid(ucp);
    326 		dc->dc_ruid = ucred_getruid(ucp);
    327 		dc->dc_egid = ucred_getegid(ucp);
    328 		dc->dc_rgid = ucred_getrgid(ucp);
    329 		dc->dc_pid = ucred_getpid(ucp);
    330 	}
    331 	return (ret);
    332 }
    333 
    334 int
    335 door_unbind(void)
    336 {
    337 	struct privdoor_data *pdd;
    338 	int rv = __door_unbind();
    339 
    340 	/*
    341 	 * If we were indeed bound to the door then check to see whether
    342 	 * we are part of a door_xcreate'd door by checking for our TSD.
    343 	 * If so, then clear the TSD for this key to avoid destructor
    344 	 * callback on future thread exit, and release the private door data.
    345 	 */
    346 	if (rv == 0 && (pdd = pthread_getspecific(privdoor_key)) != NULL) {
    347 		(void) pthread_setspecific(privdoor_key, NULL);
    348 		privdoor_data_rele(pdd);
    349 	}
    350 
    351 	return (rv);
    352 }
    353 
    354 int
    355 door_return(char *data_ptr, size_t data_size,
    356     door_desc_t *desc_ptr, uint_t num_desc)
    357 {
    358 	caddr_t sp;
    359 	size_t ssize;
    360 	size_t reserve;
    361 	ulwp_t *self = curthread;
    362 
    363 	{
    364 		stack_t s;
    365 		if (thr_stksegment(&s) != 0) {
    366 			errno = EINVAL;
    367 			return (-1);
    368 		}
    369 		sp = s.ss_sp;
    370 		ssize = s.ss_size;
    371 	}
    372 
    373 	if (!self->ul_door_noreserve) {
    374 		/*
    375 		 * When we return from the kernel, we must have enough stack
    376 		 * available to handle the request.  Since the creator of
    377 		 * the thread has control over its stack size, and larger
    378 		 * stacks generally indicate bigger request queues, we
    379 		 * use the heuristic of reserving 1/32nd of the stack size
    380 		 * (up to the default stack size), with a minimum of 1/8th
    381 		 * of MINSTACK.  Currently, this translates to:
    382 		 *
    383 		 *			_ILP32		_LP64
    384 		 *	min resv	 512 bytes	1024 bytes
    385 		 *	max resv	 32k bytes	 64k bytes
    386 		 *
    387 		 * This reservation can be disabled by setting
    388 		 *	_THREAD_DOOR_NORESERVE=1
    389 		 * in the environment, but shouldn't be.
    390 		 */
    391 
    392 #define	STACK_FRACTION		32
    393 #define	MINSTACK_FRACTION	8
    394 
    395 		if (ssize < (MINSTACK * (STACK_FRACTION/MINSTACK_FRACTION)))
    396 			reserve = MINSTACK / MINSTACK_FRACTION;
    397 		else if (ssize < DEFAULTSTACK)
    398 			reserve = ssize / STACK_FRACTION;
    399 		else
    400 			reserve = DEFAULTSTACK / STACK_FRACTION;
    401 
    402 #undef STACK_FRACTION
    403 #undef MINSTACK_FRACTION
    404 
    405 		if (ssize > reserve)
    406 			ssize -= reserve;
    407 		else
    408 			ssize = 0;
    409 	}
    410 
    411 	/*
    412 	 * Historically, the __door_return() syscall wrapper subtracted
    413 	 * some "slop" from the stack pointer before trapping into the
    414 	 * kernel.  We now do this here, so that ssize can be adjusted
    415 	 * correctly.  Eventually, this should be removed, since it is
    416 	 * unnecessary.  (note that TNF on x86 currently relies upon this
    417 	 * idiocy)
    418 	 */
    419 #if defined(__sparc)
    420 	reserve = SA(MINFRAME);
    421 #elif defined(__x86)
    422 	reserve = SA(512);
    423 #else
    424 #error need to define stack base reserve
    425 #endif
    426 
    427 #ifdef _STACK_GROWS_DOWNWARD
    428 	sp -= reserve;
    429 #else
    430 #error stack does not grow downwards, routine needs update
    431 #endif
    432 
    433 	if (ssize > reserve)
    434 		ssize -= reserve;
    435 	else
    436 		ssize = 0;
    437 
    438 	/*
    439 	 * Normally, the above will leave plenty of space in sp for a
    440 	 * request.  Just in case some bozo overrides thr_stksegment() to
    441 	 * return an uncommonly small stack size, we turn off stack size
    442 	 * checking if there is less than 1k remaining.
    443 	 */
    444 #define	MIN_DOOR_STACK	1024
    445 	if (ssize < MIN_DOOR_STACK)
    446 		ssize = 0;
    447 
    448 #undef MIN_DOOR_STACK
    449 
    450 	/*
    451 	 * We have to wrap the desc_* arguments for the syscall.  If there are
    452 	 * no descriptors being returned, we can skip the wrapping.
    453 	 */
    454 	if (num_desc != 0) {
    455 		door_return_desc_t d;
    456 
    457 		d.desc_ptr = desc_ptr;
    458 		d.desc_num = num_desc;
    459 		return (__door_return(data_ptr, data_size, &d, sp, ssize));
    460 	}
    461 	return (__door_return(data_ptr, data_size, NULL, sp, ssize));
    462 }
    463 
    464 /*
    465  * To start and synchronize a number of door service threads at once
    466  * we use a struct door_xsync_shared shared by all threads, and
    467  * a struct door_xsync for each thread.  While each thread
    468  * has its own startup state, all such state are protected by the same
    469  * shared lock.  This could cause a little contention but it is a one-off
    470  * cost at door creation.
    471  */
    472 enum door_xsync_state {
    473 	DOOR_XSYNC_CREATEWAIT = 0x1c8c8c80,	/* awaits creation handshake */
    474 	DOOR_XSYNC_ABORT,		/* aborting door_xcreate */
    475 	DOOR_XSYNC_ABORTED,		/* thread heeded abort request */
    476 	DOOR_XSYNC_MAXCONCUR,		/* create func decided no more */
    477 	DOOR_XSYNC_CREATEFAIL,		/* thr_create/pthread_create failure */
    478 	DOOR_XSYNC_SETSPEC_FAIL,	/* setspecific failed */
    479 	DOOR_XSYNC_BINDFAIL,		/* door_bind failed */
    480 	DOOR_XSYNC_BOUND,		/* door_bind succeeded */
    481 	DOOR_XSYNC_ENTER_SERVICE	/* Go on to door_return */
    482 };
    483 
    484 /* These stats are incremented non-atomically - indicative only */
    485 uint64_t door_xcreate_n_stats[DOOR_XSYNC_ENTER_SERVICE -
    486     DOOR_XSYNC_CREATEWAIT + 1];
    487 
    488 struct door_xsync_shared {
    489 	pthread_mutex_t lock;
    490 	pthread_cond_t cv_m2s;
    491 	pthread_cond_t cv_s2m;
    492 	struct privdoor_data *pdd;
    493 	volatile uint32_t waiting;
    494 };
    495 
    496 struct door_xsync {
    497 	volatile enum door_xsync_state state;
    498 	struct door_xsync_shared *sharedp;
    499 };
    500 
    501 /*
    502  * Thread start function that xcreated private doors must use in
    503  * thr_create or pthread_create.  They must also use the argument we
    504  * provide.  We:
    505  *
    506  *	o call a thread setup function if supplied, or apply sensible defaults
    507  *	o bind the newly-created thread to the door it will service
    508  *	o synchronize with door_xcreate to indicate that we have successfully
    509  *	  bound to the door;  door_xcreate will not return until all
    510  *	  requested threads have at least bound
    511  *	o enter service with door_return quoting magic sentinel args
    512  */
    513 void *
    514 door_xcreate_startf(void *arg)
    515 {
    516 	struct door_xsync *xsp = (struct door_xsync *)arg;
    517 	struct door_xsync_shared *xssp = xsp->sharedp;
    518 	struct privdoor_data *pdd = xssp->pdd;
    519 	enum door_xsync_state next_state;
    520 
    521 	privdoor_data_hold(pdd);
    522 	if (pthread_setspecific(privdoor_key, (const void *)pdd) != 0) {
    523 		next_state = DOOR_XSYNC_SETSPEC_FAIL;
    524 		privdoor_data_rele(pdd);
    525 		goto handshake;
    526 	}
    527 
    528 	if (pdd->pd_setupf != NULL) {
    529 		(pdd->pd_setupf)(pdd->pd_crcookie);
    530 	} else {
    531 		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
    532 		(void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    533 	}
    534 
    535 	if (door_bind(pdd->pd_dfd) == 0)
    536 		next_state = DOOR_XSYNC_BOUND;
    537 	else
    538 		next_state = DOOR_XSYNC_BINDFAIL;
    539 
    540 handshake:
    541 	(void) pthread_mutex_lock(&xssp->lock);
    542 
    543 	ASSERT(xsp->state == DOOR_XSYNC_CREATEWAIT ||
    544 	    xsp->state == DOOR_XSYNC_ABORT);
    545 
    546 	if (xsp->state == DOOR_XSYNC_ABORT)
    547 		next_state = DOOR_XSYNC_ABORTED;
    548 
    549 	xsp->state = next_state;
    550 
    551 	if (--xssp->waiting == 0)
    552 		(void) pthread_cond_signal(&xssp->cv_s2m);
    553 
    554 	if (next_state != DOOR_XSYNC_BOUND) {
    555 		(void) pthread_mutex_unlock(&xssp->lock);
    556 		return (NULL);	/* thread exits, key destructor called */
    557 	}
    558 
    559 	while (xsp->state == DOOR_XSYNC_BOUND)
    560 		(void) pthread_cond_wait(&xssp->cv_m2s, &xssp->lock);
    561 
    562 	next_state = xsp->state;
    563 	ASSERT(next_state == DOOR_XSYNC_ENTER_SERVICE ||
    564 	    next_state == DOOR_XSYNC_ABORT);
    565 
    566 	if (--xssp->waiting == 0)
    567 		(void) pthread_cond_signal(&xssp->cv_s2m);
    568 
    569 	(void) pthread_mutex_unlock(&xssp->lock); /* xssp/xsp can be freed */
    570 
    571 	if (next_state == DOOR_XSYNC_ABORT)
    572 		return (NULL);	/* thread exits, key destructor called */
    573 
    574 	(void) door_return(NULL, 0, NULL, 0);
    575 	return (NULL);
    576 }
    577 
    578 static int
    579 door_xcreate_n(door_info_t *dip, struct privdoor_data *pdd, int n)
    580 {
    581 	struct door_xsync_shared *xssp;
    582 	struct door_xsync *xsp;
    583 	int i, failidx = -1;
    584 	int isdepcb = 0;
    585 	int failerrno;
    586 	int bound = 0;
    587 #ifdef _STACK_GROWS_DOWNWARD
    588 	int stkdir = -1;
    589 #else
    590 	int stkdir = 1;
    591 #endif
    592 	int rv = 0;
    593 
    594 	/*
    595 	 * If we're called during door creation then we have the
    596 	 * privdoor_data.  If we're called as part of a depletion callback
    597 	 * then the current thread has the privdoor_data as TSD.
    598 	 */
    599 	if (pdd == NULL) {
    600 		isdepcb = 1;
    601 		if ((pdd = pthread_getspecific(privdoor_key)) == NULL)
    602 			thr_panic("door_xcreate_n - no privdoor_data "
    603 			    "on existing server thread");
    604 	}
    605 
    606 	/*
    607 	 * Allocate on our stack.  We'll pass pointers to this to the
    608 	 * newly-created threads, therefore this function must not return until
    609 	 * we have synced with server threads that are created.
    610 	 * We do not limit the number of threads so begin by checking
    611 	 * that we have space on the stack for this.
    612 	 */
    613 	{
    614 		size_t sz = sizeof (*xssp) + n * sizeof (*xsp) + 32;
    615 		char dummy;
    616 
    617 		if (!stack_inbounds(&dummy + stkdir * sz)) {
    618 			errno = E2BIG;
    619 			return (0);
    620 		}
    621 	}
    622 
    623 	if ((xssp = alloca(sizeof (*xssp))) == NULL ||
    624 	    (xsp = alloca(n * sizeof (*xsp))) == NULL) {
    625 		errno = E2BIG;
    626 		return (0);
    627 	}
    628 
    629 	(void) pthread_mutex_init(&xssp->lock, NULL);
    630 	(void) pthread_cond_init(&xssp->cv_m2s, NULL);
    631 	(void) pthread_cond_init(&xssp->cv_s2m, NULL);
    632 	xssp->pdd = pdd;
    633 	xssp->waiting = 0;
    634 
    635 	(void) pthread_mutex_lock(&xssp->lock);
    636 
    637 	for (i = 0; failidx == -1 && i < n; i++) {
    638 		xsp[i].sharedp = xssp;
    639 		membar_producer();	/* xssp and xsp[i] for new thread */
    640 
    641 		switch ((pdd->pd_crf)(dip, door_xcreate_startf,
    642 		    (void *)&xsp[i], pdd->pd_crcookie)) {
    643 		case 1:
    644 			/*
    645 			 * Thread successfully created.  Set mailbox
    646 			 * state and increment the number we have to
    647 			 * sync with.
    648 			 */
    649 			xsp[i].state = DOOR_XSYNC_CREATEWAIT;
    650 			xssp->waiting++;
    651 			break;
    652 		case 0:
    653 			/*
    654 			 * Elected to create no further threads.  OK for
    655 			 * a depletion callback, but not during door_xcreate.
    656 			 */
    657 			xsp[i].state = DOOR_XSYNC_MAXCONCUR;
    658 			if (!isdepcb) {
    659 				failidx = i;
    660 				failerrno = EINVAL;
    661 			}
    662 			break;
    663 		case -1:
    664 			/*
    665 			 * Thread creation was attempted but failed.
    666 			 */
    667 			xsp[i].state = DOOR_XSYNC_CREATEFAIL;
    668 			failidx = i;
    669 			failerrno = EPIPE;
    670 			break;
    671 		default:
    672 			/*
    673 			 * The application-supplied function did not return
    674 			 * -1/0/1 - best we can do is panic because anything
    675 			 * else is harder to debug.
    676 			 */
    677 			thr_panic("door server create function illegal return");
    678 			/*NOTREACHED*/
    679 		}
    680 	}
    681 
    682 	/*
    683 	 * On initial creation all must succeed; if not then abort
    684 	 */
    685 	if (!isdepcb && failidx != -1) {
    686 		for (i = 0; i < failidx; i++)
    687 			if (xsp[i].state == DOOR_XSYNC_CREATEWAIT)
    688 				xsp[i].state = DOOR_XSYNC_ABORT;
    689 	}
    690 
    691 	/*
    692 	 * Wait for thread startup handshake to complete for all threads
    693 	 */
    694 	while (xssp->waiting)
    695 		(void) pthread_cond_wait(&xssp->cv_s2m, &xssp->lock);
    696 
    697 	/*
    698 	 * If we are aborting for a failed thread create in door_xcreate
    699 	 * then we're done.
    700 	 */
    701 	if (!isdepcb && failidx != -1) {
    702 		rv = 0;
    703 		goto out;	/* lock held, failerrno is set */
    704 	}
    705 
    706 	/*
    707 	 * Did we all succeed in binding?
    708 	 */
    709 	for (i = 0; i < n; i++) {
    710 		int statidx = xsp[i].state - DOOR_XSYNC_CREATEWAIT;
    711 
    712 		door_xcreate_n_stats[statidx]++;
    713 		if (xsp[i].state == DOOR_XSYNC_BOUND)
    714 			bound++;
    715 	}
    716 
    717 	if (bound == n) {
    718 		rv = 1;
    719 	} else {
    720 		failerrno = EBADF;
    721 		rv = 0;
    722 	}
    723 
    724 	/*
    725 	 * During door_xcreate all must succeed in binding - if not then
    726 	 * we command even those that did bind to abort.  Threads that
    727 	 * did not get as far as binding have already exited.
    728 	 */
    729 	for (i = 0; i < n; i++) {
    730 		if (xsp[i].state == DOOR_XSYNC_BOUND) {
    731 			xsp[i].state = (rv == 1 || isdepcb) ?
    732 			    DOOR_XSYNC_ENTER_SERVICE : DOOR_XSYNC_ABORT;
    733 			xssp->waiting++;
    734 		}
    735 	}
    736 
    737 	(void) pthread_cond_broadcast(&xssp->cv_m2s);
    738 
    739 	while (xssp->waiting)
    740 		(void) pthread_cond_wait(&xssp->cv_s2m, &xssp->lock);
    741 
    742 out:
    743 	(void) pthread_mutex_unlock(&xssp->lock);
    744 	(void) pthread_mutex_destroy(&xssp->lock);
    745 	(void) pthread_cond_destroy(&xssp->cv_m2s);
    746 	(void) pthread_cond_destroy(&xssp->cv_s2m);
    747 
    748 	if (rv == 0)
    749 		errno = failerrno;
    750 
    751 	return (rv);
    752 }
    753 
    754 /*
    755  * Call the server creation function to give it the opportunity to
    756  * create more threads.  Called during a door invocation when we
    757  * return from door_return(NULL,0, NULL, 0) and notice that we're
    758  * running on the last available thread.
    759  */
    760 void
    761 door_depletion_cb(door_info_t *dip)
    762 {
    763 	if (dip == NULL) {
    764 		/*
    765 		 * Non-private doors always use door_server_func.
    766 		 */
    767 		(*door_server_func)(NULL);
    768 		return;
    769 	}
    770 
    771 	if (dip->di_attributes & DOOR_NO_DEPLETION_CB) {
    772 		/*
    773 		 * Private, door_xcreate'd door specified no callbacks.
    774 		 */
    775 		return;
    776 	} else if (!(dip->di_attributes & DOOR_PRIVCREATE)) {
    777 		/*
    778 		 * Private door with standard/legacy creation semantics.
    779 		 */
    780 		dip->di_attributes |= DOOR_DEPLETION_CB;
    781 		(*door_server_func)(dip);
    782 		return;
    783 	} else {
    784 		/*
    785 		 * Private, door_xcreate'd door.
    786 		 */
    787 		dip->di_attributes |= DOOR_DEPLETION_CB;
    788 		(void) door_xcreate_n(dip, NULL, 1);
    789 	}
    790 }
    791 
    792 /*
    793  * Install a new server creation function.  The appointed function
    794  * will receieve depletion callbacks for non-private doors and private
    795  * doors created with door_create(..., DOOR_PRIVATE).
    796  */
    797 door_server_func_t *
    798 door_server_create(door_server_func_t *create_func)
    799 {
    800 	door_server_func_t *prev;
    801 
    802 	lmutex_lock(&door_state_lock);
    803 	prev = door_server_func;
    804 	door_server_func = create_func;
    805 	lmutex_unlock(&door_state_lock);
    806 
    807 	return (prev);
    808 }
    809 
    810 /*
    811  * Thread start function for door_create_server() below.
    812  * Create door server threads with cancellation(5) disabled.
    813  */
    814 static void *
    815 door_create_func(void *arg)
    816 {
    817 	(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
    818 	(void) door_return(NULL, 0, NULL, 0);
    819 
    820 	return (arg);
    821 }
    822 
    823 /*
    824  * The default door_server_func_t.
    825  */
    826 /* ARGSUSED */
    827 static void
    828 door_create_server(door_info_t *dip)
    829 {
    830 	(void) thr_create(NULL, 0, door_create_func, NULL, THR_DETACHED, NULL);
    831 	yield();	/* Gives server thread a chance to run */
    832 }
    833