1 /* $NetBSD: mach_semaphore.c,v 1.11 2005/02/26 23:10:20 perry 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.11 2005/02/26 23:10:20 perry 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(l, v, retval)
76 struct lwp *l;
77 void *v;
78 register_t *retval;
79 {
80 struct mach_sys_semaphore_wait_trap_args /* {
81 syscallarg(mach_port_name_t) wait_name;
82 } */ *uap = v;
83 struct mach_semaphore *ms;
84 struct mach_waiting_lwp *mwl;
85 struct mach_right *mr;
86 mach_port_t mn;
87 int blocked = 0;
88
89 mn = SCARG(uap, wait_name);
90 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0)
91 return EPERM;
92
93 if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
94 return EINVAL;
95
96 ms = (struct mach_semaphore *)mr->mr_port->mp_data;
97
98 lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
99 ms->ms_value--;
100 if (ms->ms_value < 0)
101 blocked = 1;
102 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
103
104 if (blocked != 0) {
105 mwl = mach_waiting_lwp_get(l, ms);
106 while (ms->ms_value < 0)
107 tsleep(mwl, PZERO|PCATCH, "sem_wait", 0);
108 mach_waiting_lwp_put(mwl, ms, 0);
109 }
110 return 0;
111 }
112
113 int
114 mach_sys_semaphore_signal_trap(l, v, retval)
115 struct lwp *l;
116 void *v;
117 register_t *retval;
118 {
119 struct mach_sys_semaphore_signal_trap_args /* {
120 syscallarg(mach_port_name_t) signal_name;
121 } */ *uap = v;
122 struct mach_semaphore *ms;
123 struct mach_waiting_lwp *mwl;
124 struct mach_right *mr;
125 mach_port_t mn;
126 int unblocked = 0;
127
128 mn = SCARG(uap, signal_name);
129 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0)
130 return EPERM;
131
132 if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
133 return EINVAL;
134
135 ms = (struct mach_semaphore *)mr->mr_port->mp_data;
136
137 lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
138 ms->ms_value++;
139 if (ms->ms_value >= 0)
140 unblocked = 1;
141 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
142
143 if (unblocked != 0) {
144 lockmgr(&ms->ms_lock, LK_SHARED, NULL);
145 mwl = TAILQ_FIRST(&ms->ms_waiting);
146 wakeup(mwl);
147 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
148 }
149 return 0;
150 }
151
152 int
153 mach_semaphore_create(args)
154 struct mach_trap_args *args;
155 {
156 mach_semaphore_create_request_t *req = args->smsg;
157 mach_semaphore_create_reply_t *rep = args->rmsg;
158 size_t *msglen = args->rsize;
159 struct lwp *l = args->l;
160 struct mach_semaphore *ms;
161 struct mach_port *mp;
162 struct mach_right *mr;
163
164 ms = mach_semaphore_get(req->req_value, req->req_policy);
165
166 mp = mach_port_get();
167 mp->mp_datatype = MACH_MP_SEMAPHORE;
168 mp->mp_data = (void *)ms;
169
170 mr = mach_right_get(mp, l, MACH_PORT_TYPE_SEND, 0);
171
172 *msglen = sizeof(*rep);
173 mach_set_header(rep, req, *msglen);
174 mach_add_port_desc(rep, mr->mr_name);
175 mach_set_trailer(rep, *msglen);
176
177 return 0;
178 }
179
180 int
181 mach_semaphore_destroy(args)
182 struct mach_trap_args *args;
183 {
184 mach_semaphore_destroy_request_t *req = args->smsg;
185 mach_semaphore_destroy_reply_t *rep = args->rmsg;
186 struct lwp *l = args->l;
187 size_t *msglen = args->rsize;
188 struct mach_semaphore *ms;
189 struct mach_right *mr;
190 mach_port_t mn;
191
192 mn = req->req_sem.name;
193 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0)
194 return mach_msg_error(args, EPERM);
195
196 if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
197 return mach_msg_error(args, EINVAL);
198
199 ms = (struct mach_semaphore *)mr->mr_port->mp_data;
200 mach_semaphore_put(ms);
201 mach_right_put(mr, MACH_PORT_TYPE_REF_RIGHTS);
202
203 *msglen = sizeof(*rep);
204 mach_set_header(rep, req, *msglen);
205
206 rep->rep_retval = 0;
207
208 mach_set_trailer(rep, *msglen);
209
210 return 0;
211 }
212
213 void
214 mach_semaphore_init(void)
215 {
216 LIST_INIT(&mach_semaphore_list);
217 lockinit(&mach_semaphore_list_lock, PZERO|PCATCH, "mach_sem", 0, 0);
218 pool_init(&mach_semaphore_list_pool, sizeof (struct mach_semaphore),
219 0, 0, 0, "mach_sem_pool", NULL);
220 pool_init(&mach_waiting_lwp_pool, sizeof (struct mach_waiting_lwp),
221 0, 0, 0, "mach_waitp_pool", NULL);
222
223 return;
224 }
225
226 static struct mach_semaphore *
227 mach_semaphore_get(value, policy)
228 int value;
229 int policy;
230 {
231 struct mach_semaphore *ms;
232
233 ms = (struct mach_semaphore *)pool_get(&mach_semaphore_list_pool,
234 M_WAITOK);
235 ms->ms_value = value;
236 ms->ms_policy = policy;
237 TAILQ_INIT(&ms->ms_waiting);
238 lockinit(&ms->ms_lock, PZERO|PCATCH, "mach_waitp", 0, 0);
239
240 lockmgr(&mach_semaphore_list_lock, LK_EXCLUSIVE, NULL);
241 LIST_INSERT_HEAD(&mach_semaphore_list, ms, ms_list);
242 lockmgr(&mach_semaphore_list_lock, LK_RELEASE, NULL);
243
244 return ms;
245 }
246
247 static void
248 mach_semaphore_put(ms)
249 struct mach_semaphore *ms;
250 {
251 struct mach_waiting_lwp *mwl;
252
253 lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
254 while ((mwl = TAILQ_FIRST(&ms->ms_waiting)) != NULL)
255 mach_waiting_lwp_put(mwl, ms, 0);
256 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
257 lockmgr(&ms->ms_lock, LK_DRAIN, NULL);
258
259 lockmgr(&mach_semaphore_list_lock, LK_EXCLUSIVE, NULL);
260 LIST_REMOVE(ms, ms_list);
261 lockmgr(&mach_semaphore_list_lock, LK_RELEASE, NULL);
262
263 pool_put(&mach_semaphore_list_pool, ms);
264
265 return;
266 }
267
268 static struct mach_waiting_lwp *
269 mach_waiting_lwp_get(l, ms)
270 struct lwp *l;
271 struct mach_semaphore *ms;
272 {
273 struct mach_waiting_lwp *mwl;
274
275 mwl = (struct mach_waiting_lwp *)pool_get(&mach_waiting_lwp_pool,
276 M_WAITOK);
277 mwl->mwl_l = l;
278
279 lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
280 TAILQ_INSERT_TAIL(&ms->ms_waiting, mwl, mwl_list);
281 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
282
283 return mwl;
284 }
285
286 static void
287 mach_waiting_lwp_put(mwl, ms, locked)
288 struct mach_waiting_lwp *mwl;
289 struct mach_semaphore *ms;
290 int locked;
291 {
292 if (!locked)
293 lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
294 TAILQ_REMOVE(&ms->ms_waiting, mwl, mwl_list);
295 if (!locked)
296 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
297 pool_put(&mach_waiting_lwp_pool, mwl);
298
299 return;
300 }
301
302 /*
303 * Cleanup after process exit. Need improvements, there
304 * can be some memory leaks here.
305 */
306 void
307 mach_semaphore_cleanup(l)
308 struct lwp *l;
309 {
310 struct mach_semaphore *ms;
311 struct mach_waiting_lwp *mwl;
312
313 lockmgr(&mach_semaphore_list_lock, LK_SHARED, NULL);
314 LIST_FOREACH(ms, &mach_semaphore_list, ms_list) {
315 lockmgr(&ms->ms_lock, LK_SHARED, NULL);
316 TAILQ_FOREACH(mwl, &ms->ms_waiting, mwl_list)
317 if (mwl->mwl_l == l) {
318 lockmgr(&ms->ms_lock, LK_UPGRADE, NULL);
319 mach_waiting_lwp_put(mwl, ms, 0);
320 ms->ms_value++;
321 if (ms->ms_value >= 0)
322 wakeup(TAILQ_FIRST(&ms->ms_waiting));
323 }
324 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
325 }
326 lockmgr(&mach_semaphore_list_lock, LK_RELEASE, NULL);
327
328 return;
329 }
330
331 int
332 mach_sys_semaphore_wait_signal_trap(l, v, retval)
333 struct lwp *l;
334 void *v;
335 register_t *retval;
336 {
337 struct mach_sys_semaphore_wait_signal_trap_args /* {
338 syscallarg(mach_port_name_t) wait_name;
339 syscallarg(mach_port_name_t) signal_name;
340 } */ *uap = v;
341 struct mach_sys_semaphore_wait_trap_args cupwait;
342 struct mach_sys_semaphore_signal_trap_args cupsig;
343 int error;
344
345 SCARG(&cupsig, signal_name) = SCARG(uap, signal_name);
346 if ((error = mach_sys_semaphore_signal_trap(l, &cupsig, retval)) != 0)
347 return error;
348
349 SCARG(&cupwait, wait_name) = SCARG(uap, wait_name);
350 if ((error = mach_sys_semaphore_wait_trap(l, &cupwait, retval)) != 0)
351 return error;
352
353 return 0;
354 }
355
356
357 int
358 mach_sys_semaphore_signal_thread_trap(l, v, retval)
359 struct lwp *l;
360 void *v;
361 register_t *retval;
362 {
363 struct mach_sys_semaphore_signal_thread_trap_args /* {
364 syscallarg(mach_port_name_t) signal_name;
365 syscallarg(mach_port_name_t) thread;
366 } */ *uap = v;
367 struct mach_right *mr;
368 struct mach_semaphore *ms;
369 mach_port_t mn;
370 struct mach_waiting_lwp *mwl;
371 int unblocked = 0;
372
373 /*
374 * Get the semaphore
375 */
376 mn = SCARG(uap, signal_name);
377 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
378 return EINVAL;
379
380 if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
381 return EINVAL;
382
383 ms = (struct mach_semaphore *)mr->mr_port->mp_data;
384
385 /*
386 * Get the thread, and check that it is waiting for our semaphore
387 * If no thread was supplied, pick up the first one.
388 */
389 mn = SCARG(uap, thread);
390 if (mn != 0) {
391 if ((mr = mach_right_check(mn, l,
392 MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
393 return EINVAL;
394
395 if (mr->mr_port->mp_datatype != MACH_MP_LWP)
396 return EINVAL;
397
398 lockmgr(&ms->ms_lock, LK_SHARED, NULL);
399 TAILQ_FOREACH(mwl, &ms->ms_waiting, mwl_list)
400 if (mwl->mwl_l == (struct lwp *)mr->mr_port->mp_data)
401 break;
402 } else {
403 lockmgr(&ms->ms_lock, LK_SHARED, NULL);
404 mwl = TAILQ_FIRST(&ms->ms_waiting);
405 }
406
407 /*
408 * No thread was awaiting for this semaphore,
409 * exit without touching the semaphore.
410 */
411 if (mwl == NULL) {
412 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
413 return 0; /* Should be KERN_NOT_WAITING */
414 }
415
416 lockmgr(&ms->ms_lock, LK_UPGRADE, NULL);
417 ms->ms_value++;
418 if (ms->ms_value >= 0)
419 unblocked = 1;
420 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
421
422 if (unblocked != 0)
423 wakeup(mwl);
424
425 return 0;
426 }
427
428
429 int
430 mach_sys_semaphore_signal_all_trap(l, v, retval)
431 struct lwp *l;
432 void *v;
433 register_t *retval;
434 {
435 struct mach_sys_semaphore_signal_all_trap_args /* {
436 syscallarg(mach_port_name_t) signal_name;
437 } */ *uap = v;
438 struct mach_right *mr;
439 struct mach_semaphore *ms;
440 mach_port_t mn;
441 struct mach_waiting_lwp *mwl;
442 int unblocked = 0;
443
444 /*
445 * Get the semaphore
446 */
447 mn = SCARG(uap, signal_name);
448 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
449 return EINVAL;
450
451 if (mr->mr_port->mp_datatype != MACH_MP_SEMAPHORE)
452 return EINVAL;
453
454 ms = (struct mach_semaphore *)mr->mr_port->mp_data;
455
456 lockmgr(&ms->ms_lock, LK_EXCLUSIVE, NULL);
457 ms->ms_value++;
458 if (ms->ms_value >= 0)
459 unblocked = 1;
460 lockmgr(&ms->ms_lock, LK_DOWNGRADE, NULL);
461
462 /*
463 * Wakeup all threads sleeping on it.
464 */
465 if (unblocked != 0)
466 TAILQ_FOREACH(mwl, &ms->ms_waiting, mwl_list)
467 wakeup(mwl);
468
469 lockmgr(&ms->ms_lock, LK_RELEASE, NULL);
470
471 return 0;
472 }
473
474
Cache object: fbd91450c882c3caf81f08f3d91130de
|