1 /* $NetBSD: mach_semaphore.c,v 1.14 2006/11/16 01:32:44 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2002-2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Emmanuel Dreyfus
9 *
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.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: mach_semaphore.c,v 1.14 2006/11/16 01:32:44 christos Exp $");
41
42 #include <sys/types.h>
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/signal.h>
46 #include <sys/pool.h>
47 #include <sys/lock.h>
48 #include <sys/malloc.h>
49 #include <sys/proc.h>
50
51 #include <compat/mach/mach_types.h>
52 #include <compat/mach/mach_message.h>
53 #include <compat/mach/mach_semaphore.h>
54 #include <compat/mach/mach_clock.h>
55 #include <compat/mach/mach_errno.h>
56 #include <compat/mach/mach_port.h>
57 #include <compat/mach/mach_services.h>
58 #include <compat/mach/mach_syscallargs.h>
59
60 /* Semaphore list, lock, pools */
61 static LIST_HEAD(mach_semaphore_list, mach_semaphore) mach_semaphore_list;
62 static struct lock mach_semaphore_list_lock;
63 static struct pool mach_semaphore_list_pool;
64 static struct pool mach_waiting_lwp_pool;
65
66 /* Function to manipulate them */
67 static struct mach_semaphore *mach_semaphore_get(int, int);
68 static void mach_semaphore_put(struct mach_semaphore *);
69 static struct mach_waiting_lwp *mach_waiting_lwp_get
70 (struct lwp *, struct mach_semaphore *);
71 static void mach_waiting_lwp_put
72 (struct mach_waiting_lwp *, struct mach_semaphore *, int);
73
74 int
75 mach_sys_semaphore_wait_trap(struct lwp *l, void *v,
76 register_t *retval)
77 {
78 struct mach_sys_semaphore_wait_trap_args /* {
79 syscallarg(mach_port_name_t) wait_name;
80 } */ *uap = v;
81 struct mach_semaphore *ms;
82 struct mach_waiting_lwp *mwl;
83 struct mach_right *mr;
84 mach_port_t mn;
85 int blocked = 0;
86
87 mn = SCARG(uap, wait_name);
88 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0)
89 return EPERM;
90
91 if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
92 return EINVAL;
93
94 ms = (struct mach_semaphore *)mr->mr_port->mp_data;
95
96 lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
97 ms->ms_value--;
98 if (ms->ms_value < 0)
99 blocked = 1;
100 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
101
102 if (blocked != 0) {
103 mwl = mach_waiting_lwp_get(l, ms);
104 while (ms->ms_value < 0)
105 tsleep(mwl, PZERO|PCATCH, "sem_wait", 0);
106 mach_waiting_lwp_put(mwl, ms, 0);
107 }
108 return 0;
109 }
110
111 int
112 mach_sys_semaphore_signal_trap(struct lwp *l, void *v,
113 register_t *retval)
114 {
115 struct mach_sys_semaphore_signal_trap_args /* {
116 syscallarg(mach_port_name_t) signal_name;
117 } */ *uap = v;
118 struct mach_semaphore *ms;
119 struct mach_waiting_lwp *mwl;
120 struct mach_right *mr;
121 mach_port_t mn;
122 int unblocked = 0;
123
124 mn = SCARG(uap, signal_name);
125 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0)
126 return EPERM;
127
128 if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
129 return EINVAL;
130
131 ms = (struct mach_semaphore *)mr->mr_port->mp_data;
132
133 lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
134 ms->ms_value++;
135 if (ms->ms_value >= 0)
136 unblocked = 1;
137 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
138
139 if (unblocked != 0) {
140 lockmgr(&ms->ms_lock, LK_SHARED, NULL);
141 mwl = TAILQ_FIRST(&ms->ms_waiting);
142 wakeup(mwl);
143 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
144 }
145 return 0;
146 }
147
148 int
149 mach_semaphore_create(args)
150 struct mach_trap_args *args;
151 {
152 mach_semaphore_create_request_t *req = args->smsg;
153 mach_semaphore_create_reply_t *rep = args->rmsg;
154 size_t *msglen = args->rsize;
155 struct lwp *l = args->l;
156 struct mach_semaphore *ms;
157 struct mach_port *mp;
158 struct mach_right *mr;
159
160 ms = mach_semaphore_get(req->req_value, req->req_policy);
161
162 mp = mach_port_get();
163 mp->mp_datatype = MACH_MP_SEMAPHORE;
164 mp->mp_data = (void *)ms;
165
166 mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
167
168 *msglen = sizeof(*rep);
169 mach_set_header(rep, req, *msglen);
170 mach_add_port_desc(rep, mr->mr_name);
171 mach_set_trailer(rep, *msglen);
172
173 return 0;
174 }
175
176 int
177 mach_semaphore_destroy(args)
178 struct mach_trap_args *args;
179 {
180 mach_semaphore_destroy_request_t *req = args->smsg;
181 mach_semaphore_destroy_reply_t *rep = args->rmsg;
182 struct lwp *l = args->l;
183 size_t *msglen = args->rsize;
184 struct mach_semaphore *ms;
185 struct mach_right *mr;
186 mach_port_t mn;
187
188 mn = req->req_sem.name;
189 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0)
190 return mach_msg_error(args, EPERM);
191
192 if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
193 return mach_msg_error(args, EINVAL);
194
195 ms = (struct mach_semaphore *)mr->mr_port->mp_data;
196 mach_semaphore_put(ms);
197 mach_right_put(mr, MACH_PORT_TYPE_REF_RIGHTS);
198
199 *msglen = sizeof(*rep);
200 mach_set_header(rep, req, *msglen);
201
202 rep->rep_retval = 0;
203
204 mach_set_trailer(rep, *msglen);
205
206 return 0;
207 }
208
209 void
210 mach_semaphore_init(void)
211 {
212 LIST_INIT(&mach_semaphore_list);
213 lockinit(&mach_semaphore_list_lock, PZERO|PCATCH, "mach_sem", 0, 0);
214 pool_init(&mach_semaphore_list_pool, sizeof (struct mach_semaphore),
215 0, 0, 0, "mach_sem_pool", NULL);
216 pool_init(&mach_waiting_lwp_pool, sizeof (struct mach_waiting_lwp),
217 0, 0, 0, "mach_waitp_pool", NULL);
218
219 return;
220 }
221
222 static struct mach_semaphore *
223 mach_semaphore_get(value, policy)
224 int value;
225 int policy;
226 {
227 struct mach_semaphore *ms;
228
229 ms = (struct mach_semaphore *)pool_get(&mach_semaphore_list_pool,
230 M_WAITOK);
231 ms->ms_value = value;
232 ms->ms_policy = policy;
233 TAILQ_INIT(&ms->ms_waiting);
234 lockinit(&ms->ms_lock, PZERO|PCATCH, "mach_waitp", 0, 0);
235
236 lockmgr(&mach_semaphore_list_lock, LK_EXCLUSIVE, NULL);
237 LIST_INSERT_HEAD(&mach_semaphore_list, ms, ms_list);
238 lockmgr(&mach_semaphore_list_lock, LK_RELEASE, NULL);
239
240 return ms;
241 }
242
243 static void
244 mach_semaphore_put(ms)
245 struct mach_semaphore *ms;
246 {
247 struct mach_waiting_lwp *mwl;
248
249 lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
250 while ((mwl = TAILQ_FIRST(&ms->ms_waiting)) != NULL)
251 mach_waiting_lwp_put(mwl, ms, 0);
252 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
253 lockmgr(&ms->ms_lock, LK_DRAIN, NULL);
254
255 lockmgr(&mach_semaphore_list_lock, LK_EXCLUSIVE, NULL);
256 LIST_REMOVE(ms, ms_list);
257 lockmgr(&mach_semaphore_list_lock, LK_RELEASE, NULL);
258
259 pool_put(&mach_semaphore_list_pool, ms);
260
261 return;
262 }
263
264 static struct mach_waiting_lwp *
265 mach_waiting_lwp_get(l, ms)
266 struct lwp *l;
267 struct mach_semaphore *ms;
268 {
269 struct mach_waiting_lwp *mwl;
270
271 mwl = (struct mach_waiting_lwp *)pool_get(&mach_waiting_lwp_pool,
272 M_WAITOK);
273 mwl->mwl_l = l;
274
275 lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
276 TAILQ_INSERT_TAIL(&ms->ms_waiting, mwl, mwl_list);
277 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
278
279 return mwl;
280 }
281
282 static void
283 mach_waiting_lwp_put(mwl, ms, locked)
284 struct mach_waiting_lwp *mwl;
285 struct mach_semaphore *ms;
286 int locked;
287 {
288 if (!locked)
289 lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
290 TAILQ_REMOVE(&ms->ms_waiting, mwl, mwl_list);
291 if (!locked)
292 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
293 pool_put(&mach_waiting_lwp_pool, mwl);
294
295 return;
296 }
297
298 /*
299 * Cleanup after process exit. Need improvements, there
300 * can be some memory leaks here.
301 */
302 void
303 mach_semaphore_cleanup(l)
304 struct lwp *l;
305 {
306 struct mach_semaphore *ms;
307 struct mach_waiting_lwp *mwl;
308
309 lockmgr(&mach_semaphore_list_lock, LK_SHARED, NULL);
310 LIST_FOREACH(ms, &mach_semaphore_list, ms_list) {
311 lockmgr(&ms->ms_lock, LK_SHARED, NULL);
312 TAILQ_FOREACH(mwl, &ms->ms_waiting, mwl_list)
313 if (mwl->mwl_l == l) {
314 lockmgr(&ms->ms_lock, LK_UPGRADE, NULL);
315 mach_waiting_lwp_put(mwl, ms, 0);
316 ms->ms_value++;
317 if (ms->ms_value >= 0)
318 wakeup(TAILQ_FIRST(&ms->ms_waiting));
319 }
320 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
321 }
322 lockmgr(&mach_semaphore_list_lock, LK_RELEASE, NULL);
323
324 return;
325 }
326
327 int
328 mach_sys_semaphore_wait_signal_trap(l, v, retval)
329 struct lwp *l;
330 void *v;
331 register_t *retval;
332 {
333 struct mach_sys_semaphore_wait_signal_trap_args /* {
334 syscallarg(mach_port_name_t) wait_name;
335 syscallarg(mach_port_name_t) signal_name;
336 } */ *uap = v;
337 struct mach_sys_semaphore_wait_trap_args cupwait;
338 struct mach_sys_semaphore_signal_trap_args cupsig;
339 int error;
340
341 SCARG(&cupsig, signal_name) = SCARG(uap, signal_name);
342 if ((error = mach_sys_semaphore_signal_trap(l, &cupsig, retval)) != 0)
343 return error;
344
345 SCARG(&cupwait, wait_name) = SCARG(uap, wait_name);
346 if ((error = mach_sys_semaphore_wait_trap(l, &cupwait, retval)) != 0)
347 return error;
348
349 return 0;
350 }
351
352
353 int
354 mach_sys_semaphore_signal_thread_trap(struct lwp *l, void *v,
355 register_t *retval)
356 {
357 struct mach_sys_semaphore_signal_thread_trap_args /* {
358 syscallarg(mach_port_name_t) signal_name;
359 syscallarg(mach_port_name_t) thread;
360 } */ *uap = v;
361 struct mach_right *mr;
362 struct mach_semaphore *ms;
363 mach_port_t mn;
364 struct mach_waiting_lwp *mwl;
365 int unblocked = 0;
366
367 /*
368 * Get the semaphore
369 */
370 mn = SCARG(uap, signal_name);
371 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
372 return EINVAL;
373
374 if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
375 return EINVAL;
376
377 ms = (struct mach_semaphore *)mr->mr_port->mp_data;
378
379 /*
380 * Get the thread, and check that it is waiting for our semaphore
381 * If no thread was supplied, pick up the first one.
382 */
383 mn = SCARG(uap, thread);
384 if (mn != 0) {
385 if ((mr = mach_right_check(mn, l,
386 MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
387 return EINVAL;
388
389 if (mr->mr_port->mp_datatype != MACH_MP_LWP)
390 return EINVAL;
391
392 lockmgr(&ms->ms_lock, LK_SHARED, NULL);
393 TAILQ_FOREACH(mwl, &ms->ms_waiting, mwl_list)
394 if (mwl->mwl_l == (struct lwp *)mr->mr_port->mp_data)
395 break;
396 } else {
397 lockmgr(&ms->ms_lock, LK_SHARED, NULL);
398 mwl = TAILQ_FIRST(&ms->ms_waiting);
399 }
400
401 /*
402 * No thread was awaiting for this semaphore,
403 * exit without touching the semaphore.
404 */
405 if (mwl == NULL) {
406 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
407 return 0; /* Should be KERN_NOT_WAITING */
408 }
409
410 lockmgr(&ms->ms_lock, LK_UPGRADE, NULL);
411 ms->ms_value++;
412 if (ms->ms_value >= 0)
413 unblocked = 1;
414 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
415
416 if (unblocked != 0)
417 wakeup(mwl);
418
419 return 0;
420 }
421
422
423 int
424 mach_sys_semaphore_signal_all_trap(struct lwp *l, void *v,
425 register_t *retval)
426 {
427 struct mach_sys_semaphore_signal_all_trap_args /* {
428 syscallarg(mach_port_name_t) signal_name;
429 } */ *uap = v;
430 struct mach_right *mr;
431 struct mach_semaphore *ms;
432 mach_port_t mn;
433 struct mach_waiting_lwp *mwl;
434 int unblocked = 0;
435
436 /*
437 * Get the semaphore
438 */
439 mn = SCARG(uap, signal_name);
440 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
441 return EINVAL;
442
443 if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
444 return EINVAL;
445
446 ms = (struct mach_semaphore *)mr->mr_port->mp_data;
447
448 lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
449 ms->ms_value++;
450 if (ms->ms_value >= 0)
451 unblocked = 1;
452 lockmgr(&ms->ms_lock, LK_DOWNGRADE, NULL);
453
454 /*
455 * Wakeup all threads sleeping on it.
456 */
457 if (unblocked != 0)
458 TAILQ_FOREACH(mwl, &ms->ms_waiting, mwl_list)
459 wakeup(mwl);
460
461 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
462
463 return 0;
464 }
465
466
Cache object: b6dc4e05328289e30ba3a677eb244752
|