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