uipc_sem.c revision 1.8.2.1 1 /* $NetBSD: uipc_sem.c,v 1.8.2.1 2003/07/02 15:26:44 darrenr Exp $ */
2
3 /*-
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of Wasabi Systems, Inc.
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 /*
40 * Copyright (c) 2002 Alfred Perlstein <alfred (at) FreeBSD.org>
41 * All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 */
64
65 #include "opt_posix.h"
66
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/kernel.h>
70 #include <sys/proc.h>
71 #include <sys/lock.h>
72 #include <sys/ksem.h>
73 #include <sys/sa.h>
74 #include <sys/syscall.h>
75 #include <sys/stat.h>
76 #include <sys/malloc.h>
77 #include <sys/fcntl.h>
78
79 #include <sys/mount.h>
80
81 #include <sys/syscallargs.h>
82
83 #ifndef SEM_MAX
84 #define SEM_MAX 30
85 #endif
86
87 #define SEM_MAX_NAMELEN 14
88 #define SEM_VALUE_MAX (~0U)
89
90 #define SEM_TO_ID(x) ((intptr_t)(x))
91
92 MALLOC_DEFINE(M_SEM, "p1003_1b_sem", "p1003_1b semaphores");
93
94 /*
95 * Note: to read the ks_name member, you need either the ks_interlock
96 * or the ksem_slock. To write the ks_name member, you need both. Make
97 * sure the order is ksem_slock -> ks_interlock.
98 */
99 struct ksem {
100 LIST_ENTRY(ksem) ks_entry; /* global list entry */
101 struct simplelock ks_interlock; /* lock on this ksem */
102 char *ks_name; /* if named, this is the name */
103 unsigned int ks_ref; /* number of references */
104 mode_t ks_mode; /* protection bits */
105 uid_t ks_uid; /* creator uid */
106 gid_t ks_gid; /* creator gid */
107 unsigned int ks_value; /* current value */
108 unsigned int ks_waiters; /* number of waiters */
109 };
110
111 struct ksem_ref {
112 LIST_ENTRY(ksem_ref) ksr_list;
113 struct ksem *ksr_ksem;
114 };
115
116 struct ksem_proc {
117 struct lock kp_lock;
118 LIST_HEAD(, ksem_ref) kp_ksems;
119 };
120
121 /*
122 * ksem_slock protects ksem_head and nsems. Only named semaphores go
123 * onto ksem_head.
124 */
125 static struct simplelock ksem_slock;
126 static LIST_HEAD(, ksem) ksem_head = LIST_HEAD_INITIALIZER(&ksem_head);
127 static int nsems = 0;
128
129 static void
130 ksem_free(struct ksem *ks)
131 {
132
133 LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
134 /*
135 * If the ksem is anonymous (or has been unlinked), then
136 * this is the end if its life.
137 */
138 if (ks->ks_name == NULL) {
139 simple_unlock(&ks->ks_interlock);
140 free(ks, M_SEM);
141
142 simple_lock(&ksem_slock);
143 nsems--;
144 simple_unlock(&ksem_slock);
145 return;
146 }
147 simple_unlock(&ks->ks_interlock);
148 }
149
150 static __inline void
151 ksem_addref(struct ksem *ks)
152 {
153
154 LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
155 ks->ks_ref++;
156 KASSERT(ks->ks_ref != 0); /* XXX KDASSERT */
157 }
158
159 static __inline void
160 ksem_delref(struct ksem *ks)
161 {
162
163 LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
164 KASSERT(ks->ks_ref != 0); /* XXX KDASSERT */
165 if (--ks->ks_ref == 0) {
166 ksem_free(ks);
167 return;
168 }
169 simple_unlock(&ks->ks_interlock);
170 }
171
172 static struct ksem_proc *
173 ksem_proc_alloc(void)
174 {
175 struct ksem_proc *kp;
176
177 kp = malloc(sizeof(*kp), M_SEM, M_WAITOK);
178 lockinit(&kp->kp_lock, PWAIT, "ksproc", 0, 0);
179 LIST_INIT(&kp->kp_ksems);
180
181 return (kp);
182 }
183
184 static void
185 ksem_add_proc(struct proc *p, struct ksem *ks)
186 {
187 struct ksem_proc *kp;
188 struct ksem_ref *ksr;
189
190 if (p->p_ksems == NULL) {
191 kp = ksem_proc_alloc();
192 p->p_ksems = kp;
193 } else
194 kp = p->p_ksems;
195
196 ksr = malloc(sizeof(*ksr), M_SEM, M_WAITOK);
197 ksr->ksr_ksem = ks;
198
199 lockmgr(&kp->kp_lock, LK_EXCLUSIVE, NULL);
200 LIST_INSERT_HEAD(&kp->kp_ksems, ksr, ksr_list);
201 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
202 }
203
204 /* We MUST have a write lock on the ksem_proc list! */
205 static struct ksem_ref *
206 ksem_drop_proc(struct ksem_proc *kp, struct ksem *ks)
207 {
208 struct ksem_ref *ksr;
209
210 LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
211 LIST_FOREACH(ksr, &kp->kp_ksems, ksr_list) {
212 if (ksr->ksr_ksem == ks) {
213 ksem_delref(ks);
214 LIST_REMOVE(ksr, ksr_list);
215 return (ksr);
216 }
217 }
218 #ifdef DIAGNOSTIC
219 panic("ksem_drop_proc: ksem_proc %p ksem %p", kp, ks);
220 #endif
221 return (NULL);
222 }
223
224 static int
225 ksem_perm(struct proc *p, struct ksem *ks)
226 {
227 struct ucred *uc;
228
229 LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
230 uc = p->p_ucred;
231 if ((uc->cr_uid == ks->ks_uid && (ks->ks_mode & S_IWUSR) != 0) ||
232 (uc->cr_gid == ks->ks_gid && (ks->ks_mode & S_IWGRP) != 0) ||
233 (ks->ks_mode & S_IWOTH) != 0 || suser(uc, &p->p_acflag) == 0)
234 return (0);
235 return (EPERM);
236 }
237
238 static struct ksem *
239 ksem_lookup_byname(const char *name)
240 {
241 struct ksem *ks;
242
243 LOCK_ASSERT(simple_lock_held(&ksem_slock));
244 LIST_FOREACH(ks, &ksem_head, ks_entry) {
245 if (strcmp(ks->ks_name, name) == 0) {
246 simple_lock(&ks->ks_interlock);
247 return (ks);
248 }
249 }
250 return (NULL);
251 }
252
253 static int
254 ksem_create(struct proc *p, const char *name, struct ksem **ksret,
255 mode_t mode, unsigned int value)
256 {
257 struct ksem *ret;
258 struct ucred *uc;
259 size_t len;
260
261 uc = p->p_ucred;
262 if (value > SEM_VALUE_MAX)
263 return (EINVAL);
264 ret = malloc(sizeof(*ret), M_SEM, M_WAITOK | M_ZERO);
265 if (name != NULL) {
266 len = strlen(name);
267 if (len > SEM_MAX_NAMELEN) {
268 free(ret, M_SEM);
269 return (ENAMETOOLONG);
270 }
271 /* name must start with a '/' but not contain one. */
272 if (*name != '/' || len < 2 || strchr(name + 1, '/') != NULL) {
273 free(ret, M_SEM);
274 return (EINVAL);
275 }
276 ret->ks_name = malloc(len + 1, M_SEM, M_WAITOK);
277 strlcpy(ret->ks_name, name, len + 1);
278 } else
279 ret->ks_name = NULL;
280 ret->ks_mode = mode;
281 ret->ks_value = value;
282 ret->ks_ref = 1;
283 ret->ks_waiters = 0;
284 ret->ks_uid = uc->cr_uid;
285 ret->ks_gid = uc->cr_gid;
286 simple_lock_init(&ret->ks_interlock);
287
288 simple_lock(&ksem_slock);
289 if (nsems >= SEM_MAX) {
290 simple_unlock(&ksem_slock);
291 if (ret->ks_name != NULL)
292 free(ret->ks_name, M_SEM);
293 free(ret, M_SEM);
294 return (ENFILE);
295 }
296 nsems++;
297 simple_unlock(&ksem_slock);
298
299 *ksret = ret;
300 return (0);
301 }
302
303 int
304 sys__ksem_init(struct lwp *l, void *v, register_t *retval)
305 {
306 struct sys__ksem_init_args /* {
307 unsigned int value;
308 semid_t *idp;
309 } */ *uap = v;
310 struct ksem *ks;
311 semid_t id;
312 int error;
313
314 /* Note the mode does not matter for anonymous semaphores. */
315 error = ksem_create(l->l_proc, NULL, &ks, 0, SCARG(uap, value));
316 if (error)
317 return (error);
318 id = SEM_TO_ID(ks);
319 error = copyout(&id, SCARG(uap, idp), sizeof(id));
320 if (error) {
321 simple_lock(&ks->ks_interlock);
322 ksem_delref(ks);
323 return (error);
324 }
325
326 ksem_add_proc(l->l_proc, ks);
327
328 return (0);
329 }
330
331 int
332 sys__ksem_open(struct lwp *l, void *v, register_t *retval)
333 {
334 struct sys__ksem_open_args /* {
335 const char *name;
336 int oflag;
337 mode_t mode;
338 unsigned int value;
339 semid_t *idp;
340 } */ *uap = v;
341 char name[SEM_MAX_NAMELEN + 1];
342 size_t done;
343 int error;
344 struct ksem *ksnew, *ks;
345 semid_t id;
346
347 error = copyinstr(SCARG(uap, name), name, sizeof(name), &done);
348 if (error)
349 return (error);
350
351 ksnew = NULL;
352 simple_lock(&ksem_slock);
353 ks = ksem_lookup_byname(name);
354
355 /* Found one? */
356 if (ks != NULL) {
357 /* Check for exclusive create. */
358 if (SCARG(uap, oflag) & O_EXCL) {
359 simple_unlock(&ks->ks_interlock);
360 simple_unlock(&ksem_slock);
361 return (EEXIST);
362 }
363 found_one:
364 /*
365 * Verify permissions. If we can access it, add
366 * this process's reference.
367 */
368 LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
369 error = ksem_perm(l->l_proc, ks);
370 if (error == 0)
371 ksem_addref(ks);
372 simple_unlock(&ks->ks_interlock);
373 simple_unlock(&ksem_slock);
374 if (error)
375 return (error);
376
377 id = SEM_TO_ID(ks);
378 error = copyout(&id, SCARG(uap, idp), sizeof(id));
379 if (error) {
380 simple_lock(&ks->ks_interlock);
381 ksem_delref(ks);
382 return (error);
383 }
384
385 ksem_add_proc(l->l_proc, ks);
386
387 return (0);
388 }
389
390 /*
391 * didn't ask for creation? error.
392 */
393 if ((SCARG(uap, oflag) & O_CREAT) == 0) {
394 simple_unlock(&ksem_slock);
395 return (ENOENT);
396 }
397
398 /*
399 * We may block during creation, so drop the lock.
400 */
401 simple_unlock(&ksem_slock);
402 error = ksem_create(l->l_proc, name, &ksnew, SCARG(uap, mode),
403 SCARG(uap, value));
404 if (error != 0)
405 return (error);
406
407 id = SEM_TO_ID(ksnew);
408 error = copyout(&id, SCARG(uap, idp), sizeof(id));
409 if (error) {
410 free(ksnew->ks_name, M_SEM);
411 ksnew->ks_name = NULL;
412
413 simple_lock(&ksnew->ks_interlock);
414 ksem_delref(ksnew);
415 return (error);
416 }
417
418 /*
419 * We need to make sure we haven't lost a race while
420 * allocating during creation.
421 */
422 simple_lock(&ksem_slock);
423 if ((ks = ksem_lookup_byname(name)) != NULL) {
424 if (SCARG(uap, oflag) & O_EXCL) {
425 simple_unlock(&ks->ks_interlock);
426 simple_unlock(&ksem_slock);
427
428 free(ksnew->ks_name, M_SEM);
429 ksnew->ks_name = NULL;
430
431 simple_lock(&ksnew->ks_interlock);
432 ksem_delref(ksnew);
433 return (EEXIST);
434 }
435 goto found_one;
436 } else {
437 /* ksnew already has its initial reference. */
438 LIST_INSERT_HEAD(&ksem_head, ksnew, ks_entry);
439 simple_unlock(&ksem_slock);
440
441 ksem_add_proc(l->l_proc, ksnew);
442 }
443 return (error);
444 }
445
446 /* We must have a read lock on the ksem_proc list! */
447 static struct ksem *
448 ksem_lookup_proc(struct ksem_proc *kp, semid_t id)
449 {
450 struct ksem_ref *ksr;
451
452 LIST_FOREACH(ksr, &kp->kp_ksems, ksr_list) {
453 if (id == (semid_t) ksr->ksr_ksem) {
454 simple_lock(&ksr->ksr_ksem->ks_interlock);
455 return (ksr->ksr_ksem);
456 }
457 }
458
459 return (NULL);
460 }
461
462 int
463 sys__ksem_unlink(struct lwp *l, void *v, register_t *retval)
464 {
465 struct sys__ksem_unlink_args /* {
466 const char *name;
467 } */ *uap = v;
468 char name[SEM_MAX_NAMELEN + 1], *cp;
469 size_t done;
470 struct ksem *ks;
471 int error;
472
473 error = copyinstr(SCARG(uap, name), name, sizeof(name), &done);
474 if (error)
475 return error;
476
477 simple_lock(&ksem_slock);
478 ks = ksem_lookup_byname(name);
479 if (ks == NULL) {
480 simple_unlock(&ksem_slock);
481 return (ENOENT);
482 }
483
484 LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
485
486 LIST_REMOVE(ks, ks_entry);
487 cp = ks->ks_name;
488 ks->ks_name = NULL;
489
490 simple_unlock(&ksem_slock);
491
492 if (ks->ks_ref == 0)
493 ksem_free(ks);
494 else
495 simple_unlock(&ks->ks_interlock);
496
497 free(cp, M_SEM);
498
499 return (0);
500 }
501
502 int
503 sys__ksem_close(struct lwp *l, void *v, register_t *retval)
504 {
505 struct sys__ksem_close_args /* {
506 semid_t id;
507 } */ *uap = v;
508 struct ksem_proc *kp;
509 struct ksem_ref *ksr;
510 struct ksem *ks;
511
512 if ((kp = l->l_proc->p_ksems) == NULL)
513 return (EINVAL);
514
515 lockmgr(&kp->kp_lock, LK_EXCLUSIVE, NULL);
516
517 ks = ksem_lookup_proc(kp, SCARG(uap, id));
518 if (ks == NULL) {
519 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
520 return (EINVAL);
521 }
522
523 LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
524 if (ks->ks_name == NULL) {
525 simple_unlock(&ks->ks_interlock);
526 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
527 return (EINVAL);
528 }
529
530 ksr = ksem_drop_proc(kp, ks);
531 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
532 free(ksr, M_SEM);
533
534 return (0);
535 }
536
537 int
538 sys__ksem_post(struct lwp *l, void *v, register_t *retval)
539 {
540 struct sys__ksem_post_args /* {
541 semid_t id;
542 } */ *uap = v;
543 struct ksem_proc *kp;
544 struct ksem *ks;
545 int error;
546
547 if ((kp = l->l_proc->p_ksems) == NULL)
548 return (EINVAL);
549
550 lockmgr(&kp->kp_lock, LK_SHARED, NULL);
551 ks = ksem_lookup_proc(kp, SCARG(uap, id));
552 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
553 if (ks == NULL)
554 return (EINVAL);
555
556 LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
557 if (ks->ks_value == SEM_VALUE_MAX) {
558 error = EOVERFLOW;
559 goto out;
560 }
561 ++ks->ks_value;
562 if (ks->ks_waiters)
563 wakeup(ks);
564 error = 0;
565 out:
566 simple_unlock(&ks->ks_interlock);
567 return (error);
568 }
569
570 static int
571 ksem_wait(struct lwp *l, semid_t id, int tryflag)
572 {
573 struct ksem_proc *kp;
574 struct ksem *ks;
575 int error;
576
577 if ((kp = l->l_proc->p_ksems) == NULL)
578 return (EINVAL);
579
580 lockmgr(&kp->kp_lock, LK_SHARED, NULL);
581 ks = ksem_lookup_proc(kp, id);
582 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
583 if (ks == NULL)
584 return (EINVAL);
585
586 LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
587 ksem_addref(ks);
588 while (ks->ks_value == 0) {
589 ks->ks_waiters++;
590 error = tryflag ? EAGAIN : ltsleep(ks, PCATCH, "psem", 0,
591 &ks->ks_interlock);
592 ks->ks_waiters--;
593 if (error)
594 goto out;
595 }
596 ks->ks_value--;
597 error = 0;
598 out:
599 ksem_delref(ks);
600 return (error);
601 }
602
603 int
604 sys__ksem_wait(struct lwp *l, void *v, register_t *retval)
605 {
606 struct sys__ksem_wait_args /* {
607 semid_t id;
608 } */ *uap = v;
609
610 return ksem_wait(l, SCARG(uap, id), 0);
611 }
612
613 int
614 sys__ksem_trywait(struct lwp *l, void *v, register_t *retval)
615 {
616 struct sys__ksem_trywait_args /* {
617 semid_t id;
618 } */ *uap = v;
619
620 return ksem_wait(l, SCARG(uap, id), 1);
621 }
622
623 int
624 sys__ksem_getvalue(struct lwp *l, void *v, register_t *retval)
625 {
626 struct sys__ksem_getvalue_args /* {
627 semid_t id;
628 unsigned int *value;
629 } */ *uap = v;
630 struct ksem_proc *kp;
631 struct ksem *ks;
632 unsigned int val;
633
634 if ((kp = l->l_proc->p_ksems) == NULL)
635 return (EINVAL);
636
637 lockmgr(&kp->kp_lock, LK_SHARED, NULL);
638 ks = ksem_lookup_proc(kp, SCARG(uap, id));
639 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
640 if (ks == NULL)
641 return (EINVAL);
642
643 LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
644 val = ks->ks_value;
645 simple_unlock(&ks->ks_interlock);
646
647 return (copyout(&val, SCARG(uap, value), sizeof(val)));
648 }
649
650 int
651 sys__ksem_destroy(struct lwp *l, void *v, register_t *retval)
652 {
653 struct sys__ksem_destroy_args /*{
654 semid_t id;
655 } */ *uap = v;
656 struct ksem_proc *kp;
657 struct ksem_ref *ksr;
658 struct ksem *ks;
659
660 if ((kp = l->l_proc->p_ksems) == NULL)
661 return (EINVAL);
662
663 lockmgr(&kp->kp_lock, LK_EXCLUSIVE, NULL);
664
665 ks = ksem_lookup_proc(kp, SCARG(uap, id));
666 if (ks == NULL) {
667 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
668 return (EINVAL);
669 }
670
671 LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
672
673 /*
674 * XXX This misses named semaphores which have been unlink'd,
675 * XXX but since behavior of destroying a named semaphore is
676 * XXX undefined, this is technically allowed.
677 */
678 if (ks->ks_name != NULL) {
679 simple_unlock(&ks->ks_interlock);
680 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
681 return (EINVAL);
682 }
683
684 if (ks->ks_waiters) {
685 simple_unlock(&ks->ks_interlock);
686 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
687 return (EBUSY);
688 }
689
690 ksr = ksem_drop_proc(kp, ks);
691 lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
692 free(ksr, M_SEM);
693
694 return (0);
695 }
696
697 static void
698 ksem_forkhook(struct proc *p2, struct proc *p1)
699 {
700 struct ksem_proc *kp1, *kp2;
701 struct ksem_ref *ksr, *ksr1;
702
703 if ((kp1 = p1->p_ksems) == NULL) {
704 p2->p_ksems = NULL;
705 return;
706 }
707
708 p2->p_ksems = kp2 = ksem_proc_alloc();
709
710 lockmgr(&kp1->kp_lock, LK_SHARED, NULL);
711
712 if (!LIST_EMPTY(&kp1->kp_ksems)) {
713 LIST_FOREACH(ksr, &kp1->kp_ksems, ksr_list) {
714 ksr1 = malloc(sizeof(*ksr), M_SEM, M_WAITOK);
715 ksr1->ksr_ksem = ksr->ksr_ksem;
716 simple_lock(&ksr->ksr_ksem->ks_interlock);
717 ksem_addref(ksr->ksr_ksem);
718 simple_unlock(&ksr->ksr_ksem->ks_interlock);
719 LIST_INSERT_HEAD(&kp2->kp_ksems, ksr1, ksr_list);
720 }
721 }
722
723 lockmgr(&kp1->kp_lock, LK_RELEASE, NULL);
724 }
725
726 static void
727 ksem_exithook(struct lwp *l, void *arg)
728 {
729 struct ksem_proc *kp;
730 struct ksem_ref *ksr;
731
732 if ((kp = l->l_proc->p_ksems) == NULL)
733 return;
734
735 /* Don't bother locking; process is dying. */
736
737 while ((ksr = LIST_FIRST(&kp->kp_ksems)) != NULL) {
738 LIST_REMOVE(ksr, ksr_list);
739 simple_lock(&ksr->ksr_ksem->ks_interlock);
740 ksem_delref(ksr->ksr_ksem);
741 free(ksr, M_SEM);
742 }
743 }
744
745 void
746 ksem_init(void)
747 {
748
749 simple_lock_init(&ksem_slock);
750 exithook_establish(ksem_exithook, NULL);
751 exechook_establish(ksem_exithook, NULL);
752 forkhook_establish(ksem_forkhook);
753 }
754