1 /* $NetBSD: sysv_sem.c,v 1.41 2001/08/03 05:58:18 jdolecek Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 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 the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Implementation of SVID semaphores 42 * 43 * Author: Daniel Boulet 44 * 45 * This software is provided ``AS IS'' without any warranties of any kind. 46 */ 47 48 #define SYSVSEM 49 50 #include <sys/param.h> 51 #include <sys/kernel.h> 52 #include <sys/sem.h> 53 #include <sys/sysctl.h> 54 #include <sys/mount.h> /* XXX for <sys/syscallargs.h> */ 55 #include <sys/syscallargs.h> 56 57 int semtot = 0; 58 struct semid_ds *sema; /* semaphore id pool */ 59 struct __sem *sem; /* semaphore pool */ 60 struct sem_undo *semu_list; /* list of active undo structures */ 61 int *semu; /* undo structure pool */ 62 63 #ifdef SEM_DEBUG 64 #define SEM_PRINTF(a) printf a 65 #else 66 #define SEM_PRINTF(a) 67 #endif 68 69 struct sem_undo *semu_alloc __P((struct proc *)); 70 int semundo_adjust __P((struct proc *, struct sem_undo **, int, int, int)); 71 void semundo_clear __P((int, int)); 72 73 /* 74 * XXXSMP Once we go MP, there needs to be a lock for the semaphore system. 75 * Until then, we're saved by being a non-preemptive kernel. 76 */ 77 78 void 79 seminit() 80 { 81 int i; 82 83 if (sema == NULL) 84 panic("sema is NULL"); 85 if (semu == NULL) 86 panic("semu is NULL"); 87 88 for (i = 0; i < seminfo.semmni; i++) { 89 sema[i]._sem_base = 0; 90 sema[i].sem_perm.mode = 0; 91 } 92 for (i = 0; i < seminfo.semmnu; i++) { 93 struct sem_undo *suptr = SEMU(i); 94 suptr->un_proc = NULL; 95 } 96 semu_list = NULL; 97 } 98 99 /* 100 * Placebo. 101 */ 102 103 int 104 sys_semconfig(p, v, retval) 105 struct proc *p; 106 void *v; 107 register_t *retval; 108 { 109 *retval = 0; 110 return 0; 111 } 112 113 /* 114 * Allocate a new sem_undo structure for a process 115 * (returns ptr to structure or NULL if no more room) 116 */ 117 118 struct sem_undo * 119 semu_alloc(p) 120 struct proc *p; 121 { 122 int i; 123 struct sem_undo *suptr; 124 struct sem_undo **supptr; 125 int attempt; 126 127 /* 128 * Try twice to allocate something. 129 * (we'll purge any empty structures after the first pass so 130 * two passes are always enough) 131 */ 132 133 for (attempt = 0; attempt < 2; attempt++) { 134 /* 135 * Look for a free structure. 136 * Fill it in and return it if we find one. 137 */ 138 139 for (i = 0; i < seminfo.semmnu; i++) { 140 suptr = SEMU(i); 141 if (suptr->un_proc == NULL) { 142 suptr->un_next = semu_list; 143 semu_list = suptr; 144 suptr->un_cnt = 0; 145 suptr->un_proc = p; 146 return(suptr); 147 } 148 } 149 150 /* 151 * We didn't find a free one, if this is the first attempt 152 * then try to free some structures. 153 */ 154 155 if (attempt == 0) { 156 /* All the structures are in use - try to free some */ 157 int did_something = 0; 158 159 supptr = &semu_list; 160 while ((suptr = *supptr) != NULL) { 161 if (suptr->un_cnt == 0) { 162 suptr->un_proc = NULL; 163 *supptr = suptr->un_next; 164 did_something = 1; 165 } else 166 supptr = &(suptr->un_next); 167 } 168 169 /* If we didn't free anything then just give-up */ 170 if (!did_something) 171 return(NULL); 172 } else { 173 /* 174 * The second pass failed even though we freed 175 * something after the first pass! 176 * This is IMPOSSIBLE! 177 */ 178 panic("semu_alloc - second attempt failed"); 179 } 180 } 181 return NULL; 182 } 183 184 /* 185 * Adjust a particular entry for a particular proc 186 */ 187 188 int 189 semundo_adjust(p, supptr, semid, semnum, adjval) 190 struct proc *p; 191 struct sem_undo **supptr; 192 int semid, semnum; 193 int adjval; 194 { 195 struct sem_undo *suptr; 196 struct undo *sunptr; 197 int i; 198 199 /* Look for and remember the sem_undo if the caller doesn't provide 200 it */ 201 202 suptr = *supptr; 203 if (suptr == NULL) { 204 for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) { 205 if (suptr->un_proc == p) { 206 *supptr = suptr; 207 break; 208 } 209 } 210 if (suptr == NULL) { 211 if (adjval == 0) 212 return(0); 213 suptr = semu_alloc(p); 214 if (suptr == NULL) 215 return(ENOSPC); 216 *supptr = suptr; 217 } 218 } 219 220 /* 221 * Look for the requested entry and adjust it (delete if adjval becomes 222 * 0). 223 */ 224 sunptr = &suptr->un_ent[0]; 225 for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 226 if (sunptr->un_id != semid || sunptr->un_num != semnum) 227 continue; 228 if (adjval == 0) 229 sunptr->un_adjval = 0; 230 else 231 sunptr->un_adjval += adjval; 232 if (sunptr->un_adjval == 0) { 233 suptr->un_cnt--; 234 if (i < suptr->un_cnt) 235 suptr->un_ent[i] = 236 suptr->un_ent[suptr->un_cnt]; 237 } 238 return(0); 239 } 240 241 /* Didn't find the right entry - create it */ 242 if (adjval == 0) 243 return(0); 244 if (suptr->un_cnt == SEMUME) 245 return(EINVAL); 246 247 sunptr = &suptr->un_ent[suptr->un_cnt]; 248 suptr->un_cnt++; 249 sunptr->un_adjval = adjval; 250 sunptr->un_id = semid; 251 sunptr->un_num = semnum; 252 return(0); 253 } 254 255 void 256 semundo_clear(semid, semnum) 257 int semid, semnum; 258 { 259 struct sem_undo *suptr; 260 261 for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) { 262 struct undo *sunptr; 263 int i; 264 265 sunptr = &suptr->un_ent[0]; 266 for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 267 if (sunptr->un_id == semid) { 268 if (semnum == -1 || sunptr->un_num == semnum) { 269 suptr->un_cnt--; 270 if (i < suptr->un_cnt) { 271 suptr->un_ent[i] = 272 suptr->un_ent[suptr->un_cnt]; 273 i--, sunptr--; 274 } 275 } 276 if (semnum != -1) 277 break; 278 } 279 } 280 } 281 } 282 283 int 284 sys_____semctl13(p, v, retval) 285 struct proc *p; 286 void *v; 287 register_t *retval; 288 { 289 struct sys_____semctl13_args /* { 290 syscallarg(int) semid; 291 syscallarg(int) semnum; 292 syscallarg(int) cmd; 293 syscallarg(union __semun *) arg; 294 } */ *uap = v; 295 struct semid_ds sembuf; 296 int cmd, error; 297 void *pass_arg; 298 union __semun karg; 299 300 cmd = SCARG(uap, cmd); 301 302 switch (cmd) { 303 case IPC_SET: 304 case IPC_STAT: 305 pass_arg = &sembuf; 306 break; 307 308 case GETALL: 309 case SETVAL: 310 case SETALL: 311 pass_arg = &karg; 312 break; 313 default: 314 pass_arg = NULL; 315 break; 316 } 317 318 if (pass_arg) { 319 error = copyin(SCARG(uap, arg), &karg, sizeof(karg)); 320 if (error) 321 return error; 322 if (cmd == IPC_SET) { 323 error = copyin(karg.buf, &sembuf, sizeof(sembuf)); 324 if (error) 325 return (error); 326 } 327 } 328 329 error = semctl1(p, SCARG(uap, semid), SCARG(uap, semnum), cmd, 330 pass_arg, retval); 331 332 if (error == 0 && cmd == IPC_STAT) 333 error = copyout(&sembuf, karg.buf, sizeof(sembuf)); 334 335 return (error); 336 } 337 338 int 339 semctl1(p, semid, semnum, cmd, v, retval) 340 struct proc *p; 341 int semid, semnum, cmd; 342 void *v; 343 register_t *retval; 344 { 345 struct ucred *cred = p->p_ucred; 346 union __semun *arg = v; 347 struct semid_ds *sembuf = v, *semaptr; 348 int i, error, ix; 349 350 SEM_PRINTF(("call to semctl(%d, %d, %d, %p)\n", 351 semid, semnum, cmd, v)); 352 353 ix = IPCID_TO_IX(semid); 354 if (ix < 0 || ix >= seminfo.semmsl) 355 return (EINVAL); 356 357 semaptr = &sema[ix]; 358 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || 359 semaptr->sem_perm._seq != IPCID_TO_SEQ(semid)) 360 return (EINVAL); 361 362 switch (cmd) { 363 case IPC_RMID: 364 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M)) != 0) 365 return (error); 366 semaptr->sem_perm.cuid = cred->cr_uid; 367 semaptr->sem_perm.uid = cred->cr_uid; 368 semtot -= semaptr->sem_nsems; 369 for (i = semaptr->_sem_base - sem; i < semtot; i++) 370 sem[i] = sem[i + semaptr->sem_nsems]; 371 for (i = 0; i < seminfo.semmni; i++) { 372 if ((sema[i].sem_perm.mode & SEM_ALLOC) && 373 sema[i]._sem_base > semaptr->_sem_base) 374 sema[i]._sem_base -= semaptr->sem_nsems; 375 } 376 semaptr->sem_perm.mode = 0; 377 semundo_clear(ix, -1); 378 wakeup(semaptr); 379 break; 380 381 case IPC_SET: 382 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M))) 383 return (error); 384 semaptr->sem_perm.uid = sembuf->sem_perm.uid; 385 semaptr->sem_perm.gid = sembuf->sem_perm.gid; 386 semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) | 387 (sembuf->sem_perm.mode & 0777); 388 semaptr->sem_ctime = time.tv_sec; 389 break; 390 391 case IPC_STAT: 392 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 393 return (error); 394 memcpy(sembuf, semaptr, sizeof(struct semid_ds)); 395 break; 396 397 case GETNCNT: 398 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 399 return (error); 400 if (semnum < 0 || semnum >= semaptr->sem_nsems) 401 return (EINVAL); 402 *retval = semaptr->_sem_base[semnum].semncnt; 403 break; 404 405 case GETPID: 406 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 407 return (error); 408 if (semnum < 0 || semnum >= semaptr->sem_nsems) 409 return (EINVAL); 410 *retval = semaptr->_sem_base[semnum].sempid; 411 break; 412 413 case GETVAL: 414 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 415 return (error); 416 if (semnum < 0 || semnum >= semaptr->sem_nsems) 417 return (EINVAL); 418 *retval = semaptr->_sem_base[semnum].semval; 419 break; 420 421 case GETALL: 422 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 423 return (error); 424 for (i = 0; i < semaptr->sem_nsems; i++) { 425 error = copyout(&semaptr->_sem_base[i].semval, 426 &arg->array[i], sizeof(arg->array[i])); 427 if (error != 0) 428 break; 429 } 430 break; 431 432 case GETZCNT: 433 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 434 return (error); 435 if (semnum < 0 || semnum >= semaptr->sem_nsems) 436 return (EINVAL); 437 *retval = semaptr->_sem_base[semnum].semzcnt; 438 break; 439 440 case SETVAL: 441 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W))) 442 return (error); 443 if (semnum < 0 || semnum >= semaptr->sem_nsems) 444 return (EINVAL); 445 semaptr->_sem_base[semnum].semval = arg->val; 446 semundo_clear(ix, semnum); 447 wakeup(semaptr); 448 break; 449 450 case SETALL: 451 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W))) 452 return (error); 453 for (i = 0; i < semaptr->sem_nsems; i++) { 454 error = copyin(&arg->array[i], 455 &semaptr->_sem_base[i].semval, 456 sizeof(arg->array[i])); 457 if (error != 0) 458 break; 459 } 460 semundo_clear(ix, -1); 461 wakeup(semaptr); 462 break; 463 464 default: 465 return (EINVAL); 466 } 467 468 return (error); 469 } 470 471 int 472 sys_semget(p, v, retval) 473 struct proc *p; 474 void *v; 475 register_t *retval; 476 { 477 struct sys_semget_args /* { 478 syscallarg(key_t) key; 479 syscallarg(int) nsems; 480 syscallarg(int) semflg; 481 } */ *uap = v; 482 int semid, eval; 483 int key = SCARG(uap, key); 484 int nsems = SCARG(uap, nsems); 485 int semflg = SCARG(uap, semflg); 486 struct ucred *cred = p->p_ucred; 487 488 SEM_PRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); 489 490 if (key != IPC_PRIVATE) { 491 for (semid = 0; semid < seminfo.semmni; semid++) { 492 if ((sema[semid].sem_perm.mode & SEM_ALLOC) && 493 sema[semid].sem_perm._key == key) 494 break; 495 } 496 if (semid < seminfo.semmni) { 497 SEM_PRINTF(("found public key\n")); 498 if ((eval = ipcperm(cred, &sema[semid].sem_perm, 499 semflg & 0700))) 500 return(eval); 501 if (nsems > 0 && sema[semid].sem_nsems < nsems) { 502 SEM_PRINTF(("too small\n")); 503 return(EINVAL); 504 } 505 if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 506 SEM_PRINTF(("not exclusive\n")); 507 return(EEXIST); 508 } 509 goto found; 510 } 511 } 512 513 SEM_PRINTF(("need to allocate the semid_ds\n")); 514 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 515 if (nsems <= 0 || nsems > seminfo.semmsl) { 516 SEM_PRINTF(("nsems out of range (0<%d<=%d)\n", nsems, 517 seminfo.semmsl)); 518 return(EINVAL); 519 } 520 if (nsems > seminfo.semmns - semtot) { 521 SEM_PRINTF(("not enough semaphores left (need %d, got %d)\n", 522 nsems, seminfo.semmns - semtot)); 523 return(ENOSPC); 524 } 525 for (semid = 0; semid < seminfo.semmni; semid++) { 526 if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0) 527 break; 528 } 529 if (semid == seminfo.semmni) { 530 SEM_PRINTF(("no more semid_ds's available\n")); 531 return(ENOSPC); 532 } 533 SEM_PRINTF(("semid %d is available\n", semid)); 534 sema[semid].sem_perm._key = key; 535 sema[semid].sem_perm.cuid = cred->cr_uid; 536 sema[semid].sem_perm.uid = cred->cr_uid; 537 sema[semid].sem_perm.cgid = cred->cr_gid; 538 sema[semid].sem_perm.gid = cred->cr_gid; 539 sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 540 sema[semid].sem_perm._seq = 541 (sema[semid].sem_perm._seq + 1) & 0x7fff; 542 sema[semid].sem_nsems = nsems; 543 sema[semid].sem_otime = 0; 544 sema[semid].sem_ctime = time.tv_sec; 545 sema[semid]._sem_base = &sem[semtot]; 546 semtot += nsems; 547 memset(sema[semid]._sem_base, 0, 548 sizeof(sema[semid]._sem_base[0])*nsems); 549 SEM_PRINTF(("sembase = %p, next = %p\n", sema[semid]._sem_base, 550 &sem[semtot])); 551 } else { 552 SEM_PRINTF(("didn't find it and wasn't asked to create it\n")); 553 return(ENOENT); 554 } 555 556 found: 557 *retval = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm); 558 return(0); 559 } 560 561 int 562 sys_semop(p, v, retval) 563 struct proc *p; 564 void *v; 565 register_t *retval; 566 { 567 struct sys_semop_args /* { 568 syscallarg(int) semid; 569 syscallarg(struct sembuf *) sops; 570 syscallarg(size_t) nsops; 571 } */ *uap = v; 572 int semid = SCARG(uap, semid); 573 size_t nsops = SCARG(uap, nsops); 574 struct sembuf sops[MAX_SOPS]; 575 struct semid_ds *semaptr; 576 struct sembuf *sopptr = NULL; 577 struct __sem *semptr = NULL; 578 struct sem_undo *suptr = NULL; 579 struct ucred *cred = p->p_ucred; 580 int i, j, eval; 581 int do_wakeup, do_undos; 582 583 SEM_PRINTF(("call to semop(%d, %p, %d)\n", semid, sops, nsops)); 584 585 semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 586 587 if (semid < 0 || semid >= seminfo.semmsl) 588 return(EINVAL); 589 590 semaptr = &sema[semid]; 591 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || 592 semaptr->sem_perm._seq != IPCID_TO_SEQ(SCARG(uap, semid))) 593 return(EINVAL); 594 595 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) { 596 SEM_PRINTF(("eval = %d from ipaccess\n", eval)); 597 return(eval); 598 } 599 600 if (nsops > MAX_SOPS) { 601 SEM_PRINTF(("too many sops (max=%d, nsops=%d)\n", MAX_SOPS, nsops)); 602 return(E2BIG); 603 } 604 605 if ((eval = copyin(SCARG(uap, sops), sops, nsops * sizeof(sops[0]))) 606 != 0) { 607 SEM_PRINTF(("eval = %d from copyin(%p, %p, %d)\n", eval, 608 SCARG(uap, sops), &sops, nsops * sizeof(sops[0]))); 609 return(eval); 610 } 611 612 /* 613 * Loop trying to satisfy the vector of requests. 614 * If we reach a point where we must wait, any requests already 615 * performed are rolled back and we go to sleep until some other 616 * process wakes us up. At this point, we start all over again. 617 * 618 * This ensures that from the perspective of other tasks, a set 619 * of requests is atomic (never partially satisfied). 620 */ 621 do_undos = 0; 622 623 for (;;) { 624 do_wakeup = 0; 625 626 for (i = 0; i < nsops; i++) { 627 sopptr = &sops[i]; 628 629 if (sopptr->sem_num >= semaptr->sem_nsems) 630 return(EFBIG); 631 632 semptr = &semaptr->_sem_base[sopptr->sem_num]; 633 634 SEM_PRINTF(("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n", 635 semaptr, semaptr->_sem_base, semptr, 636 sopptr->sem_num, semptr->semval, sopptr->sem_op, 637 (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait")); 638 639 if (sopptr->sem_op < 0) { 640 if ((int)(semptr->semval + 641 sopptr->sem_op) < 0) { 642 SEM_PRINTF(("semop: can't do it now\n")); 643 break; 644 } else { 645 semptr->semval += sopptr->sem_op; 646 if (semptr->semval == 0 && 647 semptr->semzcnt > 0) 648 do_wakeup = 1; 649 } 650 if (sopptr->sem_flg & SEM_UNDO) 651 do_undos = 1; 652 } else if (sopptr->sem_op == 0) { 653 if (semptr->semval > 0) { 654 SEM_PRINTF(("semop: not zero now\n")); 655 break; 656 } 657 } else { 658 if (semptr->semncnt > 0) 659 do_wakeup = 1; 660 semptr->semval += sopptr->sem_op; 661 if (sopptr->sem_flg & SEM_UNDO) 662 do_undos = 1; 663 } 664 } 665 666 /* 667 * Did we get through the entire vector? 668 */ 669 if (i >= nsops) 670 goto done; 671 672 /* 673 * No ... rollback anything that we've already done 674 */ 675 SEM_PRINTF(("semop: rollback 0 through %d\n", i-1)); 676 for (j = 0; j < i; j++) 677 semaptr->_sem_base[sops[j].sem_num].semval -= 678 sops[j].sem_op; 679 680 /* 681 * If the request that we couldn't satisfy has the 682 * NOWAIT flag set then return with EAGAIN. 683 */ 684 if (sopptr->sem_flg & IPC_NOWAIT) 685 return(EAGAIN); 686 687 if (sopptr->sem_op == 0) 688 semptr->semzcnt++; 689 else 690 semptr->semncnt++; 691 692 SEM_PRINTF(("semop: good night!\n")); 693 eval = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH, 694 "semwait", 0); 695 SEM_PRINTF(("semop: good morning (eval=%d)!\n", eval)); 696 697 suptr = NULL; /* sem_undo may have been reallocated */ 698 699 if (eval != 0) 700 return(EINTR); 701 SEM_PRINTF(("semop: good morning!\n")); 702 703 /* 704 * Make sure that the semaphore still exists 705 */ 706 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || 707 semaptr->sem_perm._seq != IPCID_TO_SEQ(SCARG(uap, semid))) { 708 /* The man page says to return EIDRM. */ 709 /* Unfortunately, BSD doesn't define that code! */ 710 #ifdef EIDRM 711 return(EIDRM); 712 #else 713 return(EINVAL); 714 #endif 715 } 716 717 /* 718 * The semaphore is still alive. Readjust the count of 719 * waiting processes. 720 */ 721 if (sopptr->sem_op == 0) 722 semptr->semzcnt--; 723 else 724 semptr->semncnt--; 725 } 726 727 done: 728 /* 729 * Process any SEM_UNDO requests. 730 */ 731 if (do_undos) { 732 for (i = 0; i < nsops; i++) { 733 /* 734 * We only need to deal with SEM_UNDO's for non-zero 735 * op's. 736 */ 737 int adjval; 738 739 if ((sops[i].sem_flg & SEM_UNDO) == 0) 740 continue; 741 adjval = sops[i].sem_op; 742 if (adjval == 0) 743 continue; 744 eval = semundo_adjust(p, &suptr, semid, 745 sops[i].sem_num, -adjval); 746 if (eval == 0) 747 continue; 748 749 /* 750 * Oh-Oh! We ran out of either sem_undo's or undo's. 751 * Rollback the adjustments to this point and then 752 * rollback the semaphore ups and down so we can return 753 * with an error with all structures restored. We 754 * rollback the undo's in the exact reverse order that 755 * we applied them. This guarantees that we won't run 756 * out of space as we roll things back out. 757 */ 758 for (j = i - 1; j >= 0; j--) { 759 if ((sops[j].sem_flg & SEM_UNDO) == 0) 760 continue; 761 adjval = sops[j].sem_op; 762 if (adjval == 0) 763 continue; 764 if (semundo_adjust(p, &suptr, semid, 765 sops[j].sem_num, adjval) != 0) 766 panic("semop - can't undo undos"); 767 } 768 769 for (j = 0; j < nsops; j++) 770 semaptr->_sem_base[sops[j].sem_num].semval -= 771 sops[j].sem_op; 772 773 SEM_PRINTF(("eval = %d from semundo_adjust\n", eval)); 774 return(eval); 775 } /* loop through the sops */ 776 } /* if (do_undos) */ 777 778 /* We're definitely done - set the sempid's */ 779 for (i = 0; i < nsops; i++) { 780 sopptr = &sops[i]; 781 semptr = &semaptr->_sem_base[sopptr->sem_num]; 782 semptr->sempid = p->p_pid; 783 } 784 785 /* Do a wakeup if any semaphore was up'd. */ 786 if (do_wakeup) { 787 SEM_PRINTF(("semop: doing wakeup\n")); 788 #ifdef SEM_WAKEUP 789 sem_wakeup((caddr_t)semaptr); 790 #else 791 wakeup((caddr_t)semaptr); 792 #endif 793 SEM_PRINTF(("semop: back from wakeup\n")); 794 } 795 SEM_PRINTF(("semop: done\n")); 796 *retval = 0; 797 return(0); 798 } 799 800 /* 801 * Go through the undo structures for this process and apply the adjustments to 802 * semaphores. 803 */ 804 void 805 semexit(p) 806 struct proc *p; 807 { 808 struct sem_undo *suptr; 809 struct sem_undo **supptr; 810 811 /* 812 * Go through the chain of undo vectors looking for one associated with 813 * this process. 814 */ 815 816 for (supptr = &semu_list; (suptr = *supptr) != NULL; 817 supptr = &suptr->un_next) { 818 if (suptr->un_proc == p) 819 break; 820 } 821 822 /* 823 * If there is no undo vector, skip to the end. 824 */ 825 826 if (suptr == NULL) 827 return; 828 829 /* 830 * We now have an undo vector for this process. 831 */ 832 833 SEM_PRINTF(("proc @%p has undo structure with %d entries\n", p, 834 suptr->un_cnt)); 835 836 /* 837 * If there are any active undo elements then process them. 838 */ 839 if (suptr->un_cnt > 0) { 840 int ix; 841 842 for (ix = 0; ix < suptr->un_cnt; ix++) { 843 int semid = suptr->un_ent[ix].un_id; 844 int semnum = suptr->un_ent[ix].un_num; 845 int adjval = suptr->un_ent[ix].un_adjval; 846 struct semid_ds *semaptr; 847 848 semaptr = &sema[semid]; 849 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) 850 panic("semexit - semid not allocated"); 851 if (semnum >= semaptr->sem_nsems) 852 panic("semexit - semnum out of range"); 853 854 SEM_PRINTF(("semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n", 855 suptr->un_proc, suptr->un_ent[ix].un_id, 856 suptr->un_ent[ix].un_num, 857 suptr->un_ent[ix].un_adjval, 858 semaptr->_sem_base[semnum].semval)); 859 860 if (adjval < 0 && 861 semaptr->_sem_base[semnum].semval < -adjval) 862 semaptr->_sem_base[semnum].semval = 0; 863 else 864 semaptr->_sem_base[semnum].semval += adjval; 865 866 #ifdef SEM_WAKEUP 867 sem_wakeup((caddr_t)semaptr); 868 #else 869 wakeup((caddr_t)semaptr); 870 #endif 871 SEM_PRINTF(("semexit: back from wakeup\n")); 872 } 873 } 874 875 /* 876 * Deallocate the undo vector. 877 */ 878 SEM_PRINTF(("removing vector\n")); 879 suptr->un_proc = NULL; 880 *supptr = suptr->un_next; 881 } 882