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