1 /* $NetBSD: uipc_sem.c,v 1.40 2013/03/29 01:08:17 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Mindaugas Rasiukevicius. 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 2002 Alfred Perlstein <alfred@FreeBSD.org> 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 */ 57 58 /* 59 * Implementation of POSIX semaphore. 60 */ 61 62 #include <sys/cdefs.h> 63 __KERNEL_RCSID(0, "$NetBSD: uipc_sem.c,v 1.40 2013/03/29 01:08:17 christos Exp $"); 64 65 #include <sys/param.h> 66 #include <sys/kernel.h> 67 68 #include <sys/atomic.h> 69 #include <sys/proc.h> 70 #include <sys/ksem.h> 71 #include <sys/syscall.h> 72 #include <sys/stat.h> 73 #include <sys/kmem.h> 74 #include <sys/fcntl.h> 75 #include <sys/file.h> 76 #include <sys/filedesc.h> 77 #include <sys/kauth.h> 78 #include <sys/module.h> 79 #include <sys/mount.h> 80 #include <sys/syscall.h> 81 #include <sys/syscallargs.h> 82 #include <sys/syscallvar.h> 83 84 MODULE(MODULE_CLASS_MISC, ksem, NULL); 85 86 #define SEM_MAX_NAMELEN 14 87 #define SEM_VALUE_MAX (~0U) 88 89 #define KS_UNLINKED 0x01 90 91 static kmutex_t ksem_lock __cacheline_aligned; 92 static LIST_HEAD(,ksem) ksem_head __cacheline_aligned; 93 static u_int nsems_total __cacheline_aligned; 94 static u_int nsems __cacheline_aligned; 95 96 static kauth_listener_t ksem_listener; 97 98 static int ksem_sysinit(void); 99 static int ksem_sysfini(bool); 100 static int ksem_modcmd(modcmd_t, void *); 101 static int ksem_close_fop(file_t *); 102 static int ksem_stat_fop(file_t *, struct stat *); 103 static int ksem_read_fop(file_t *, off_t *, struct uio *, 104 kauth_cred_t, int); 105 106 static const struct fileops semops = { 107 .fo_read = ksem_read_fop, 108 .fo_write = fbadop_write, 109 .fo_ioctl = fbadop_ioctl, 110 .fo_fcntl = fnullop_fcntl, 111 .fo_poll = fnullop_poll, 112 .fo_stat = ksem_stat_fop, 113 .fo_close = ksem_close_fop, 114 .fo_kqfilter = fnullop_kqfilter, 115 .fo_restart = fnullop_restart, 116 }; 117 118 static const struct syscall_package ksem_syscalls[] = { 119 { SYS__ksem_init, 0, (sy_call_t *)sys__ksem_init }, 120 { SYS__ksem_open, 0, (sy_call_t *)sys__ksem_open }, 121 { SYS__ksem_unlink, 0, (sy_call_t *)sys__ksem_unlink }, 122 { SYS__ksem_close, 0, (sy_call_t *)sys__ksem_close }, 123 { SYS__ksem_post, 0, (sy_call_t *)sys__ksem_post }, 124 { SYS__ksem_wait, 0, (sy_call_t *)sys__ksem_wait }, 125 { SYS__ksem_trywait, 0, (sy_call_t *)sys__ksem_trywait }, 126 { SYS__ksem_getvalue, 0, (sy_call_t *)sys__ksem_getvalue }, 127 { SYS__ksem_destroy, 0, (sy_call_t *)sys__ksem_destroy }, 128 { SYS__ksem_timedwait, 0, (sy_call_t *)sys__ksem_timedwait }, 129 { 0, 0, NULL }, 130 }; 131 132 static int 133 ksem_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, 134 void *arg0, void *arg1, void *arg2, void *arg3) 135 { 136 ksem_t *ks; 137 mode_t mode; 138 139 if (action != KAUTH_SYSTEM_SEMAPHORE) 140 return KAUTH_RESULT_DEFER; 141 142 ks = arg1; 143 mode = ks->ks_mode; 144 145 if ((kauth_cred_geteuid(cred) == ks->ks_uid && (mode & S_IWUSR) != 0) || 146 (kauth_cred_getegid(cred) == ks->ks_gid && (mode & S_IWGRP) != 0) || 147 (mode & S_IWOTH) != 0) 148 return KAUTH_RESULT_ALLOW; 149 150 return KAUTH_RESULT_DEFER; 151 } 152 153 static int 154 ksem_sysinit(void) 155 { 156 int error; 157 158 mutex_init(&ksem_lock, MUTEX_DEFAULT, IPL_NONE); 159 LIST_INIT(&ksem_head); 160 nsems_total = 0; 161 nsems = 0; 162 163 error = syscall_establish(NULL, ksem_syscalls); 164 if (error) { 165 (void)ksem_sysfini(false); 166 } 167 168 ksem_listener = kauth_listen_scope(KAUTH_SCOPE_SYSTEM, 169 ksem_listener_cb, NULL); 170 171 return error; 172 } 173 174 static int 175 ksem_sysfini(bool interface) 176 { 177 int error; 178 179 if (interface) { 180 error = syscall_disestablish(NULL, ksem_syscalls); 181 if (error != 0) { 182 return error; 183 } 184 /* 185 * Make sure that no semaphores are in use. Note: semops 186 * must be unused at this point. 187 */ 188 if (nsems_total) { 189 error = syscall_establish(NULL, ksem_syscalls); 190 KASSERT(error == 0); 191 return EBUSY; 192 } 193 } 194 kauth_unlisten_scope(ksem_listener); 195 mutex_destroy(&ksem_lock); 196 return 0; 197 } 198 199 static int 200 ksem_modcmd(modcmd_t cmd, void *arg) 201 { 202 203 switch (cmd) { 204 case MODULE_CMD_INIT: 205 return ksem_sysinit(); 206 207 case MODULE_CMD_FINI: 208 return ksem_sysfini(true); 209 210 default: 211 return ENOTTY; 212 } 213 } 214 215 static ksem_t * 216 ksem_lookup(const char *name) 217 { 218 ksem_t *ks; 219 220 KASSERT(mutex_owned(&ksem_lock)); 221 222 LIST_FOREACH(ks, &ksem_head, ks_entry) { 223 if (strcmp(ks->ks_name, name) == 0) { 224 mutex_enter(&ks->ks_lock); 225 return ks; 226 } 227 } 228 return NULL; 229 } 230 231 static int 232 ksem_perm(lwp_t *l, ksem_t *ks) 233 { 234 kauth_cred_t uc = l->l_cred; 235 236 KASSERT(mutex_owned(&ks->ks_lock)); 237 238 if (kauth_authorize_system(uc, KAUTH_SYSTEM_SEMAPHORE, 0, ks, NULL, NULL) != 0) 239 return EACCES; 240 241 return 0; 242 } 243 244 /* 245 * ksem_get: get the semaphore from the descriptor. 246 * 247 * => locks the semaphore, if found. 248 * => holds a reference on the file descriptor. 249 */ 250 static int 251 ksem_get(int fd, ksem_t **ksret) 252 { 253 ksem_t *ks; 254 file_t *fp; 255 256 fp = fd_getfile(fd); 257 if (__predict_false(fp == NULL)) 258 return EINVAL; 259 if (__predict_false(fp->f_type != DTYPE_SEM)) { 260 fd_putfile(fd); 261 return EINVAL; 262 } 263 ks = fp->f_data; 264 mutex_enter(&ks->ks_lock); 265 266 *ksret = ks; 267 return 0; 268 } 269 270 /* 271 * ksem_create: allocate and setup a new semaphore structure. 272 */ 273 static int 274 ksem_create(lwp_t *l, const char *name, ksem_t **ksret, mode_t mode, u_int val) 275 { 276 ksem_t *ks; 277 kauth_cred_t uc; 278 char *kname; 279 size_t len; 280 281 /* Pre-check for the limit. */ 282 if (nsems >= ksem_max) { 283 return ENFILE; 284 } 285 286 if (val > SEM_VALUE_MAX) { 287 return EINVAL; 288 } 289 290 if (name != NULL) { 291 len = strlen(name); 292 if (len > SEM_MAX_NAMELEN) { 293 return ENAMETOOLONG; 294 } 295 /* Name must start with a '/' but not contain one. */ 296 if (*name != '/' || len < 2 || strchr(name + 1, '/') != NULL) { 297 return EINVAL; 298 } 299 kname = kmem_alloc(++len, KM_SLEEP); 300 strlcpy(kname, name, len); 301 } else { 302 kname = NULL; 303 len = 0; 304 } 305 306 ks = kmem_zalloc(sizeof(ksem_t), KM_SLEEP); 307 mutex_init(&ks->ks_lock, MUTEX_DEFAULT, IPL_NONE); 308 cv_init(&ks->ks_cv, "psem"); 309 ks->ks_name = kname; 310 ks->ks_namelen = len; 311 ks->ks_mode = mode; 312 ks->ks_value = val; 313 ks->ks_ref = 1; 314 315 uc = l->l_cred; 316 ks->ks_uid = kauth_cred_geteuid(uc); 317 ks->ks_gid = kauth_cred_getegid(uc); 318 319 atomic_inc_uint(&nsems_total); 320 *ksret = ks; 321 return 0; 322 } 323 324 static void 325 ksem_free(ksem_t *ks) 326 { 327 328 KASSERT(!cv_has_waiters(&ks->ks_cv)); 329 330 if (ks->ks_name) { 331 KASSERT(ks->ks_namelen > 0); 332 kmem_free(ks->ks_name, ks->ks_namelen); 333 } 334 mutex_destroy(&ks->ks_lock); 335 cv_destroy(&ks->ks_cv); 336 kmem_free(ks, sizeof(ksem_t)); 337 338 atomic_dec_uint(&nsems_total); 339 } 340 341 int 342 sys__ksem_init(struct lwp *l, const struct sys__ksem_init_args *uap, 343 register_t *retval) 344 { 345 /* { 346 unsigned int value; 347 intptr_t *idp; 348 } */ 349 350 return do_ksem_init(l, SCARG(uap, value), SCARG(uap, idp), copyout); 351 } 352 353 int 354 do_ksem_init(lwp_t *l, u_int val, intptr_t *idp, copyout_t docopyout) 355 { 356 proc_t *p = l->l_proc; 357 ksem_t *ks; 358 file_t *fp; 359 intptr_t id; 360 int fd, error; 361 362 error = fd_allocfile(&fp, &fd); 363 if (error) { 364 return error; 365 } 366 fp->f_type = DTYPE_SEM; 367 fp->f_flag = FREAD | FWRITE; 368 fp->f_ops = &semops; 369 370 id = (intptr_t)fd; 371 error = (*docopyout)(&id, idp, sizeof(*idp)); 372 if (error) { 373 fd_abort(p, fp, fd); 374 return error; 375 } 376 377 /* Note the mode does not matter for anonymous semaphores. */ 378 error = ksem_create(l, NULL, &ks, 0, val); 379 if (error) { 380 fd_abort(p, fp, fd); 381 return error; 382 } 383 fp->f_data = ks; 384 fd_affix(p, fp, fd); 385 return error; 386 } 387 388 int 389 sys__ksem_open(struct lwp *l, const struct sys__ksem_open_args *uap, 390 register_t *retval) 391 { 392 /* { 393 const char *name; 394 int oflag; 395 mode_t mode; 396 unsigned int value; 397 intptr_t *idp; 398 } */ 399 400 return do_ksem_open(l, SCARG(uap, name), SCARG(uap, oflag), 401 SCARG(uap, mode), SCARG(uap, value), SCARG(uap, idp), copyout); 402 } 403 404 int 405 do_ksem_open(struct lwp *l, const char *semname, int oflag, mode_t mode, 406 unsigned int value, intptr_t *idp, copyout_t docopyout) 407 { 408 char name[SEM_MAX_NAMELEN + 1]; 409 proc_t *p = l->l_proc; 410 ksem_t *ksnew = NULL, *ks; 411 file_t *fp; 412 intptr_t id; 413 int fd, error; 414 415 error = copyinstr(semname, name, sizeof(name), NULL); 416 if (error) { 417 return error; 418 } 419 error = fd_allocfile(&fp, &fd); 420 if (error) { 421 return error; 422 } 423 fp->f_type = DTYPE_SEM; 424 fp->f_flag = FREAD | FWRITE; 425 fp->f_ops = &semops; 426 427 /* 428 * The ID (file descriptor number) can be stored early. 429 * Note that zero is a special value for libpthread. 430 */ 431 id = (intptr_t)fd; 432 error = (*docopyout)(&id, idp, sizeof(*idp)); 433 if (error) { 434 goto err; 435 } 436 437 if (oflag & O_CREAT) { 438 /* Create a new semaphore. */ 439 error = ksem_create(l, name, &ksnew, mode, value); 440 if (error) { 441 goto err; 442 } 443 KASSERT(ksnew != NULL); 444 } 445 446 /* Lookup for a semaphore with such name. */ 447 mutex_enter(&ksem_lock); 448 ks = ksem_lookup(name); 449 if (ks) { 450 KASSERT(mutex_owned(&ks->ks_lock)); 451 mutex_exit(&ksem_lock); 452 453 /* Check for exclusive create. */ 454 if (oflag & O_EXCL) { 455 mutex_exit(&ks->ks_lock); 456 error = EEXIST; 457 goto err; 458 } 459 /* 460 * Verify permissions. If we can access it, 461 * add the reference of this thread. 462 */ 463 error = ksem_perm(l, ks); 464 if (error == 0) { 465 ks->ks_ref++; 466 } 467 mutex_exit(&ks->ks_lock); 468 if (error) { 469 goto err; 470 } 471 } else { 472 /* Fail if not found and not creating. */ 473 if ((oflag & O_CREAT) == 0) { 474 mutex_exit(&ksem_lock); 475 KASSERT(ksnew == NULL); 476 error = ENOENT; 477 goto err; 478 } 479 480 /* Check for the limit locked. */ 481 if (nsems >= ksem_max) { 482 mutex_exit(&ksem_lock); 483 error = ENFILE; 484 goto err; 485 } 486 487 /* 488 * Finally, insert semaphore into the list. 489 * Note: it already has the initial reference. 490 */ 491 ks = ksnew; 492 LIST_INSERT_HEAD(&ksem_head, ks, ks_entry); 493 nsems++; 494 mutex_exit(&ksem_lock); 495 496 ksnew = NULL; 497 } 498 KASSERT(ks != NULL); 499 fp->f_data = ks; 500 fd_affix(p, fp, fd); 501 err: 502 if (error) { 503 fd_abort(p, fp, fd); 504 } 505 if (ksnew) { 506 ksem_free(ksnew); 507 } 508 return error; 509 } 510 511 int 512 sys__ksem_close(struct lwp *l, const struct sys__ksem_close_args *uap, 513 register_t *retval) 514 { 515 /* { 516 intptr_t id; 517 } */ 518 int fd = (int)SCARG(uap, id); 519 520 if (fd_getfile(fd) == NULL) { 521 return EBADF; 522 } 523 return fd_close(fd); 524 } 525 526 static int 527 ksem_read_fop(file_t *fp, off_t *offset, struct uio *uio, kauth_cred_t cred, 528 int flags) 529 { 530 size_t len; 531 char *name; 532 ksem_t *ks = fp->f_data; 533 534 mutex_enter(&ks->ks_lock); 535 len = ks->ks_namelen; 536 name = ks->ks_name; 537 mutex_exit(&ks->ks_lock); 538 if (name == NULL || len == 0) 539 return 0; 540 return uiomove(name, len, uio); 541 } 542 543 static int 544 ksem_stat_fop(file_t *fp, struct stat *ub) 545 { 546 ksem_t *ks = fp->f_data; 547 548 mutex_enter(&ks->ks_lock); 549 550 memset(ub, 0, sizeof(*ub)); 551 552 ub->st_mode = ks->ks_mode | ((ks->ks_name && ks->ks_namelen) 553 ? _S_IFLNK : _S_IFREG); 554 ub->st_uid = ks->ks_uid; 555 ub->st_gid = ks->ks_gid; 556 ub->st_size = ks->ks_value; 557 ub->st_blocks = (ub->st_size) ? 1 : 0; 558 ub->st_nlink = ks->ks_ref; 559 ub->st_blksize = 4096; 560 561 nanotime(&ub->st_atimespec); 562 ub->st_mtimespec = ub->st_ctimespec = ub->st_birthtimespec = 563 ub->st_atimespec; 564 565 /* 566 * Left as 0: st_dev, st_ino, st_rdev, st_flags, st_gen. 567 * XXX (st_dev, st_ino) should be unique. 568 */ 569 mutex_exit(&ks->ks_lock); 570 return 0; 571 } 572 573 static int 574 ksem_close_fop(file_t *fp) 575 { 576 ksem_t *ks = fp->f_data; 577 bool destroy = false; 578 579 mutex_enter(&ks->ks_lock); 580 KASSERT(ks->ks_ref > 0); 581 if (--ks->ks_ref == 0) { 582 /* 583 * Destroy if the last reference and semaphore is unnamed, 584 * or unlinked (for named semaphore). 585 */ 586 destroy = (ks->ks_flags & KS_UNLINKED) || (ks->ks_name == NULL); 587 } 588 mutex_exit(&ks->ks_lock); 589 590 if (destroy) { 591 ksem_free(ks); 592 } 593 return 0; 594 } 595 596 int 597 sys__ksem_unlink(struct lwp *l, const struct sys__ksem_unlink_args *uap, 598 register_t *retval) 599 { 600 /* { 601 const char *name; 602 } */ 603 char name[SEM_MAX_NAMELEN + 1]; 604 ksem_t *ks; 605 u_int refcnt; 606 int error; 607 608 error = copyinstr(SCARG(uap, name), name, sizeof(name), NULL); 609 if (error) 610 return error; 611 612 mutex_enter(&ksem_lock); 613 ks = ksem_lookup(name); 614 if (ks == NULL) { 615 mutex_exit(&ksem_lock); 616 return ENOENT; 617 } 618 KASSERT(mutex_owned(&ks->ks_lock)); 619 620 /* Verify permissions. */ 621 error = ksem_perm(l, ks); 622 if (error) { 623 mutex_exit(&ks->ks_lock); 624 mutex_exit(&ksem_lock); 625 return error; 626 } 627 628 /* Remove from the global list. */ 629 LIST_REMOVE(ks, ks_entry); 630 nsems--; 631 mutex_exit(&ksem_lock); 632 633 refcnt = ks->ks_ref; 634 if (refcnt) { 635 /* Mark as unlinked, if there are references. */ 636 ks->ks_flags |= KS_UNLINKED; 637 } 638 mutex_exit(&ks->ks_lock); 639 640 if (refcnt == 0) { 641 ksem_free(ks); 642 } 643 return 0; 644 } 645 646 int 647 sys__ksem_post(struct lwp *l, const struct sys__ksem_post_args *uap, 648 register_t *retval) 649 { 650 /* { 651 intptr_t id; 652 } */ 653 int fd = (int)SCARG(uap, id), error; 654 ksem_t *ks; 655 656 error = ksem_get(fd, &ks); 657 if (error) { 658 return error; 659 } 660 KASSERT(mutex_owned(&ks->ks_lock)); 661 if (ks->ks_value == SEM_VALUE_MAX) { 662 error = EOVERFLOW; 663 goto out; 664 } 665 ks->ks_value++; 666 if (ks->ks_waiters) { 667 cv_broadcast(&ks->ks_cv); 668 } 669 out: 670 mutex_exit(&ks->ks_lock); 671 fd_putfile(fd); 672 return error; 673 } 674 675 int 676 do_ksem_wait(lwp_t *l, intptr_t id, bool try, struct timespec *abstime) 677 { 678 int fd = (int)id, error, timeo; 679 ksem_t *ks; 680 681 error = ksem_get(fd, &ks); 682 if (error) { 683 return error; 684 } 685 KASSERT(mutex_owned(&ks->ks_lock)); 686 while (ks->ks_value == 0) { 687 ks->ks_waiters++; 688 if (!try && abstime != NULL) { 689 error = ts2timo(CLOCK_REALTIME, TIMER_ABSTIME, abstime, 690 &timeo, NULL); 691 if (error != 0) 692 goto out; 693 } else { 694 timeo = 0; 695 } 696 error = try ? EAGAIN : cv_timedwait_sig(&ks->ks_cv, 697 &ks->ks_lock, timeo); 698 ks->ks_waiters--; 699 if (error) 700 goto out; 701 } 702 ks->ks_value--; 703 out: 704 mutex_exit(&ks->ks_lock); 705 fd_putfile(fd); 706 return error; 707 } 708 709 int 710 sys__ksem_wait(struct lwp *l, const struct sys__ksem_wait_args *uap, 711 register_t *retval) 712 { 713 /* { 714 intptr_t id; 715 } */ 716 717 return do_ksem_wait(l, SCARG(uap, id), false, NULL); 718 } 719 720 int 721 sys__ksem_timedwait(struct lwp *l, const struct sys__ksem_timedwait_args *uap, 722 register_t *retval) 723 { 724 /* { 725 intptr_t id; 726 const struct timespec *abstime; 727 } */ 728 struct timespec ts; 729 int error; 730 731 error = copyin(SCARG(uap, abstime), &ts, sizeof(ts)); 732 if (error != 0) 733 return error; 734 735 if (ts.tv_sec < 0 || ts.tv_nsec < 0 || ts.tv_nsec >= 1000000000) 736 return EINVAL; 737 738 error = do_ksem_wait(l, SCARG(uap, id), false, &ts); 739 if (error == EWOULDBLOCK) 740 error = ETIMEDOUT; 741 return error; 742 } 743 744 int 745 sys__ksem_trywait(struct lwp *l, const struct sys__ksem_trywait_args *uap, 746 register_t *retval) 747 { 748 /* { 749 intptr_t id; 750 } */ 751 752 return do_ksem_wait(l, SCARG(uap, id), true, NULL); 753 } 754 755 int 756 sys__ksem_getvalue(struct lwp *l, const struct sys__ksem_getvalue_args *uap, 757 register_t *retval) 758 { 759 /* { 760 intptr_t id; 761 unsigned int *value; 762 } */ 763 int fd = (int)SCARG(uap, id), error; 764 ksem_t *ks; 765 unsigned int val; 766 767 error = ksem_get(fd, &ks); 768 if (error) { 769 return error; 770 } 771 KASSERT(mutex_owned(&ks->ks_lock)); 772 val = ks->ks_value; 773 mutex_exit(&ks->ks_lock); 774 fd_putfile(fd); 775 776 return copyout(&val, SCARG(uap, value), sizeof(val)); 777 } 778 779 int 780 sys__ksem_destroy(struct lwp *l, const struct sys__ksem_destroy_args *uap, 781 register_t *retval) 782 { 783 /* { 784 intptr_t id; 785 } */ 786 int fd = (int)SCARG(uap, id), error; 787 ksem_t *ks; 788 789 error = ksem_get(fd, &ks); 790 if (error) { 791 return error; 792 } 793 KASSERT(mutex_owned(&ks->ks_lock)); 794 795 /* Operation is only for unnamed semaphores. */ 796 if (ks->ks_name != NULL) { 797 error = EINVAL; 798 goto out; 799 } 800 /* Cannot destroy if there are waiters. */ 801 if (ks->ks_waiters) { 802 error = EBUSY; 803 goto out; 804 } 805 out: 806 mutex_exit(&ks->ks_lock); 807 if (error) { 808 fd_putfile(fd); 809 return error; 810 } 811 return fd_close(fd); 812 } 813