Lots of fixes
[kopensolaris-gnu/glibc.git] / sysdeps / unix / sysv / solaris2 / kopensolaris-gnu / door.c
1 /* Copyright (C) 2008 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <sysdep-cancel.h>
21 #include <inline-syscall.h>
22 #include <doorP.h>
23 #include <libio/libioP.h>
24 #include <atomic.h>
25 #include <thread.h>
26 #include <dlfcn.h>
27
28 static pid_t __door_private_pid, __door_unref_pid;
29 static void * door_server_create_default (door_info_t *);
30 static door_server_func_t *door_server_create_proc = &door_server_create_default;
31 static int (*thr_create_ptr) (void *, size_t, void * (*)(void *), void *,
32     long, thread_t *);
33
34 /* Arguments are passed normally with the 6th argument always the subcode.  */
35
36 DECLARE_INLINE_SYSCALL (int, door, long, long, long, long, long, long subcode);
37
38
39 int door_info (int d, door_info_t *info)
40 {
41   return INLINE_SYSCALL (door, 6, d, (long)info, 0, 0, 0, SYS_SUB_door_info);
42 }
43
44
45 int door_bind (int d)
46 {
47   return INLINE_SYSCALL (door, 6, d, 0, 0, 0, 0, SYS_SUB_door_bind);
48 }
49
50
51 int door_unbind (void)
52 {
53   return INLINE_SYSCALL (door, 6, 0, 0, 0, 0, 0, SYS_SUB_door_unbind);
54 }
55
56
57 int door_revoke (int d)
58 {
59   return INLINE_SYSCALL (door, 6, d, 0, 0, 0, 0, SYS_SUB_door_revoke);
60 }
61
62
63 int door_getparam(int d, int param, size_t *out)
64 {
65   return INLINE_SYSCALL (door, 6, d, param, (long)out, 0, 0,
66     SYS_SUB_door_getparam);
67 }
68
69
70 int door_setparam (int d, int param, size_t val)
71 {
72   return INLINE_SYSCALL (door, 6, d, param, val, 0, 0, SYS_SUB_door_setparam);
73 }
74
75
76 int door_call (int d, door_arg_t* params)
77 {
78   if (SINGLE_THREAD_P)
79     return INLINE_SYSCALL (door, 6, d, (long)params, 0, 0, 0,
80       SYS_SUB_door_call);
81
82   int oldtype = LIBC_CANCEL_ASYNC ();
83
84   int res = INLINE_SYSCALL (door, 6, d, (long)params, 0, 0, 0,
85     SYS_SUB_door_call);
86
87   LIBC_CANCEL_RESET (oldtype);
88
89   return res;
90 }
91
92
93 int door_return (char *data_ptr, size_t data_size, door_desc_t *desc_ptr,
94      uint_t num_desc)
95 {
96   ucontext_t uc;
97   if (getcontext (&uc) != 0)
98     return -1;
99
100   door_return_desc_t drd;
101   drd.desc_ptr = desc_ptr;
102   drd.desc_num = num_desc;
103
104   return INLINE_SYSCALL (door, 6, (long)data_ptr, data_size, (long)&drd,
105       (long)uc.uc_stack.ss_sp, uc.uc_stack.ss_size, SYS_SUB_door_return);
106 }
107
108
109 door_server_func_t * door_server_create (door_server_func_t *create_proc)
110 {
111   while (1)
112     {
113       door_server_func_t *cur_proc = door_server_create_proc;
114       door_server_func_t *old_proc = atomic_compare_and_exchange_val_acq (
115           &door_server_create_proc, create_proc, cur_proc);
116       if (old_proc == cur_proc)
117         return old_proc;
118     }
119 }
120
121
122 static void * door_create_default_proc (void *arg)
123 {
124   pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
125   door_return (NULL, 0, NULL, 0);
126
127   return arg;
128 }
129
130
131 static void * door_server_create_default (door_info_t *info)
132 {
133   if (!thr_create_ptr)
134     {
135       void *libpthread = __libc_dlopen ("libpthread.so");
136       if (!libpthread)
137         return NULL;
138       thr_create_ptr = __libc_dlsym (libpthread, "thr_create");
139       if (!thr_create_ptr)
140         return NULL;
141     }
142
143   /* The default server create action is to create a server thread. We use
144      thr_create since we want to create this as a daemon thread.  */
145   thr_create_ptr (NULL, 0, door_create_default_proc, NULL, THR_DETACHED, NULL);
146
147   return NULL;
148 }
149
150
151 int door_create (void (*server_procedure)(void *cookie, char *argp,
152       size_t arg_size, door_desc_t *dp, uint_t n_desc), void *cookie,
153       unsigned int attributes)
154 {
155   // TODO: remove
156   if (attributes & ~(DOOR_NO_CANCEL | DOOR_REFUSE_DESC | DOOR_PRIVATE))
157     abort ();
158
159   /* We lock the io list lock as fork() locks it before forking. This allows us
160      to be safe in the face of a fork.  */
161   _IO_list_lock ();
162
163   return INLINE_SYSCALL (door, 6, (long)server_procedure, (long)cookie, attributes,
164       0, 0, SYS_SUB_door_create);
165
166   pid_t pid = getpid ();
167   if (__door_private_pid != pid && (attributes & DOOR_PRIVATE) == 0)
168     {
169       /* We haven't created the first server.  */
170       (*door_server_create_proc) (NULL);
171       __door_private_pid = pid;
172     }
173
174   // TODO: DOOR_UNREF and DOOR_UNREF_MULTI
175
176   _IO_list_unlock ();
177 }