289semundo_clear(semid, semnum) 290 int semid, semnum; 291{ 292 register struct sem_undo *suptr; 293 294 for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) { 295 register struct undo *sunptr = &suptr->un_ent[0]; 296 register int i = 0; 297 298 while (i < suptr->un_cnt) { 299 if (sunptr->un_id == semid) { 300 if (semnum == -1 || sunptr->un_num == semnum) { 301 suptr->un_cnt--; 302 if (i < suptr->un_cnt) { 303 suptr->un_ent[i] = 304 suptr->un_ent[suptr->un_cnt]; 305 continue; 306 } 307 } 308 if (semnum != -1) 309 break; 310 } 311 i++, sunptr++; 312 } 313 } 314} 315 316struct semctl_args { 317 int semid; 318 int semnum; 319 int cmd; 320 union semun *arg; 321}; 322 323static int 324semctl(p, uap, retval) 325 struct proc *p; 326 register struct semctl_args *uap; 327 int *retval; 328{ 329 int semid = uap->semid; 330 int semnum = uap->semnum; 331 int cmd = uap->cmd; 332 union semun *arg = uap->arg; 333 union semun real_arg; 334 struct ucred *cred = p->p_ucred; 335 int i, rval, eval; 336 struct semid_ds sbuf; 337 register struct semid_ds *semaptr; 338 339#ifdef SEM_DEBUG 340 printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg); 341#endif 342 343 semid = IPCID_TO_IX(semid); 344 if (semid < 0 || semid >= seminfo.semmsl) 345 return(EINVAL); 346 347 semaptr = &sema[semid]; 348 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || 349 semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) 350 return(EINVAL); 351 352 eval = 0; 353 rval = 0; 354 355 switch (cmd) { 356 case IPC_RMID: 357 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M))) 358 return(eval); 359 semaptr->sem_perm.cuid = cred->cr_uid; 360 semaptr->sem_perm.uid = cred->cr_uid; 361 semtot -= semaptr->sem_nsems; 362 for (i = semaptr->sem_base - sem; i < semtot; i++) 363 sem[i] = sem[i + semaptr->sem_nsems]; 364 for (i = 0; i < seminfo.semmni; i++) { 365 if ((sema[i].sem_perm.mode & SEM_ALLOC) && 366 sema[i].sem_base > semaptr->sem_base) 367 sema[i].sem_base -= semaptr->sem_nsems; 368 } 369 semaptr->sem_perm.mode = 0; 370 semundo_clear(semid, -1); 371 wakeup((caddr_t)semaptr); 372 break; 373 374 case IPC_SET: 375 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M))) 376 return(eval); 377 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 378 return(eval); 379 if ((eval = copyin(real_arg.buf, (caddr_t)&sbuf, 380 sizeof(sbuf))) != 0) 381 return(eval); 382 semaptr->sem_perm.uid = sbuf.sem_perm.uid; 383 semaptr->sem_perm.gid = sbuf.sem_perm.gid; 384 semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) | 385 (sbuf.sem_perm.mode & 0777); 386 semaptr->sem_ctime = time.tv_sec; 387 break; 388 389 case IPC_STAT: 390 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 391 return(eval); 392 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 393 return(eval); 394 eval = copyout((caddr_t)semaptr, real_arg.buf, 395 sizeof(struct semid_ds)); 396 break; 397 398 case GETNCNT: 399 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 400 return(eval); 401 if (semnum < 0 || semnum >= semaptr->sem_nsems) 402 return(EINVAL); 403 rval = semaptr->sem_base[semnum].semncnt; 404 break; 405 406 case GETPID: 407 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 408 return(eval); 409 if (semnum < 0 || semnum >= semaptr->sem_nsems) 410 return(EINVAL); 411 rval = semaptr->sem_base[semnum].sempid; 412 break; 413 414 case GETVAL: 415 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 416 return(eval); 417 if (semnum < 0 || semnum >= semaptr->sem_nsems) 418 return(EINVAL); 419 rval = semaptr->sem_base[semnum].semval; 420 break; 421 422 case GETALL: 423 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 424 return(eval); 425 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 426 return(eval); 427 for (i = 0; i < semaptr->sem_nsems; i++) { 428 eval = copyout((caddr_t)&semaptr->sem_base[i].semval, 429 &real_arg.array[i], sizeof(real_arg.array[0])); 430 if (eval != 0) 431 break; 432 } 433 break; 434 435 case GETZCNT: 436 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 437 return(eval); 438 if (semnum < 0 || semnum >= semaptr->sem_nsems) 439 return(EINVAL); 440 rval = semaptr->sem_base[semnum].semzcnt; 441 break; 442 443 case SETVAL: 444 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) 445 return(eval); 446 if (semnum < 0 || semnum >= semaptr->sem_nsems) 447 return(EINVAL); 448 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 449 return(eval); 450 semaptr->sem_base[semnum].semval = real_arg.val; 451 semundo_clear(semid, semnum); 452 wakeup((caddr_t)semaptr); 453 break; 454 455 case SETALL: 456 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) 457 return(eval); 458 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 459 return(eval); 460 for (i = 0; i < semaptr->sem_nsems; i++) { 461 eval = copyin(&real_arg.array[i], 462 (caddr_t)&semaptr->sem_base[i].semval, 463 sizeof(real_arg.array[0])); 464 if (eval != 0) 465 break; 466 } 467 semundo_clear(semid, -1); 468 wakeup((caddr_t)semaptr); 469 break; 470 471 default: 472 return(EINVAL); 473 } 474 475 if (eval == 0) 476 *retval = rval; 477 return(eval); 478} 479 480struct semget_args { 481 key_t key; 482 int nsems; 483 int semflg; 484}; 485 486static int 487semget(p, uap, retval) 488 struct proc *p; 489 register struct semget_args *uap; 490 int *retval; 491{ 492 int semid, eval; 493 int key = uap->key; 494 int nsems = uap->nsems; 495 int semflg = uap->semflg; 496 struct ucred *cred = p->p_ucred; 497 498#ifdef SEM_DEBUG 499 printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg); 500#endif 501 502 if (key != IPC_PRIVATE) { 503 for (semid = 0; semid < seminfo.semmni; semid++) { 504 if ((sema[semid].sem_perm.mode & SEM_ALLOC) && 505 sema[semid].sem_perm.key == key) 506 break; 507 } 508 if (semid < seminfo.semmni) { 509#ifdef SEM_DEBUG 510 printf("found public key\n"); 511#endif 512 if ((eval = ipcperm(cred, &sema[semid].sem_perm, 513 semflg & 0700))) 514 return(eval); 515 if (nsems > 0 && sema[semid].sem_nsems < nsems) { 516#ifdef SEM_DEBUG 517 printf("too small\n"); 518#endif 519 return(EINVAL); 520 } 521 if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 522#ifdef SEM_DEBUG 523 printf("not exclusive\n"); 524#endif 525 return(EEXIST); 526 } 527 goto found; 528 } 529 } 530 531#ifdef SEM_DEBUG 532 printf("need to allocate the semid_ds\n"); 533#endif 534 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 535 if (nsems <= 0 || nsems > seminfo.semmsl) { 536#ifdef SEM_DEBUG 537 printf("nsems out of range (0<%d<=%d)\n", nsems, 538 seminfo.semmsl); 539#endif 540 return(EINVAL); 541 } 542 if (nsems > seminfo.semmns - semtot) { 543#ifdef SEM_DEBUG 544 printf("not enough semaphores left (need %d, got %d)\n", 545 nsems, seminfo.semmns - semtot); 546#endif 547 return(ENOSPC); 548 } 549 for (semid = 0; semid < seminfo.semmni; semid++) { 550 if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0) 551 break; 552 } 553 if (semid == seminfo.semmni) { 554#ifdef SEM_DEBUG 555 printf("no more semid_ds's available\n"); 556#endif 557 return(ENOSPC); 558 } 559#ifdef SEM_DEBUG 560 printf("semid %d is available\n", semid); 561#endif 562 sema[semid].sem_perm.key = key; 563 sema[semid].sem_perm.cuid = cred->cr_uid; 564 sema[semid].sem_perm.uid = cred->cr_uid; 565 sema[semid].sem_perm.cgid = cred->cr_gid; 566 sema[semid].sem_perm.gid = cred->cr_gid; 567 sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 568 sema[semid].sem_perm.seq = 569 (sema[semid].sem_perm.seq + 1) & 0x7fff; 570 sema[semid].sem_nsems = nsems; 571 sema[semid].sem_otime = 0; 572 sema[semid].sem_ctime = time.tv_sec; 573 sema[semid].sem_base = &sem[semtot]; 574 semtot += nsems; 575 bzero(sema[semid].sem_base, 576 sizeof(sema[semid].sem_base[0])*nsems); 577#ifdef SEM_DEBUG 578 printf("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base, 579 &sem[semtot]); 580#endif 581 } else { 582#ifdef SEM_DEBUG 583 printf("didn't find it and wasn't asked to create it\n"); 584#endif 585 return(ENOENT); 586 } 587 588found: 589 *retval = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm); 590 return(0); 591} 592 593struct semop_args { 594 int semid; 595 struct sembuf *sops; 596 int nsops; 597}; 598 599static int 600semop(p, uap, retval) 601 struct proc *p; 602 register struct semop_args *uap; 603 int *retval; 604{ 605 int semid = uap->semid; 606 int nsops = uap->nsops; 607 struct sembuf sops[MAX_SOPS]; 608 register struct semid_ds *semaptr; 609 register struct sembuf *sopptr; 610 register struct sem *semptr; 611 struct sem_undo *suptr = NULL; 612 struct ucred *cred = p->p_ucred; 613 int i, j, eval; 614 int do_wakeup, do_undos; 615 616#ifdef SEM_DEBUG 617 printf("call to semop(%d, 0x%x, %d)\n", semid, sops, nsops); 618#endif 619 620 semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 621 622 if (semid < 0 || semid >= seminfo.semmsl) 623 return(EINVAL); 624 625 semaptr = &sema[semid]; 626 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) 627 return(EINVAL); 628 if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) 629 return(EINVAL); 630 631 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) { 632#ifdef SEM_DEBUG 633 printf("eval = %d from ipaccess\n", eval); 634#endif 635 return(eval); 636 } 637 638 if (nsops > MAX_SOPS) { 639#ifdef SEM_DEBUG 640 printf("too many sops (max=%d, nsops=%d)\n", MAX_SOPS, nsops); 641#endif 642 return(E2BIG); 643 } 644 645 if ((eval = copyin(uap->sops, &sops, nsops * sizeof(sops[0]))) != 0) { 646#ifdef SEM_DEBUG 647 printf("eval = %d from copyin(%08x, %08x, %d)\n", eval, 648 uap->sops, &sops, nsops * sizeof(sops[0])); 649#endif 650 return(eval); 651 } 652 653 /* 654 * Loop trying to satisfy the vector of requests. 655 * If we reach a point where we must wait, any requests already 656 * performed are rolled back and we go to sleep until some other 657 * process wakes us up. At this point, we start all over again. 658 * 659 * This ensures that from the perspective of other tasks, a set 660 * of requests is atomic (never partially satisfied). 661 */ 662 do_undos = 0; 663 664 for (;;) { 665 do_wakeup = 0; 666 667 for (i = 0; i < nsops; i++) { 668 sopptr = &sops[i]; 669 670 if (sopptr->sem_num >= semaptr->sem_nsems) 671 return(EFBIG); 672 673 semptr = &semaptr->sem_base[sopptr->sem_num]; 674 675#ifdef SEM_DEBUG 676 printf("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n", 677 semaptr, semaptr->sem_base, semptr, 678 sopptr->sem_num, semptr->semval, sopptr->sem_op, 679 (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait"); 680#endif 681 682 if (sopptr->sem_op < 0) { 683 if (semptr->semval + sopptr->sem_op < 0) { 684#ifdef SEM_DEBUG 685 printf("semop: can't do it now\n"); 686#endif 687 break; 688 } else { 689 semptr->semval += sopptr->sem_op; 690 if (semptr->semval == 0 && 691 semptr->semzcnt > 0) 692 do_wakeup = 1; 693 } 694 if (sopptr->sem_flg & SEM_UNDO) 695 do_undos = 1; 696 } else if (sopptr->sem_op == 0) { 697 if (semptr->semval > 0) { 698#ifdef SEM_DEBUG 699 printf("semop: not zero now\n"); 700#endif 701 break; 702 } 703 } else { 704 if (semptr->semncnt > 0) 705 do_wakeup = 1; 706 semptr->semval += sopptr->sem_op; 707 if (sopptr->sem_flg & SEM_UNDO) 708 do_undos = 1; 709 } 710 } 711 712 /* 713 * Did we get through the entire vector? 714 */ 715 if (i >= nsops) 716 goto done; 717 718 /* 719 * No ... rollback anything that we've already done 720 */ 721#ifdef SEM_DEBUG 722 printf("semop: rollback 0 through %d\n", i-1); 723#endif 724 for (j = 0; j < i; j++) 725 semaptr->sem_base[sops[j].sem_num].semval -= 726 sops[j].sem_op; 727 728 /* 729 * If the request that we couldn't satisfy has the 730 * NOWAIT flag set then return with EAGAIN. 731 */ 732 if (sopptr->sem_flg & IPC_NOWAIT) 733 return(EAGAIN); 734 735 if (sopptr->sem_op == 0) 736 semptr->semzcnt++; 737 else 738 semptr->semncnt++; 739 740#ifdef SEM_DEBUG 741 printf("semop: good night!\n"); 742#endif 743 eval = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH, 744 "semwait", 0); 745#ifdef SEM_DEBUG 746 printf("semop: good morning (eval=%d)!\n", eval); 747#endif 748 749 suptr = NULL; /* sem_undo may have been reallocated */ 750 751 if (eval != 0) 752 return(EINTR); 753#ifdef SEM_DEBUG 754 printf("semop: good morning!\n"); 755#endif 756 757 /* 758 * Make sure that the semaphore still exists 759 */ 760 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || 761 semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) { 762 /* The man page says to return EIDRM. */ 763 /* Unfortunately, BSD doesn't define that code! */ 764#ifdef EIDRM 765 return(EIDRM); 766#else 767 return(EINVAL); 768#endif 769 } 770 771 /* 772 * The semaphore is still alive. Readjust the count of 773 * waiting processes. 774 */ 775 if (sopptr->sem_op == 0) 776 semptr->semzcnt--; 777 else 778 semptr->semncnt--; 779 } 780 781done: 782 /* 783 * Process any SEM_UNDO requests. 784 */ 785 if (do_undos) { 786 for (i = 0; i < nsops; i++) { 787 /* 788 * We only need to deal with SEM_UNDO's for non-zero 789 * op's. 790 */ 791 int adjval; 792 793 if ((sops[i].sem_flg & SEM_UNDO) == 0) 794 continue; 795 adjval = sops[i].sem_op; 796 if (adjval == 0) 797 continue; 798 eval = semundo_adjust(p, &suptr, semid, 799 sops[i].sem_num, -adjval); 800 if (eval == 0) 801 continue; 802 803 /* 804 * Oh-Oh! We ran out of either sem_undo's or undo's. 805 * Rollback the adjustments to this point and then 806 * rollback the semaphore ups and down so we can return 807 * with an error with all structures restored. We 808 * rollback the undo's in the exact reverse order that 809 * we applied them. This guarantees that we won't run 810 * out of space as we roll things back out. 811 */ 812 for (j = i - 1; j >= 0; j--) { 813 if ((sops[j].sem_flg & SEM_UNDO) == 0) 814 continue; 815 adjval = sops[j].sem_op; 816 if (adjval == 0) 817 continue; 818 if (semundo_adjust(p, &suptr, semid, 819 sops[j].sem_num, adjval) != 0) 820 panic("semop - can't undo undos"); 821 } 822 823 for (j = 0; j < nsops; j++) 824 semaptr->sem_base[sops[j].sem_num].semval -= 825 sops[j].sem_op; 826 827#ifdef SEM_DEBUG 828 printf("eval = %d from semundo_adjust\n", eval); 829#endif 830 return(eval); 831 } /* loop through the sops */ 832 } /* if (do_undos) */ 833 834 /* We're definitely done - set the sempid's */ 835 for (i = 0; i < nsops; i++) { 836 sopptr = &sops[i]; 837 semptr = &semaptr->sem_base[sopptr->sem_num]; 838 semptr->sempid = p->p_pid; 839 } 840 841 /* Do a wakeup if any semaphore was up'd. */ 842 if (do_wakeup) { 843#ifdef SEM_DEBUG 844 printf("semop: doing wakeup\n"); 845#ifdef SEM_WAKEUP 846 sem_wakeup((caddr_t)semaptr); 847#else 848 wakeup((caddr_t)semaptr); 849#endif 850 printf("semop: back from wakeup\n"); 851#else 852 wakeup((caddr_t)semaptr); 853#endif 854 } 855#ifdef SEM_DEBUG 856 printf("semop: done\n"); 857#endif 858 *retval = 0; 859 return(0); 860} 861 862/* 863 * Go through the undo structures for this process and apply the adjustments to 864 * semaphores. 865 */
| 291semundo_clear(semid, semnum) 292 int semid, semnum; 293{ 294 register struct sem_undo *suptr; 295 296 for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) { 297 register struct undo *sunptr = &suptr->un_ent[0]; 298 register int i = 0; 299 300 while (i < suptr->un_cnt) { 301 if (sunptr->un_id == semid) { 302 if (semnum == -1 || sunptr->un_num == semnum) { 303 suptr->un_cnt--; 304 if (i < suptr->un_cnt) { 305 suptr->un_ent[i] = 306 suptr->un_ent[suptr->un_cnt]; 307 continue; 308 } 309 } 310 if (semnum != -1) 311 break; 312 } 313 i++, sunptr++; 314 } 315 } 316} 317 318struct semctl_args { 319 int semid; 320 int semnum; 321 int cmd; 322 union semun *arg; 323}; 324 325static int 326semctl(p, uap, retval) 327 struct proc *p; 328 register struct semctl_args *uap; 329 int *retval; 330{ 331 int semid = uap->semid; 332 int semnum = uap->semnum; 333 int cmd = uap->cmd; 334 union semun *arg = uap->arg; 335 union semun real_arg; 336 struct ucred *cred = p->p_ucred; 337 int i, rval, eval; 338 struct semid_ds sbuf; 339 register struct semid_ds *semaptr; 340 341#ifdef SEM_DEBUG 342 printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg); 343#endif 344 345 semid = IPCID_TO_IX(semid); 346 if (semid < 0 || semid >= seminfo.semmsl) 347 return(EINVAL); 348 349 semaptr = &sema[semid]; 350 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || 351 semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) 352 return(EINVAL); 353 354 eval = 0; 355 rval = 0; 356 357 switch (cmd) { 358 case IPC_RMID: 359 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M))) 360 return(eval); 361 semaptr->sem_perm.cuid = cred->cr_uid; 362 semaptr->sem_perm.uid = cred->cr_uid; 363 semtot -= semaptr->sem_nsems; 364 for (i = semaptr->sem_base - sem; i < semtot; i++) 365 sem[i] = sem[i + semaptr->sem_nsems]; 366 for (i = 0; i < seminfo.semmni; i++) { 367 if ((sema[i].sem_perm.mode & SEM_ALLOC) && 368 sema[i].sem_base > semaptr->sem_base) 369 sema[i].sem_base -= semaptr->sem_nsems; 370 } 371 semaptr->sem_perm.mode = 0; 372 semundo_clear(semid, -1); 373 wakeup((caddr_t)semaptr); 374 break; 375 376 case IPC_SET: 377 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M))) 378 return(eval); 379 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 380 return(eval); 381 if ((eval = copyin(real_arg.buf, (caddr_t)&sbuf, 382 sizeof(sbuf))) != 0) 383 return(eval); 384 semaptr->sem_perm.uid = sbuf.sem_perm.uid; 385 semaptr->sem_perm.gid = sbuf.sem_perm.gid; 386 semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) | 387 (sbuf.sem_perm.mode & 0777); 388 semaptr->sem_ctime = time.tv_sec; 389 break; 390 391 case IPC_STAT: 392 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 393 return(eval); 394 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 395 return(eval); 396 eval = copyout((caddr_t)semaptr, real_arg.buf, 397 sizeof(struct semid_ds)); 398 break; 399 400 case GETNCNT: 401 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 402 return(eval); 403 if (semnum < 0 || semnum >= semaptr->sem_nsems) 404 return(EINVAL); 405 rval = semaptr->sem_base[semnum].semncnt; 406 break; 407 408 case GETPID: 409 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 410 return(eval); 411 if (semnum < 0 || semnum >= semaptr->sem_nsems) 412 return(EINVAL); 413 rval = semaptr->sem_base[semnum].sempid; 414 break; 415 416 case GETVAL: 417 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 418 return(eval); 419 if (semnum < 0 || semnum >= semaptr->sem_nsems) 420 return(EINVAL); 421 rval = semaptr->sem_base[semnum].semval; 422 break; 423 424 case GETALL: 425 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 426 return(eval); 427 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 428 return(eval); 429 for (i = 0; i < semaptr->sem_nsems; i++) { 430 eval = copyout((caddr_t)&semaptr->sem_base[i].semval, 431 &real_arg.array[i], sizeof(real_arg.array[0])); 432 if (eval != 0) 433 break; 434 } 435 break; 436 437 case GETZCNT: 438 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 439 return(eval); 440 if (semnum < 0 || semnum >= semaptr->sem_nsems) 441 return(EINVAL); 442 rval = semaptr->sem_base[semnum].semzcnt; 443 break; 444 445 case SETVAL: 446 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) 447 return(eval); 448 if (semnum < 0 || semnum >= semaptr->sem_nsems) 449 return(EINVAL); 450 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 451 return(eval); 452 semaptr->sem_base[semnum].semval = real_arg.val; 453 semundo_clear(semid, semnum); 454 wakeup((caddr_t)semaptr); 455 break; 456 457 case SETALL: 458 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) 459 return(eval); 460 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 461 return(eval); 462 for (i = 0; i < semaptr->sem_nsems; i++) { 463 eval = copyin(&real_arg.array[i], 464 (caddr_t)&semaptr->sem_base[i].semval, 465 sizeof(real_arg.array[0])); 466 if (eval != 0) 467 break; 468 } 469 semundo_clear(semid, -1); 470 wakeup((caddr_t)semaptr); 471 break; 472 473 default: 474 return(EINVAL); 475 } 476 477 if (eval == 0) 478 *retval = rval; 479 return(eval); 480} 481 482struct semget_args { 483 key_t key; 484 int nsems; 485 int semflg; 486}; 487 488static int 489semget(p, uap, retval) 490 struct proc *p; 491 register struct semget_args *uap; 492 int *retval; 493{ 494 int semid, eval; 495 int key = uap->key; 496 int nsems = uap->nsems; 497 int semflg = uap->semflg; 498 struct ucred *cred = p->p_ucred; 499 500#ifdef SEM_DEBUG 501 printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg); 502#endif 503 504 if (key != IPC_PRIVATE) { 505 for (semid = 0; semid < seminfo.semmni; semid++) { 506 if ((sema[semid].sem_perm.mode & SEM_ALLOC) && 507 sema[semid].sem_perm.key == key) 508 break; 509 } 510 if (semid < seminfo.semmni) { 511#ifdef SEM_DEBUG 512 printf("found public key\n"); 513#endif 514 if ((eval = ipcperm(cred, &sema[semid].sem_perm, 515 semflg & 0700))) 516 return(eval); 517 if (nsems > 0 && sema[semid].sem_nsems < nsems) { 518#ifdef SEM_DEBUG 519 printf("too small\n"); 520#endif 521 return(EINVAL); 522 } 523 if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 524#ifdef SEM_DEBUG 525 printf("not exclusive\n"); 526#endif 527 return(EEXIST); 528 } 529 goto found; 530 } 531 } 532 533#ifdef SEM_DEBUG 534 printf("need to allocate the semid_ds\n"); 535#endif 536 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 537 if (nsems <= 0 || nsems > seminfo.semmsl) { 538#ifdef SEM_DEBUG 539 printf("nsems out of range (0<%d<=%d)\n", nsems, 540 seminfo.semmsl); 541#endif 542 return(EINVAL); 543 } 544 if (nsems > seminfo.semmns - semtot) { 545#ifdef SEM_DEBUG 546 printf("not enough semaphores left (need %d, got %d)\n", 547 nsems, seminfo.semmns - semtot); 548#endif 549 return(ENOSPC); 550 } 551 for (semid = 0; semid < seminfo.semmni; semid++) { 552 if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0) 553 break; 554 } 555 if (semid == seminfo.semmni) { 556#ifdef SEM_DEBUG 557 printf("no more semid_ds's available\n"); 558#endif 559 return(ENOSPC); 560 } 561#ifdef SEM_DEBUG 562 printf("semid %d is available\n", semid); 563#endif 564 sema[semid].sem_perm.key = key; 565 sema[semid].sem_perm.cuid = cred->cr_uid; 566 sema[semid].sem_perm.uid = cred->cr_uid; 567 sema[semid].sem_perm.cgid = cred->cr_gid; 568 sema[semid].sem_perm.gid = cred->cr_gid; 569 sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 570 sema[semid].sem_perm.seq = 571 (sema[semid].sem_perm.seq + 1) & 0x7fff; 572 sema[semid].sem_nsems = nsems; 573 sema[semid].sem_otime = 0; 574 sema[semid].sem_ctime = time.tv_sec; 575 sema[semid].sem_base = &sem[semtot]; 576 semtot += nsems; 577 bzero(sema[semid].sem_base, 578 sizeof(sema[semid].sem_base[0])*nsems); 579#ifdef SEM_DEBUG 580 printf("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base, 581 &sem[semtot]); 582#endif 583 } else { 584#ifdef SEM_DEBUG 585 printf("didn't find it and wasn't asked to create it\n"); 586#endif 587 return(ENOENT); 588 } 589 590found: 591 *retval = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm); 592 return(0); 593} 594 595struct semop_args { 596 int semid; 597 struct sembuf *sops; 598 int nsops; 599}; 600 601static int 602semop(p, uap, retval) 603 struct proc *p; 604 register struct semop_args *uap; 605 int *retval; 606{ 607 int semid = uap->semid; 608 int nsops = uap->nsops; 609 struct sembuf sops[MAX_SOPS]; 610 register struct semid_ds *semaptr; 611 register struct sembuf *sopptr; 612 register struct sem *semptr; 613 struct sem_undo *suptr = NULL; 614 struct ucred *cred = p->p_ucred; 615 int i, j, eval; 616 int do_wakeup, do_undos; 617 618#ifdef SEM_DEBUG 619 printf("call to semop(%d, 0x%x, %d)\n", semid, sops, nsops); 620#endif 621 622 semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 623 624 if (semid < 0 || semid >= seminfo.semmsl) 625 return(EINVAL); 626 627 semaptr = &sema[semid]; 628 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) 629 return(EINVAL); 630 if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) 631 return(EINVAL); 632 633 if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) { 634#ifdef SEM_DEBUG 635 printf("eval = %d from ipaccess\n", eval); 636#endif 637 return(eval); 638 } 639 640 if (nsops > MAX_SOPS) { 641#ifdef SEM_DEBUG 642 printf("too many sops (max=%d, nsops=%d)\n", MAX_SOPS, nsops); 643#endif 644 return(E2BIG); 645 } 646 647 if ((eval = copyin(uap->sops, &sops, nsops * sizeof(sops[0]))) != 0) { 648#ifdef SEM_DEBUG 649 printf("eval = %d from copyin(%08x, %08x, %d)\n", eval, 650 uap->sops, &sops, nsops * sizeof(sops[0])); 651#endif 652 return(eval); 653 } 654 655 /* 656 * Loop trying to satisfy the vector of requests. 657 * If we reach a point where we must wait, any requests already 658 * performed are rolled back and we go to sleep until some other 659 * process wakes us up. At this point, we start all over again. 660 * 661 * This ensures that from the perspective of other tasks, a set 662 * of requests is atomic (never partially satisfied). 663 */ 664 do_undos = 0; 665 666 for (;;) { 667 do_wakeup = 0; 668 669 for (i = 0; i < nsops; i++) { 670 sopptr = &sops[i]; 671 672 if (sopptr->sem_num >= semaptr->sem_nsems) 673 return(EFBIG); 674 675 semptr = &semaptr->sem_base[sopptr->sem_num]; 676 677#ifdef SEM_DEBUG 678 printf("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n", 679 semaptr, semaptr->sem_base, semptr, 680 sopptr->sem_num, semptr->semval, sopptr->sem_op, 681 (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait"); 682#endif 683 684 if (sopptr->sem_op < 0) { 685 if (semptr->semval + sopptr->sem_op < 0) { 686#ifdef SEM_DEBUG 687 printf("semop: can't do it now\n"); 688#endif 689 break; 690 } else { 691 semptr->semval += sopptr->sem_op; 692 if (semptr->semval == 0 && 693 semptr->semzcnt > 0) 694 do_wakeup = 1; 695 } 696 if (sopptr->sem_flg & SEM_UNDO) 697 do_undos = 1; 698 } else if (sopptr->sem_op == 0) { 699 if (semptr->semval > 0) { 700#ifdef SEM_DEBUG 701 printf("semop: not zero now\n"); 702#endif 703 break; 704 } 705 } else { 706 if (semptr->semncnt > 0) 707 do_wakeup = 1; 708 semptr->semval += sopptr->sem_op; 709 if (sopptr->sem_flg & SEM_UNDO) 710 do_undos = 1; 711 } 712 } 713 714 /* 715 * Did we get through the entire vector? 716 */ 717 if (i >= nsops) 718 goto done; 719 720 /* 721 * No ... rollback anything that we've already done 722 */ 723#ifdef SEM_DEBUG 724 printf("semop: rollback 0 through %d\n", i-1); 725#endif 726 for (j = 0; j < i; j++) 727 semaptr->sem_base[sops[j].sem_num].semval -= 728 sops[j].sem_op; 729 730 /* 731 * If the request that we couldn't satisfy has the 732 * NOWAIT flag set then return with EAGAIN. 733 */ 734 if (sopptr->sem_flg & IPC_NOWAIT) 735 return(EAGAIN); 736 737 if (sopptr->sem_op == 0) 738 semptr->semzcnt++; 739 else 740 semptr->semncnt++; 741 742#ifdef SEM_DEBUG 743 printf("semop: good night!\n"); 744#endif 745 eval = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH, 746 "semwait", 0); 747#ifdef SEM_DEBUG 748 printf("semop: good morning (eval=%d)!\n", eval); 749#endif 750 751 suptr = NULL; /* sem_undo may have been reallocated */ 752 753 if (eval != 0) 754 return(EINTR); 755#ifdef SEM_DEBUG 756 printf("semop: good morning!\n"); 757#endif 758 759 /* 760 * Make sure that the semaphore still exists 761 */ 762 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || 763 semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) { 764 /* The man page says to return EIDRM. */ 765 /* Unfortunately, BSD doesn't define that code! */ 766#ifdef EIDRM 767 return(EIDRM); 768#else 769 return(EINVAL); 770#endif 771 } 772 773 /* 774 * The semaphore is still alive. Readjust the count of 775 * waiting processes. 776 */ 777 if (sopptr->sem_op == 0) 778 semptr->semzcnt--; 779 else 780 semptr->semncnt--; 781 } 782 783done: 784 /* 785 * Process any SEM_UNDO requests. 786 */ 787 if (do_undos) { 788 for (i = 0; i < nsops; i++) { 789 /* 790 * We only need to deal with SEM_UNDO's for non-zero 791 * op's. 792 */ 793 int adjval; 794 795 if ((sops[i].sem_flg & SEM_UNDO) == 0) 796 continue; 797 adjval = sops[i].sem_op; 798 if (adjval == 0) 799 continue; 800 eval = semundo_adjust(p, &suptr, semid, 801 sops[i].sem_num, -adjval); 802 if (eval == 0) 803 continue; 804 805 /* 806 * Oh-Oh! We ran out of either sem_undo's or undo's. 807 * Rollback the adjustments to this point and then 808 * rollback the semaphore ups and down so we can return 809 * with an error with all structures restored. We 810 * rollback the undo's in the exact reverse order that 811 * we applied them. This guarantees that we won't run 812 * out of space as we roll things back out. 813 */ 814 for (j = i - 1; j >= 0; j--) { 815 if ((sops[j].sem_flg & SEM_UNDO) == 0) 816 continue; 817 adjval = sops[j].sem_op; 818 if (adjval == 0) 819 continue; 820 if (semundo_adjust(p, &suptr, semid, 821 sops[j].sem_num, adjval) != 0) 822 panic("semop - can't undo undos"); 823 } 824 825 for (j = 0; j < nsops; j++) 826 semaptr->sem_base[sops[j].sem_num].semval -= 827 sops[j].sem_op; 828 829#ifdef SEM_DEBUG 830 printf("eval = %d from semundo_adjust\n", eval); 831#endif 832 return(eval); 833 } /* loop through the sops */ 834 } /* if (do_undos) */ 835 836 /* We're definitely done - set the sempid's */ 837 for (i = 0; i < nsops; i++) { 838 sopptr = &sops[i]; 839 semptr = &semaptr->sem_base[sopptr->sem_num]; 840 semptr->sempid = p->p_pid; 841 } 842 843 /* Do a wakeup if any semaphore was up'd. */ 844 if (do_wakeup) { 845#ifdef SEM_DEBUG 846 printf("semop: doing wakeup\n"); 847#ifdef SEM_WAKEUP 848 sem_wakeup((caddr_t)semaptr); 849#else 850 wakeup((caddr_t)semaptr); 851#endif 852 printf("semop: back from wakeup\n"); 853#else 854 wakeup((caddr_t)semaptr); 855#endif 856 } 857#ifdef SEM_DEBUG 858 printf("semop: done\n"); 859#endif 860 *retval = 0; 861 return(0); 862} 863 864/* 865 * Go through the undo structures for this process and apply the adjustments to 866 * semaphores. 867 */
|