1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #pragma weak door_create = _door_create
30*7c478bd9Sstevel@tonic-gate #pragma weak door_ucred = _door_ucred
31*7c478bd9Sstevel@tonic-gate #pragma weak door_cred = _door_cred
32*7c478bd9Sstevel@tonic-gate #pragma weak door_return = _door_return
33*7c478bd9Sstevel@tonic-gate #pragma weak door_server_create = _door_server_create
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #include "synonyms.h"
36*7c478bd9Sstevel@tonic-gate #include "thr_uberdata.h"
37*7c478bd9Sstevel@tonic-gate #include "libc.h"
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #include <alloca.h>
40*7c478bd9Sstevel@tonic-gate #include <unistd.h>
41*7c478bd9Sstevel@tonic-gate #include <thread.h>
42*7c478bd9Sstevel@tonic-gate #include <pthread.h>
43*7c478bd9Sstevel@tonic-gate #include <stdio.h>
44*7c478bd9Sstevel@tonic-gate #include <errno.h>
45*7c478bd9Sstevel@tonic-gate #include <door.h>
46*7c478bd9Sstevel@tonic-gate #include <signal.h>
47*7c478bd9Sstevel@tonic-gate #include <ucred.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/ucred.h>
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate static door_server_func_t door_create_server;
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate /*
53*7c478bd9Sstevel@tonic-gate  * Global state -- the non-statics are accessed from the __door_return()
54*7c478bd9Sstevel@tonic-gate  * syscall wrapper.
55*7c478bd9Sstevel@tonic-gate  */
56*7c478bd9Sstevel@tonic-gate static mutex_t		door_state_lock = DEFAULTMUTEX;
57*7c478bd9Sstevel@tonic-gate door_server_func_t	*door_server_func = door_create_server;
58*7c478bd9Sstevel@tonic-gate pid_t			door_create_pid = 0;
59*7c478bd9Sstevel@tonic-gate static pid_t		door_create_first_pid = 0;
60*7c478bd9Sstevel@tonic-gate static pid_t		door_create_unref_pid = 0;
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate /*
63*7c478bd9Sstevel@tonic-gate  * The raw system call interfaces
64*7c478bd9Sstevel@tonic-gate  */
65*7c478bd9Sstevel@tonic-gate extern int __door_create(void (*)(void *, char *, size_t, door_desc_t *,
66*7c478bd9Sstevel@tonic-gate     uint_t), void *, uint_t);
67*7c478bd9Sstevel@tonic-gate extern int __door_return(caddr_t, size_t, door_return_desc_t *, caddr_t,
68*7c478bd9Sstevel@tonic-gate     size_t);
69*7c478bd9Sstevel@tonic-gate extern int __door_ucred(ucred_t *);
70*7c478bd9Sstevel@tonic-gate extern int __door_unref(void);
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate /*
73*7c478bd9Sstevel@tonic-gate  * We park the ourselves in the kernel to serve as the "caller" for
74*7c478bd9Sstevel@tonic-gate  * unreferenced upcalls for this process.  If the call returns with
75*7c478bd9Sstevel@tonic-gate  * EINTR (e.g., someone did a forkall), we repeat as long as we're still
76*7c478bd9Sstevel@tonic-gate  * in the parent.  If the child creates an unref door it will create
77*7c478bd9Sstevel@tonic-gate  * a new thread.
78*7c478bd9Sstevel@tonic-gate  */
79*7c478bd9Sstevel@tonic-gate static void *
80*7c478bd9Sstevel@tonic-gate door_unref_func(void *arg)
81*7c478bd9Sstevel@tonic-gate {
82*7c478bd9Sstevel@tonic-gate 	pid_t mypid = (pid_t)(uintptr_t)arg;
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate 	sigset_t fillset;
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate 	/* mask signals before diving into the kernel */
87*7c478bd9Sstevel@tonic-gate 	(void) sigfillset(&fillset);
88*7c478bd9Sstevel@tonic-gate 	(void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate 	while (getpid() == mypid && __door_unref() && errno == EINTR)
91*7c478bd9Sstevel@tonic-gate 		continue;
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	return (NULL);
94*7c478bd9Sstevel@tonic-gate }
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate int
97*7c478bd9Sstevel@tonic-gate door_create(void (*f)(void *, char *, size_t, door_desc_t *, uint_t),
98*7c478bd9Sstevel@tonic-gate     void *cookie, uint_t flags)
99*7c478bd9Sstevel@tonic-gate {
100*7c478bd9Sstevel@tonic-gate 	int d;
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate 	int is_private = (flags & DOOR_PRIVATE);
103*7c478bd9Sstevel@tonic-gate 	int is_unref = (flags & (DOOR_UNREF | DOOR_UNREF_MULTI));
104*7c478bd9Sstevel@tonic-gate 	int do_create_first = 0;
105*7c478bd9Sstevel@tonic-gate 	int do_create_unref = 0;
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	ulwp_t *self = curthread;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	pid_t mypid;
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate 	if (self->ul_vfork) {
112*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
113*7c478bd9Sstevel@tonic-gate 		return (-1);
114*7c478bd9Sstevel@tonic-gate 	}
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	/*
117*7c478bd9Sstevel@tonic-gate 	 * Doors are associated with the processes which created them.  In
118*7c478bd9Sstevel@tonic-gate 	 * the face of forkall(), this gets quite complicated.  To simplify
119*7c478bd9Sstevel@tonic-gate 	 * it somewhat, we include the call to __door_create() in a critical
120*7c478bd9Sstevel@tonic-gate 	 * section, and figure out what additional actions to take while
121*7c478bd9Sstevel@tonic-gate 	 * still in the critical section.
122*7c478bd9Sstevel@tonic-gate 	 */
123*7c478bd9Sstevel@tonic-gate 	enter_critical(self);
124*7c478bd9Sstevel@tonic-gate 	if ((d = __door_create(f, cookie, flags)) < 0) {
125*7c478bd9Sstevel@tonic-gate 		exit_critical(self);
126*7c478bd9Sstevel@tonic-gate 		return (-1);
127*7c478bd9Sstevel@tonic-gate 	}
128*7c478bd9Sstevel@tonic-gate 	mypid = getpid();
129*7c478bd9Sstevel@tonic-gate 	if (mypid != door_create_pid ||
130*7c478bd9Sstevel@tonic-gate 	    (!is_private && mypid != door_create_first_pid) ||
131*7c478bd9Sstevel@tonic-gate 	    (is_unref && mypid != door_create_unref_pid)) {
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 		lmutex_lock(&door_state_lock);
134*7c478bd9Sstevel@tonic-gate 		door_create_pid = mypid;
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 		if (!is_private && mypid != door_create_first_pid) {
137*7c478bd9Sstevel@tonic-gate 			do_create_first = 1;
138*7c478bd9Sstevel@tonic-gate 			door_create_first_pid = mypid;
139*7c478bd9Sstevel@tonic-gate 		}
140*7c478bd9Sstevel@tonic-gate 		if (is_unref && mypid != door_create_unref_pid) {
141*7c478bd9Sstevel@tonic-gate 			do_create_unref = 1;
142*7c478bd9Sstevel@tonic-gate 			door_create_unref_pid = mypid;
143*7c478bd9Sstevel@tonic-gate 		}
144*7c478bd9Sstevel@tonic-gate 		lmutex_unlock(&door_state_lock);
145*7c478bd9Sstevel@tonic-gate 	}
146*7c478bd9Sstevel@tonic-gate 	exit_critical(self);
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 	if (do_create_unref) {
149*7c478bd9Sstevel@tonic-gate 		/*
150*7c478bd9Sstevel@tonic-gate 		 * Create an unref thread the first time we create an
151*7c478bd9Sstevel@tonic-gate 		 * unref door for this process.  Create it as a daemon
152*7c478bd9Sstevel@tonic-gate 		 * thread, so that it doesn't interfere with normal exit
153*7c478bd9Sstevel@tonic-gate 		 * processing.
154*7c478bd9Sstevel@tonic-gate 		 */
155*7c478bd9Sstevel@tonic-gate 		(void) thr_create(NULL, 0, door_unref_func,
156*7c478bd9Sstevel@tonic-gate 		    (void *)(uintptr_t)mypid, THR_DAEMON, NULL);
157*7c478bd9Sstevel@tonic-gate 	}
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 	/*
160*7c478bd9Sstevel@tonic-gate 	 * If this is the first door created in the process, or the door
161*7c478bd9Sstevel@tonic-gate 	 * has a private pool, we need to kick off the thread pool now.
162*7c478bd9Sstevel@tonic-gate 	 */
163*7c478bd9Sstevel@tonic-gate 	if (do_create_first)
164*7c478bd9Sstevel@tonic-gate 		(*door_server_func)(NULL);
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate 	if (is_private) {
167*7c478bd9Sstevel@tonic-gate 		door_info_t di;
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 		if (__door_info(d, &di) < 0)
170*7c478bd9Sstevel@tonic-gate 			return (-1);
171*7c478bd9Sstevel@tonic-gate 		(*door_server_func)(&di);
172*7c478bd9Sstevel@tonic-gate 	}
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	return (d);
175*7c478bd9Sstevel@tonic-gate }
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate int
178*7c478bd9Sstevel@tonic-gate door_ucred(ucred_t **uc)
179*7c478bd9Sstevel@tonic-gate {
180*7c478bd9Sstevel@tonic-gate 	ucred_t *ucp = *uc;
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	if (ucp == NULL) {
183*7c478bd9Sstevel@tonic-gate 		ucp = _ucred_alloc();
184*7c478bd9Sstevel@tonic-gate 		if (ucp == NULL)
185*7c478bd9Sstevel@tonic-gate 			return (-1);
186*7c478bd9Sstevel@tonic-gate 	}
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 	if (__door_ucred(ucp) != 0) {
189*7c478bd9Sstevel@tonic-gate 		if (*uc == NULL)
190*7c478bd9Sstevel@tonic-gate 			ucred_free(ucp);
191*7c478bd9Sstevel@tonic-gate 		return (-1);
192*7c478bd9Sstevel@tonic-gate 	}
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	*uc = ucp;
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	return (0);
197*7c478bd9Sstevel@tonic-gate }
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate int
200*7c478bd9Sstevel@tonic-gate door_cred(door_cred_t *dc)
201*7c478bd9Sstevel@tonic-gate {
202*7c478bd9Sstevel@tonic-gate 	/*
203*7c478bd9Sstevel@tonic-gate 	 * Ucred size is small and alloca is fast
204*7c478bd9Sstevel@tonic-gate 	 * and cannot fail.
205*7c478bd9Sstevel@tonic-gate 	 */
206*7c478bd9Sstevel@tonic-gate 	ucred_t *ucp = alloca(ucred_size());
207*7c478bd9Sstevel@tonic-gate 	int ret;
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	if ((ret = __door_ucred(ucp)) == 0) {
210*7c478bd9Sstevel@tonic-gate 		dc->dc_euid = ucred_geteuid(ucp);
211*7c478bd9Sstevel@tonic-gate 		dc->dc_ruid = ucred_getruid(ucp);
212*7c478bd9Sstevel@tonic-gate 		dc->dc_egid = ucred_getegid(ucp);
213*7c478bd9Sstevel@tonic-gate 		dc->dc_rgid = ucred_getrgid(ucp);
214*7c478bd9Sstevel@tonic-gate 		dc->dc_pid = ucred_getpid(ucp);
215*7c478bd9Sstevel@tonic-gate 	}
216*7c478bd9Sstevel@tonic-gate 	return (ret);
217*7c478bd9Sstevel@tonic-gate }
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate int
220*7c478bd9Sstevel@tonic-gate door_return(char *data_ptr, size_t data_size,
221*7c478bd9Sstevel@tonic-gate     door_desc_t *desc_ptr, uint_t num_desc)
222*7c478bd9Sstevel@tonic-gate {
223*7c478bd9Sstevel@tonic-gate 	caddr_t sp;
224*7c478bd9Sstevel@tonic-gate 	size_t ssize;
225*7c478bd9Sstevel@tonic-gate 	size_t reserve;
226*7c478bd9Sstevel@tonic-gate 	ulwp_t *self = curthread;
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 	{
229*7c478bd9Sstevel@tonic-gate 		stack_t s;
230*7c478bd9Sstevel@tonic-gate 		if (thr_stksegment(&s) != 0) {
231*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
232*7c478bd9Sstevel@tonic-gate 			return (-1);
233*7c478bd9Sstevel@tonic-gate 		}
234*7c478bd9Sstevel@tonic-gate 		sp = s.ss_sp;
235*7c478bd9Sstevel@tonic-gate 		ssize = s.ss_size;
236*7c478bd9Sstevel@tonic-gate 	}
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	if (!self->ul_door_noreserve) {
239*7c478bd9Sstevel@tonic-gate 		/*
240*7c478bd9Sstevel@tonic-gate 		 * When we return from the kernel, we must have enough stack
241*7c478bd9Sstevel@tonic-gate 		 * available to handle the request.  Since the creator of
242*7c478bd9Sstevel@tonic-gate 		 * the thread has control over its stack size, and larger
243*7c478bd9Sstevel@tonic-gate 		 * stacks generally indicate bigger request queues, we
244*7c478bd9Sstevel@tonic-gate 		 * use the heuristic of reserving 1/32nd of the stack size
245*7c478bd9Sstevel@tonic-gate 		 * (up to the default stack size), with a minimum of 1/8th
246*7c478bd9Sstevel@tonic-gate 		 * of MINSTACK.  Currently, this translates to:
247*7c478bd9Sstevel@tonic-gate 		 *
248*7c478bd9Sstevel@tonic-gate 		 *			_ILP32		_LP64
249*7c478bd9Sstevel@tonic-gate 		 *	min resv	 512 bytes	1024 bytes
250*7c478bd9Sstevel@tonic-gate 		 *	max resv	 32k bytes	 64k bytes
251*7c478bd9Sstevel@tonic-gate 		 *
252*7c478bd9Sstevel@tonic-gate 		 * This reservation can be disabled by setting
253*7c478bd9Sstevel@tonic-gate 		 *	_THREAD_DOOR_NORESERVE=1
254*7c478bd9Sstevel@tonic-gate 		 * in the environment, but shouldn't be.
255*7c478bd9Sstevel@tonic-gate 		 */
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate #define	STACK_FRACTION		32
258*7c478bd9Sstevel@tonic-gate #define	MINSTACK_FRACTION	8
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 		if (ssize < (MINSTACK * (STACK_FRACTION/MINSTACK_FRACTION)))
261*7c478bd9Sstevel@tonic-gate 			reserve = MINSTACK / MINSTACK_FRACTION;
262*7c478bd9Sstevel@tonic-gate 		else if (ssize < DEFAULTSTACK)
263*7c478bd9Sstevel@tonic-gate 			reserve = ssize / STACK_FRACTION;
264*7c478bd9Sstevel@tonic-gate 		else
265*7c478bd9Sstevel@tonic-gate 			reserve = DEFAULTSTACK / STACK_FRACTION;
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate #undef STACK_FRACTION
268*7c478bd9Sstevel@tonic-gate #undef MINSTACK_FRACTION
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 		if (ssize > reserve)
271*7c478bd9Sstevel@tonic-gate 			ssize -= reserve;
272*7c478bd9Sstevel@tonic-gate 		else
273*7c478bd9Sstevel@tonic-gate 			ssize = 0;
274*7c478bd9Sstevel@tonic-gate 	}
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 	/*
277*7c478bd9Sstevel@tonic-gate 	 * Historically, the __door_return() syscall wrapper subtracted
278*7c478bd9Sstevel@tonic-gate 	 * some "slop" from the stack pointer before trapping into the
279*7c478bd9Sstevel@tonic-gate 	 * kernel.  We now do this here, so that ssize can be adjusted
280*7c478bd9Sstevel@tonic-gate 	 * correctly.  Eventually, this should be removed, since it is
281*7c478bd9Sstevel@tonic-gate 	 * unnecessary.  (note that TNF on x86 currently relies upon this
282*7c478bd9Sstevel@tonic-gate 	 * idiocy)
283*7c478bd9Sstevel@tonic-gate 	 */
284*7c478bd9Sstevel@tonic-gate #if defined(__sparc)
285*7c478bd9Sstevel@tonic-gate 	reserve = SA(MINFRAME);
286*7c478bd9Sstevel@tonic-gate #elif defined(__x86)
287*7c478bd9Sstevel@tonic-gate 	reserve = SA(512);
288*7c478bd9Sstevel@tonic-gate #else
289*7c478bd9Sstevel@tonic-gate #error need to define stack base reserve
290*7c478bd9Sstevel@tonic-gate #endif
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate #ifdef _STACK_GROWS_DOWNWARD
293*7c478bd9Sstevel@tonic-gate 	sp -= reserve;
294*7c478bd9Sstevel@tonic-gate #else
295*7c478bd9Sstevel@tonic-gate #error stack does not grow downwards, routine needs update
296*7c478bd9Sstevel@tonic-gate #endif
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 	if (ssize > reserve)
299*7c478bd9Sstevel@tonic-gate 		ssize -= reserve;
300*7c478bd9Sstevel@tonic-gate 	else
301*7c478bd9Sstevel@tonic-gate 		ssize = 0;
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	/*
304*7c478bd9Sstevel@tonic-gate 	 * Normally, the above will leave plenty of space in sp for a
305*7c478bd9Sstevel@tonic-gate 	 * request.  Just in case some bozo overrides thr_stksegment() to
306*7c478bd9Sstevel@tonic-gate 	 * return an uncommonly small stack size, we turn off stack size
307*7c478bd9Sstevel@tonic-gate 	 * checking if there is less than 1k remaining.
308*7c478bd9Sstevel@tonic-gate 	 */
309*7c478bd9Sstevel@tonic-gate #define	MIN_DOOR_STACK	1024
310*7c478bd9Sstevel@tonic-gate 	if (ssize < MIN_DOOR_STACK)
311*7c478bd9Sstevel@tonic-gate 		ssize = 0;
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate #undef MIN_DOOR_STACK
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	/*
316*7c478bd9Sstevel@tonic-gate 	 * We have to wrap the desc_* arguments for the syscall.  If there are
317*7c478bd9Sstevel@tonic-gate 	 * no descriptors being returned, we can skip the wrapping.
318*7c478bd9Sstevel@tonic-gate 	 */
319*7c478bd9Sstevel@tonic-gate 	if (num_desc != 0) {
320*7c478bd9Sstevel@tonic-gate 		door_return_desc_t d;
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 		d.desc_ptr = desc_ptr;
323*7c478bd9Sstevel@tonic-gate 		d.desc_num = num_desc;
324*7c478bd9Sstevel@tonic-gate 		return (__door_return(data_ptr, data_size, &d, sp, ssize));
325*7c478bd9Sstevel@tonic-gate 	}
326*7c478bd9Sstevel@tonic-gate 	return (__door_return(data_ptr, data_size, NULL, sp, ssize));
327*7c478bd9Sstevel@tonic-gate }
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate /*
330*7c478bd9Sstevel@tonic-gate  * Install a new server creation function.
331*7c478bd9Sstevel@tonic-gate  */
332*7c478bd9Sstevel@tonic-gate door_server_func_t *
333*7c478bd9Sstevel@tonic-gate door_server_create(door_server_func_t *create_func)
334*7c478bd9Sstevel@tonic-gate {
335*7c478bd9Sstevel@tonic-gate 	door_server_func_t *prev;
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate 	lmutex_lock(&door_state_lock);
338*7c478bd9Sstevel@tonic-gate 	prev = door_server_func;
339*7c478bd9Sstevel@tonic-gate 	door_server_func = create_func;
340*7c478bd9Sstevel@tonic-gate 	lmutex_unlock(&door_state_lock);
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	return (prev);
343*7c478bd9Sstevel@tonic-gate }
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate /*
346*7c478bd9Sstevel@tonic-gate  * Create door server threads with cancellation(5) disabled.
347*7c478bd9Sstevel@tonic-gate  */
348*7c478bd9Sstevel@tonic-gate static void *
349*7c478bd9Sstevel@tonic-gate door_create_func(void *arg)
350*7c478bd9Sstevel@tonic-gate {
351*7c478bd9Sstevel@tonic-gate 	(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
352*7c478bd9Sstevel@tonic-gate 	(void) door_return(NULL, 0, NULL, 0);
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	return (arg);
355*7c478bd9Sstevel@tonic-gate }
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate /*
358*7c478bd9Sstevel@tonic-gate  * The default server thread creation routine.
359*7c478bd9Sstevel@tonic-gate  */
360*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
361*7c478bd9Sstevel@tonic-gate static void
362*7c478bd9Sstevel@tonic-gate door_create_server(door_info_t *dip)
363*7c478bd9Sstevel@tonic-gate {
364*7c478bd9Sstevel@tonic-gate 	(void) thr_create(NULL, 0, door_create_func, NULL, THR_DETACHED, NULL);
365*7c478bd9Sstevel@tonic-gate 	yield();	/* Gives server thread a chance to run */
366*7c478bd9Sstevel@tonic-gate }
367