diff options
Diffstat (limited to 'sysdeps/unix/sysv/solaris2/kopensolaris-gnu/door.c')
-rw-r--r-- | sysdeps/unix/sysv/solaris2/kopensolaris-gnu/door.c | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/door.c b/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/door.c new file mode 100644 index 0000000000..93d19f86ae --- /dev/null +++ b/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/door.c @@ -0,0 +1,261 @@ +/* Copyright (C) 2008 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sysdep-cancel.h> +#include <inline-syscall.h> +#include <doorP.h> +#include <ucredP.h> +#include <libio/libioP.h> +#include <atomic.h> +#include <thread.h> +#include <dlfcn.h> +#include <alloca.h> +#include <signal.h> + +static pid_t __door_private_pid, __door_unref_pid; +static void door_server_create_default (door_info_t *); +door_server_func_t *door_server_create_proc = door_server_create_default; +static int (*thr_create_ptr) (void *, size_t, void * (*)(void *), void *, + long, thread_t *); + +/* Arguments are passed normally with the 6th argument always the subcode. */ + +DECLARE_INLINE_SYSCALL (int, door, long, long, long, long, long, long subcode); + + +int door_info (int d, door_info_t *info) +{ + return INLINE_SYSCALL (door, 6, d, (long)info, 0, 0, 0, SYS_SUB_door_info); +} + + +int door_bind (int d) +{ + return INLINE_SYSCALL (door, 6, d, 0, 0, 0, 0, SYS_SUB_door_bind); +} + + +int door_unbind (void) +{ + return INLINE_SYSCALL (door, 6, 0, 0, 0, 0, 0, SYS_SUB_door_unbind); +} + + +int door_revoke (int d) +{ + return INLINE_SYSCALL (door, 6, d, 0, 0, 0, 0, SYS_SUB_door_revoke); +} + + +int door_getparam(int d, int param, size_t *out) +{ + return INLINE_SYSCALL (door, 6, d, param, (long)out, 0, 0, + SYS_SUB_door_getparam); +} + + +int door_setparam (int d, int param, size_t val) +{ + return INLINE_SYSCALL (door, 6, d, param, val, 0, 0, SYS_SUB_door_setparam); +} + + +int door_call (int d, door_arg_t* params) +{ + if (SINGLE_THREAD_P) + return INLINE_SYSCALL (door, 6, d, (long)params, 0, 0, 0, + SYS_SUB_door_call); + + int oldtype = LIBC_CANCEL_ASYNC (); + + int res = INLINE_SYSCALL (door, 6, d, (long)params, 0, 0, 0, + SYS_SUB_door_call); + + LIBC_CANCEL_RESET (oldtype); + + return res; +} + + +int door_return (char *data_ptr, size_t data_size, door_desc_t *desc_ptr, + uint_t num_desc) +{ + /* Reserve space for returned client arguments. */ + stack_t stack; + thr_stksegment (&stack); + if (stack.ss_size > DOOR_MIN_STACKSIZE) + { + stack.ss_size -= DOOR_MIN_STACKSIZE; + // TODO: handle stacks that grow up + stack.ss_sp -= DOOR_MIN_STACKSIZE; + } + else + { + stack.ss_size = 0; + } + + door_return_desc_t drd; + drd.desc_ptr = desc_ptr; + drd.desc_num = num_desc; + + /* __door_return never returns unless there's an error. */ + while (__door_return ((long)data_ptr, data_size, (long)&drd, + (long)stack.ss_sp, stack.ss_size, SYS_SUB_door_return) == 0 || + errno == EINTR || errno == ERESTART) ; + return -1; +} + + +door_server_func_t * door_server_create (door_server_func_t *create_proc) +{ + while (1) + { + door_server_func_t *cur_proc = door_server_create_proc; + door_server_func_t *old_proc = atomic_compare_and_exchange_val_acq ( + &door_server_create_proc, create_proc, cur_proc); + if (old_proc == cur_proc) + return old_proc; + } +} + + +static void * door_create_default_proc (void *arg) +{ + pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); + door_return (NULL, 0, NULL, 0); + + return arg; +} + + +static int door_load_libpthread (void) +{ + if (!thr_create_ptr) + { + void *libpthread = __libc_dlopen ("libpthread.so.0"); + if (!libpthread) + return -1; + thr_create_ptr = __libc_dlsym (libpthread, "thr_create"); + if (!thr_create_ptr) + return -1; + } + + return 0; +} + + +static void door_server_create_default (door_info_t *info) +{ + if (door_load_libpthread () != 0) + return; + + /* The default server create action is to create a server thread. We use + thr_create since we want to create this as a daemon thread. */ + thr_create_ptr (NULL, 0, door_create_default_proc, NULL, THR_DETACHED, NULL); +} + + +static void * door_unref_proc (void *arg) +{ + /* We may get interrupted so loop. */ + while (INLINE_SYSCALL (door, 6, 0, 0, 0, 0, 0, SYS_SUB_door_unrefsys) && + errno == EINTR) ; + + return NULL; +} + + +int door_create (void (*server_procedure)(void *cookie, char *argp, + size_t arg_size, door_desc_t *dp, uint_t n_desc), void *cookie, + unsigned int attributes) +{ + // TODO: remove + if (attributes & ~(DOOR_NO_CANCEL | DOOR_REFUSE_DESC | DOOR_PRIVATE | \ + DOOR_UNREF | DOOR_UNREF_MULTI)) + abort (); + + /* We lock the io list lock as fork() locks it before forking. This allows us + to be safe in the face of a fork. */ + _IO_list_lock (); + + int res = INLINE_SYSCALL (door, 6, (long)server_procedure, + (long)cookie, attributes, 0, 0, SYS_SUB_door_create); + + pid_t pid = getpid (); + if (__door_private_pid != pid && (attributes & DOOR_PRIVATE) == 0) + { + /* We haven't created the first server. */ + (*door_server_create_proc) (NULL); + __door_private_pid = pid; + } + if (__door_unref_pid != pid && (attributes & (DOOR_UNREF | DOOR_UNREF_MULTI))) + { + if (door_load_libpthread () != 0) + return -1; + + /* We haven't created the unreferenced thread. */ + thr_create_ptr (NULL, 0, door_unref_proc, NULL, THR_DAEMON, NULL); + __door_unref_pid = pid; + } + + _IO_list_unlock (); + + return res; +} + + +int door_ucred (ucred_t **info) +{ + ucred_t *uc = *info; + if (!uc) + { + uc = _ucred_alloc (); + if (!uc) + return -1; + } + + int res = INLINE_SYSCALL (door, 6, (long)uc, 0, 0, 0, 0, SYS_SUB_door_ucred); + if (res != 0) + { + if (!*info) + free (uc); + return -1; + } + + *info = uc; + + return 0; +} + + +int door_cred (door_cred_t *info) +{ + ucred_t *uc = alloca (ucred_size ()); + int res = INLINE_SYSCALL (door, 6, (long)uc, 0, 0, 0, 0, SYS_SUB_door_ucred); + if (res != 0) + return -1; + + info->dc_euid = ucred_geteuid (uc); + info->dc_ruid = ucred_getruid (uc); + info->dc_egid = ucred_getegid (uc); + info->dc_rgid = ucred_getrgid (uc); + info->dc_pid = ucred_getpid (uc); + + return 0; +} |