No empty .Rs/.Re
[netbsd-mini2440.git] / sys / compat / mach / mach_semaphore.c
blobdd6ff54e8fb2870e2a5d7c4b201489ea220ec337
1 /* $NetBSD: mach_semaphore.c,v 1.18 2007/12/20 23:02:59 dsl Exp $ */
3 /*-
4 * Copyright (c) 2002-2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Emmanuel Dreyfus
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mach_semaphore.c,v 1.18 2007/12/20 23:02:59 dsl Exp $");
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/signal.h>
39 #include <sys/pool.h>
40 #include <sys/rwlock.h>
41 #include <sys/malloc.h>
42 #include <sys/proc.h>
44 #include <compat/mach/mach_types.h>
45 #include <compat/mach/mach_message.h>
46 #include <compat/mach/mach_semaphore.h>
47 #include <compat/mach/mach_clock.h>
48 #include <compat/mach/mach_errno.h>
49 #include <compat/mach/mach_port.h>
50 #include <compat/mach/mach_services.h>
51 #include <compat/mach/mach_syscallargs.h>
53 /* Semaphore list, lock, pools */
54 static LIST_HEAD(mach_semaphore_list, mach_semaphore) mach_semaphore_list;
55 static krwlock_t mach_semaphore_list_lock;
56 static struct pool mach_semaphore_list_pool;
57 static struct pool mach_waiting_lwp_pool;
59 /* Function to manipulate them */
60 static struct mach_semaphore *mach_semaphore_get(int, int);
61 static void mach_semaphore_put(struct mach_semaphore *);
62 static struct mach_waiting_lwp *mach_waiting_lwp_get
63 (struct lwp *, struct mach_semaphore *);
64 static void mach_waiting_lwp_put
65 (struct mach_waiting_lwp *, struct mach_semaphore *, int);
67 int
68 mach_sys_semaphore_wait_trap(struct lwp *l, const struct mach_sys_semaphore_wait_trap_args *uap, register_t *retval)
70 /* {
71 syscallarg(mach_port_name_t) wait_name;
72 } */
73 struct mach_semaphore *ms;
74 struct mach_waiting_lwp *mwl;
75 struct mach_right *mr;
76 mach_port_t mn;
77 int blocked = 0;
79 mn = SCARG(uap, wait_name);
80 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0)
81 return EPERM;
83 if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
84 return EINVAL;
86 ms = (struct mach_semaphore *)mr->mr_port->mp_data;
88 rw_enter(&ms->ms_lock, RW_WRITER);
89 ms->ms_value--;
90 if (ms->ms_value < 0)
91 blocked = 1;
92 rw_exit(&ms->ms_lock);
94 if (blocked != 0) {
95 mwl = mach_waiting_lwp_get(l, ms);
96 while (ms->ms_value < 0)
97 tsleep(mwl, PZERO|PCATCH, "sem_wait", 0);
98 mach_waiting_lwp_put(mwl, ms, 0);
100 return 0;
104 mach_sys_semaphore_signal_trap(struct lwp *l, const struct mach_sys_semaphore_signal_trap_args *uap, register_t *retval)
106 /* {
107 syscallarg(mach_port_name_t) signal_name;
108 } */
109 struct mach_semaphore *ms;
110 struct mach_waiting_lwp *mwl;
111 struct mach_right *mr;
112 mach_port_t mn;
113 int unblocked = 0;
115 mn = SCARG(uap, signal_name);
116 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0)
117 return EPERM;
119 if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
120 return EINVAL;
122 ms = (struct mach_semaphore *)mr->mr_port->mp_data;
124 rw_enter(&ms->ms_lock, RW_WRITER);
125 ms->ms_value++;
126 if (ms->ms_value >= 0)
127 unblocked = 1;
128 rw_exit(&ms->ms_lock);
130 if (unblocked != 0) {
131 rw_enter(&ms->ms_lock, RW_READER);
132 mwl = TAILQ_FIRST(&ms->ms_waiting);
133 wakeup(mwl);
134 rw_exit(&ms->ms_lock);
136 return 0;
140 mach_semaphore_create(struct mach_trap_args *args)
142 mach_semaphore_create_request_t *req = args->smsg;
143 mach_semaphore_create_reply_t *rep = args->rmsg;
144 size_t *msglen = args->rsize;
145 struct lwp *l = args->l;
146 struct mach_semaphore *ms;
147 struct mach_port *mp;
148 struct mach_right *mr;
150 ms = mach_semaphore_get(req->req_value, req->req_policy);
152 mp = mach_port_get();
153 mp->mp_datatype = MACH_MP_SEMAPHORE;
154 mp->mp_data = (void *)ms;
156 mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
158 *msglen = sizeof(*rep);
159 mach_set_header(rep, req, *msglen);
160 mach_add_port_desc(rep, mr->mr_name);
161 mach_set_trailer(rep, *msglen);
163 return 0;
167 mach_semaphore_destroy(struct mach_trap_args *args)
169 mach_semaphore_destroy_request_t *req = args->smsg;
170 mach_semaphore_destroy_reply_t *rep = args->rmsg;
171 struct lwp *l = args->l;
172 size_t *msglen = args->rsize;
173 struct mach_semaphore *ms;
174 struct mach_right *mr;
175 mach_port_t mn;
177 mn = req->req_sem.name;
178 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0)
179 return mach_msg_error(args, EPERM);
181 if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
182 return mach_msg_error(args, EINVAL);
184 ms = (struct mach_semaphore *)mr->mr_port->mp_data;
185 mach_semaphore_put(ms);
186 mach_right_put(mr, MACH_PORT_TYPE_REF_RIGHTS);
188 *msglen = sizeof(*rep);
189 mach_set_header(rep, req, *msglen);
191 rep->rep_retval = 0;
193 mach_set_trailer(rep, *msglen);
195 return 0;
198 void
199 mach_semaphore_init(void)
201 LIST_INIT(&mach_semaphore_list);
202 rw_init(&mach_semaphore_list_lock);
203 pool_init(&mach_semaphore_list_pool, sizeof (struct mach_semaphore),
204 0, 0, 0, "mach_sem_pool", NULL, IPL_NONE);
205 pool_init(&mach_waiting_lwp_pool, sizeof (struct mach_waiting_lwp),
206 0, 0, 0, "mach_waitp_pool", NULL, IPL_NONE);
208 return;
211 static struct mach_semaphore *
212 mach_semaphore_get(int value, int policy)
214 struct mach_semaphore *ms;
216 ms = (struct mach_semaphore *)pool_get(&mach_semaphore_list_pool,
217 M_WAITOK);
218 ms->ms_value = value;
219 ms->ms_policy = policy;
220 TAILQ_INIT(&ms->ms_waiting);
221 rw_init(&ms->ms_lock);
223 rw_enter(&mach_semaphore_list_lock, RW_WRITER);
224 LIST_INSERT_HEAD(&mach_semaphore_list, ms, ms_list);
225 rw_exit(&mach_semaphore_list_lock);
227 return ms;
230 static void
231 mach_semaphore_put(struct mach_semaphore *ms)
233 struct mach_waiting_lwp *mwl;
235 rw_enter(&ms->ms_lock, RW_WRITER);
236 while ((mwl = TAILQ_FIRST(&ms->ms_waiting)) != NULL)
237 mach_waiting_lwp_put(mwl, ms, 0);
238 rw_exit(&ms->ms_lock);
239 rw_destroy(&ms->ms_lock);
241 rw_enter(&mach_semaphore_list_lock, RW_WRITER);
242 LIST_REMOVE(ms, ms_list);
243 rw_exit(&mach_semaphore_list_lock);
245 pool_put(&mach_semaphore_list_pool, ms);
247 return;
250 static struct mach_waiting_lwp *
251 mach_waiting_lwp_get(struct lwp *l, struct mach_semaphore *ms)
253 struct mach_waiting_lwp *mwl;
255 mwl = (struct mach_waiting_lwp *)pool_get(&mach_waiting_lwp_pool,
256 M_WAITOK);
257 mwl->mwl_l = l;
259 rw_enter(&ms->ms_lock, RW_WRITER);
260 TAILQ_INSERT_TAIL(&ms->ms_waiting, mwl, mwl_list);
261 rw_exit(&ms->ms_lock);
263 return mwl;
266 static void
267 mach_waiting_lwp_put(struct mach_waiting_lwp *mwl, struct mach_semaphore *ms, int locked)
269 if (!locked)
270 rw_enter(&ms->ms_lock, RW_WRITER);
271 TAILQ_REMOVE(&ms->ms_waiting, mwl, mwl_list);
272 if (!locked)
273 rw_exit(&ms->ms_lock);
274 pool_put(&mach_waiting_lwp_pool, mwl);
276 return;
280 * Cleanup after process exit. Need improvements, there
281 * can be some memory leaks here.
283 void
284 mach_semaphore_cleanup(struct lwp *l)
286 struct mach_semaphore *ms;
287 struct mach_waiting_lwp *mwl;
289 rw_enter(&mach_semaphore_list_lock, RW_READER);
290 LIST_FOREACH(ms, &mach_semaphore_list, ms_list) {
291 rw_enter(&ms->ms_lock, RW_WRITER);
292 TAILQ_FOREACH(mwl, &ms->ms_waiting, mwl_list)
293 if (mwl->mwl_l == l) {
294 mach_waiting_lwp_put(mwl, ms, 0);
295 ms->ms_value++;
296 if (ms->ms_value >= 0)
297 wakeup(TAILQ_FIRST(&ms->ms_waiting));
299 rw_exit(&ms->ms_lock);
301 rw_exit(&mach_semaphore_list_lock);
303 return;
307 mach_sys_semaphore_wait_signal_trap(struct lwp *l, const struct mach_sys_semaphore_wait_signal_trap_args *uap, register_t *retval)
309 /* {
310 syscallarg(mach_port_name_t) wait_name;
311 syscallarg(mach_port_name_t) signal_name;
312 } */
313 struct mach_sys_semaphore_wait_trap_args cupwait;
314 struct mach_sys_semaphore_signal_trap_args cupsig;
315 int error;
317 SCARG(&cupsig, signal_name) = SCARG(uap, signal_name);
318 if ((error = mach_sys_semaphore_signal_trap(l, &cupsig, retval)) != 0)
319 return error;
321 SCARG(&cupwait, wait_name) = SCARG(uap, wait_name);
322 if ((error = mach_sys_semaphore_wait_trap(l, &cupwait, retval)) != 0)
323 return error;
325 return 0;
330 mach_sys_semaphore_signal_thread_trap(struct lwp *l, const struct mach_sys_semaphore_signal_thread_trap_args *uap, register_t *retval)
332 /* {
333 syscallarg(mach_port_name_t) signal_name;
334 syscallarg(mach_port_name_t) thread;
335 } */
336 struct mach_right *mr;
337 struct mach_semaphore *ms;
338 mach_port_t mn;
339 struct mach_waiting_lwp *mwl;
340 int unblocked = 0;
343 * Get the semaphore
345 mn = SCARG(uap, signal_name);
346 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
347 return EINVAL;
349 if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
350 return EINVAL;
352 ms = (struct mach_semaphore *)mr->mr_port->mp_data;
355 * Get the thread, and check that it is waiting for our semaphore
356 * If no thread was supplied, pick up the first one.
358 mn = SCARG(uap, thread);
359 if (mn != 0) {
360 if ((mr = mach_right_check(mn, l,
361 MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
362 return EINVAL;
364 if (mr->mr_port->mp_datatype != MACH_MP_LWP)
365 return EINVAL;
367 rw_enter(&ms->ms_lock, RW_WRITER);
368 TAILQ_FOREACH(mwl, &ms->ms_waiting, mwl_list)
369 if (mwl->mwl_l == (struct lwp *)mr->mr_port->mp_data)
370 break;
371 } else {
372 rw_enter(&ms->ms_lock, RW_WRITER);
373 mwl = TAILQ_FIRST(&ms->ms_waiting);
377 * No thread was awaiting for this semaphore,
378 * exit without touching the semaphore.
380 if (mwl == NULL) {
381 rw_exit(&ms->ms_lock);
382 return 0; /* Should be KERN_NOT_WAITING */
385 ms->ms_value++;
386 if (ms->ms_value >= 0)
387 unblocked = 1;
388 rw_exit(&ms->ms_lock);
390 if (unblocked != 0)
391 wakeup(mwl);
393 return 0;
398 mach_sys_semaphore_signal_all_trap(struct lwp *l, const struct mach_sys_semaphore_signal_all_trap_args *uap, register_t *retval)
400 /* {
401 syscallarg(mach_port_name_t) signal_name;
402 } */
403 struct mach_right *mr;
404 struct mach_semaphore *ms;
405 mach_port_t mn;
406 struct mach_waiting_lwp *mwl;
407 int unblocked = 0;
410 * Get the semaphore
412 mn = SCARG(uap, signal_name);
413 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
414 return EINVAL;
416 if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
417 return EINVAL;
419 ms = (struct mach_semaphore *)mr->mr_port->mp_data;
421 rw_enter(&ms->ms_lock, RW_WRITER);
422 ms->ms_value++;
423 if (ms->ms_value >= 0)
424 unblocked = 1;
427 * Wakeup all threads sleeping on it.
429 if (unblocked != 0)
430 TAILQ_FOREACH(mwl, &ms->ms_waiting, mwl_list)
431 wakeup(mwl);
433 rw_exit(&ms->ms_lock);
435 return 0;