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