6811333 Remove prom_printf() message in emlxs driver
[opensolaris.git] / usr / src / lib / libc / port / threads / door_calls.c
blob3dae1445d8ae3a7d0610396cfd756b2cd5e812ee
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include "lint.h"
30 #include "thr_uberdata.h"
31 #include "libc.h"
33 #include <alloca.h>
34 #include <unistd.h>
35 #include <thread.h>
36 #include <pthread.h>
37 #include <stdio.h>
38 #include <errno.h>
39 #include <door.h>
40 #include <signal.h>
41 #include <ucred.h>
42 #include <sys/ucred.h>
44 static door_server_func_t door_create_server;
47 * Global state -- the non-statics are accessed from the __door_return()
48 * syscall wrapper.
50 static mutex_t door_state_lock = DEFAULTMUTEX;
51 door_server_func_t *door_server_func = door_create_server;
52 pid_t door_create_pid = 0;
53 static pid_t door_create_first_pid = 0;
54 static pid_t door_create_unref_pid = 0;
57 * The raw system call interfaces
59 extern int __door_create(void (*)(void *, char *, size_t, door_desc_t *,
60 uint_t), void *, uint_t);
61 extern int __door_return(caddr_t, size_t, door_return_desc_t *, caddr_t,
62 size_t);
63 extern int __door_ucred(ucred_t *);
64 extern int __door_unref(void);
67 * We park the ourselves in the kernel to serve as the "caller" for
68 * unreferenced upcalls for this process. If the call returns with
69 * EINTR (e.g., someone did a forkall), we repeat as long as we're still
70 * in the parent. If the child creates an unref door it will create
71 * a new thread.
73 static void *
74 door_unref_func(void *arg)
76 pid_t mypid = (pid_t)(uintptr_t)arg;
78 sigset_t fillset;
80 /* mask signals before diving into the kernel */
81 (void) sigfillset(&fillset);
82 (void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
84 while (getpid() == mypid && __door_unref() && errno == EINTR)
85 continue;
87 return (NULL);
90 int
91 door_create(void (*f)(void *, char *, size_t, door_desc_t *, uint_t),
92 void *cookie, uint_t flags)
94 int d;
96 int is_private = (flags & DOOR_PRIVATE);
97 int is_unref = (flags & (DOOR_UNREF | DOOR_UNREF_MULTI));
98 int do_create_first = 0;
99 int do_create_unref = 0;
101 ulwp_t *self = curthread;
103 pid_t mypid;
105 if (self->ul_vfork) {
106 errno = ENOTSUP;
107 return (-1);
111 * Doors are associated with the processes which created them. In
112 * the face of forkall(), this gets quite complicated. To simplify
113 * it somewhat, we include the call to __door_create() in a critical
114 * section, and figure out what additional actions to take while
115 * still in the critical section.
117 enter_critical(self);
118 if ((d = __door_create(f, cookie, flags)) < 0) {
119 exit_critical(self);
120 return (-1);
122 mypid = getpid();
123 if (mypid != door_create_pid ||
124 (!is_private && mypid != door_create_first_pid) ||
125 (is_unref && mypid != door_create_unref_pid)) {
127 lmutex_lock(&door_state_lock);
128 door_create_pid = mypid;
130 if (!is_private && mypid != door_create_first_pid) {
131 do_create_first = 1;
132 door_create_first_pid = mypid;
134 if (is_unref && mypid != door_create_unref_pid) {
135 do_create_unref = 1;
136 door_create_unref_pid = mypid;
138 lmutex_unlock(&door_state_lock);
140 exit_critical(self);
142 if (do_create_unref) {
144 * Create an unref thread the first time we create an
145 * unref door for this process. Create it as a daemon
146 * thread, so that it doesn't interfere with normal exit
147 * processing.
149 (void) thr_create(NULL, 0, door_unref_func,
150 (void *)(uintptr_t)mypid, THR_DAEMON, NULL);
154 * If this is the first door created in the process, or the door
155 * has a private pool, we need to kick off the thread pool now.
157 if (do_create_first)
158 (*door_server_func)(NULL);
160 if (is_private) {
161 door_info_t di;
163 if (__door_info(d, &di) < 0)
164 return (-1);
165 (*door_server_func)(&di);
168 return (d);
172 door_ucred(ucred_t **uc)
174 ucred_t *ucp = *uc;
176 if (ucp == NULL) {
177 ucp = _ucred_alloc();
178 if (ucp == NULL)
179 return (-1);
182 if (__door_ucred(ucp) != 0) {
183 if (*uc == NULL)
184 ucred_free(ucp);
185 return (-1);
188 *uc = ucp;
190 return (0);
194 door_cred(door_cred_t *dc)
197 * Ucred size is small and alloca is fast
198 * and cannot fail.
200 ucred_t *ucp = alloca(ucred_size());
201 int ret;
203 if ((ret = __door_ucred(ucp)) == 0) {
204 dc->dc_euid = ucred_geteuid(ucp);
205 dc->dc_ruid = ucred_getruid(ucp);
206 dc->dc_egid = ucred_getegid(ucp);
207 dc->dc_rgid = ucred_getrgid(ucp);
208 dc->dc_pid = ucred_getpid(ucp);
210 return (ret);
214 door_return(char *data_ptr, size_t data_size,
215 door_desc_t *desc_ptr, uint_t num_desc)
217 caddr_t sp;
218 size_t ssize;
219 size_t reserve;
220 ulwp_t *self = curthread;
223 stack_t s;
224 if (thr_stksegment(&s) != 0) {
225 errno = EINVAL;
226 return (-1);
228 sp = s.ss_sp;
229 ssize = s.ss_size;
232 if (!self->ul_door_noreserve) {
234 * When we return from the kernel, we must have enough stack
235 * available to handle the request. Since the creator of
236 * the thread has control over its stack size, and larger
237 * stacks generally indicate bigger request queues, we
238 * use the heuristic of reserving 1/32nd of the stack size
239 * (up to the default stack size), with a minimum of 1/8th
240 * of MINSTACK. Currently, this translates to:
242 * _ILP32 _LP64
243 * min resv 512 bytes 1024 bytes
244 * max resv 32k bytes 64k bytes
246 * This reservation can be disabled by setting
247 * _THREAD_DOOR_NORESERVE=1
248 * in the environment, but shouldn't be.
251 #define STACK_FRACTION 32
252 #define MINSTACK_FRACTION 8
254 if (ssize < (MINSTACK * (STACK_FRACTION/MINSTACK_FRACTION)))
255 reserve = MINSTACK / MINSTACK_FRACTION;
256 else if (ssize < DEFAULTSTACK)
257 reserve = ssize / STACK_FRACTION;
258 else
259 reserve = DEFAULTSTACK / STACK_FRACTION;
261 #undef STACK_FRACTION
262 #undef MINSTACK_FRACTION
264 if (ssize > reserve)
265 ssize -= reserve;
266 else
267 ssize = 0;
271 * Historically, the __door_return() syscall wrapper subtracted
272 * some "slop" from the stack pointer before trapping into the
273 * kernel. We now do this here, so that ssize can be adjusted
274 * correctly. Eventually, this should be removed, since it is
275 * unnecessary. (note that TNF on x86 currently relies upon this
276 * idiocy)
278 #if defined(__sparc)
279 reserve = SA(MINFRAME);
280 #elif defined(__x86)
281 reserve = SA(512);
282 #else
283 #error need to define stack base reserve
284 #endif
286 #ifdef _STACK_GROWS_DOWNWARD
287 sp -= reserve;
288 #else
289 #error stack does not grow downwards, routine needs update
290 #endif
292 if (ssize > reserve)
293 ssize -= reserve;
294 else
295 ssize = 0;
298 * Normally, the above will leave plenty of space in sp for a
299 * request. Just in case some bozo overrides thr_stksegment() to
300 * return an uncommonly small stack size, we turn off stack size
301 * checking if there is less than 1k remaining.
303 #define MIN_DOOR_STACK 1024
304 if (ssize < MIN_DOOR_STACK)
305 ssize = 0;
307 #undef MIN_DOOR_STACK
310 * We have to wrap the desc_* arguments for the syscall. If there are
311 * no descriptors being returned, we can skip the wrapping.
313 if (num_desc != 0) {
314 door_return_desc_t d;
316 d.desc_ptr = desc_ptr;
317 d.desc_num = num_desc;
318 return (__door_return(data_ptr, data_size, &d, sp, ssize));
320 return (__door_return(data_ptr, data_size, NULL, sp, ssize));
324 * Install a new server creation function.
326 door_server_func_t *
327 door_server_create(door_server_func_t *create_func)
329 door_server_func_t *prev;
331 lmutex_lock(&door_state_lock);
332 prev = door_server_func;
333 door_server_func = create_func;
334 lmutex_unlock(&door_state_lock);
336 return (prev);
340 * Create door server threads with cancellation(5) disabled.
342 static void *
343 door_create_func(void *arg)
345 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
346 (void) door_return(NULL, 0, NULL, 0);
348 return (arg);
352 * The default server thread creation routine.
354 /* ARGSUSED */
355 static void
356 door_create_server(door_info_t *dip)
358 (void) thr_create(NULL, 0, door_create_func, NULL, THR_DETACHED, NULL);
359 yield(); /* Gives server thread a chance to run */