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