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