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