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@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