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