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
privdoor_data_hold(struct privdoor_data * pdd)104 privdoor_data_hold(struct privdoor_data *pdd)
105 {
106 atomic_inc_32(&pdd->pd_refcnt);
107 }
108
109 static void
privdoor_data_rele(struct privdoor_data * pdd)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
privdoor_destructor(void * data)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 *
door_unref_func(void * arg)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
door_create_cmn(door_server_procedure_t * f,void * cookie,uint_t flags,door_xcreate_server_func_t * crf,door_xcreate_thrsetup_func_t * setupf,void * crcookie,int nthread)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
door_create(door_server_procedure_t * f,void * cookie,uint_t flags)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
door_xcreate(door_server_procedure_t * f,void * cookie,uint_t flags,door_xcreate_server_func_t * crf,door_xcreate_thrsetup_func_t * setupf,void * crcookie,int nthread)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
door_ucred(ucred_t ** uc)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
door_cred(door_cred_t * dc)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
door_unbind(void)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
door_return(char * data_ptr,size_t data_size,door_desc_t * desc_ptr,uint_t num_desc)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 *
door_xcreate_startf(void * arg)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
door_xcreate_n(door_info_t * dip,struct privdoor_data * pdd,int n)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
door_depletion_cb(door_info_t * dip)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 *
door_server_create(door_server_func_t * create_func)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 *
door_create_func(void * arg)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
door_create_server(door_info_t * dip)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