sysv_sem.c revision 83341
1/* $FreeBSD: head/sys/kern/sysv_sem.c 83341 2001-09-11 12:20:24Z dd $ */ 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 "opt_sysvipc.h" 12 13#include <sys/param.h> 14#include <sys/systm.h> 15#include <sys/sysproto.h> 16#include <sys/kernel.h> 17#include <sys/proc.h> 18#include <sys/lock.h> 19#include <sys/mutex.h> 20#include <sys/sem.h> 21#include <sys/syscall.h> 22#include <sys/sysent.h> 23#include <sys/sysctl.h> 24#include <sys/malloc.h> 25#include <sys/jail.h> 26 27static MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores"); 28 29static void seminit __P((void)); 30static int sysvsem_modload __P((struct module *, int, void *)); 31static int semunload __P((void)); 32static void semexit_myhook __P((struct proc *p)); 33static int sysctl_sema __P((SYSCTL_HANDLER_ARGS)); 34 35#ifndef _SYS_SYSPROTO_H_ 36struct __semctl_args; 37int __semctl __P((struct proc *p, struct __semctl_args *uap)); 38struct semget_args; 39int semget __P((struct proc *p, struct semget_args *uap)); 40struct semop_args; 41int semop __P((struct proc *p, struct semop_args *uap)); 42#endif 43 44static struct sem_undo *semu_alloc __P((struct proc *p)); 45static int semundo_adjust __P((struct proc *p, struct sem_undo **supptr, 46 int semid, int semnum, int adjval)); 47static void semundo_clear __P((int semid, int semnum)); 48 49/* XXX casting to (sy_call_t *) is bogus, as usual. */ 50static sy_call_t *semcalls[] = { 51 (sy_call_t *)__semctl, (sy_call_t *)semget, 52 (sy_call_t *)semop 53}; 54 55static int semtot = 0; 56static struct semid_ds *sema; /* semaphore id pool */ 57static struct sem *sem; /* semaphore pool */ 58static struct sem_undo *semu_list; /* list of active undo structures */ 59static int *semu; /* undo structure pool */ 60 61struct sem { 62 u_short semval; /* semaphore value */ 63 pid_t sempid; /* pid of last operation */ 64 u_short semncnt; /* # awaiting semval > cval */ 65 u_short semzcnt; /* # awaiting semval = 0 */ 66}; 67 68/* 69 * Undo structure (one per process) 70 */ 71struct sem_undo { 72 struct sem_undo *un_next; /* ptr to next active undo structure */ 73 struct proc *un_proc; /* owner of this structure */ 74 short un_cnt; /* # of active entries */ 75 struct undo { 76 short un_adjval; /* adjust on exit values */ 77 short un_num; /* semaphore # */ 78 int un_id; /* semid */ 79 } un_ent[1]; /* undo entries */ 80}; 81 82/* 83 * Configuration parameters 84 */ 85#ifndef SEMMNI 86#define SEMMNI 10 /* # of semaphore identifiers */ 87#endif 88#ifndef SEMMNS 89#define SEMMNS 60 /* # of semaphores in system */ 90#endif 91#ifndef SEMUME 92#define SEMUME 10 /* max # of undo entries per process */ 93#endif 94#ifndef SEMMNU 95#define SEMMNU 30 /* # of undo structures in system */ 96#endif 97 98/* shouldn't need tuning */ 99#ifndef SEMMAP 100#define SEMMAP 30 /* # of entries in semaphore map */ 101#endif 102#ifndef SEMMSL 103#define SEMMSL SEMMNS /* max # of semaphores per id */ 104#endif 105#ifndef SEMOPM 106#define SEMOPM 100 /* max # of operations per semop call */ 107#endif 108 109#define SEMVMX 32767 /* semaphore maximum value */ 110#define SEMAEM 16384 /* adjust on exit max value */ 111 112/* 113 * Due to the way semaphore memory is allocated, we have to ensure that 114 * SEMUSZ is properly aligned. 115 */ 116 117#define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) 118 119/* actual size of an undo structure */ 120#define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME])) 121 122/* 123 * Macro to find a particular sem_undo vector 124 */ 125#define SEMU(ix) ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz)) 126 127/* 128 * semaphore info struct 129 */ 130struct seminfo seminfo = { 131 SEMMAP, /* # of entries in semaphore map */ 132 SEMMNI, /* # of semaphore identifiers */ 133 SEMMNS, /* # of semaphores in system */ 134 SEMMNU, /* # of undo structures in system */ 135 SEMMSL, /* max # of semaphores per id */ 136 SEMOPM, /* max # of operations per semop call */ 137 SEMUME, /* max # of undo entries per process */ 138 SEMUSZ, /* size in bytes of undo structure */ 139 SEMVMX, /* semaphore maximum value */ 140 SEMAEM /* adjust on exit max value */ 141}; 142 143SYSCTL_DECL(_kern_ipc); 144SYSCTL_INT(_kern_ipc, OID_AUTO, semmap, CTLFLAG_RW, &seminfo.semmap, 0, ""); 145SYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RD, &seminfo.semmni, 0, ""); 146SYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RD, &seminfo.semmns, 0, ""); 147SYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RD, &seminfo.semmnu, 0, ""); 148SYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0, ""); 149SYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RD, &seminfo.semopm, 0, ""); 150SYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RD, &seminfo.semume, 0, ""); 151SYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RD, &seminfo.semusz, 0, ""); 152SYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0, ""); 153SYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0, ""); 154SYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLFLAG_RD, 155 NULL, 0, sysctl_sema, "", ""); 156 157#if 0 158RO seminfo.semmap /* SEMMAP unused */ 159RO seminfo.semmni 160RO seminfo.semmns 161RO seminfo.semmnu /* undo entries per system */ 162RW seminfo.semmsl 163RO seminfo.semopm /* SEMOPM unused */ 164RO seminfo.semume 165RO seminfo.semusz /* param - derived from SEMUME for per-proc sizeof */ 166RO seminfo.semvmx /* SEMVMX unused - user param */ 167RO seminfo.semaem /* SEMAEM unused - user param */ 168#endif 169 170static void 171seminit(void) 172{ 173 register int i; 174 175 sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK); 176 if (sem == NULL) 177 panic("sem is NULL"); 178 sema = malloc(sizeof(struct semid_ds) * seminfo.semmni, M_SEM, M_WAITOK); 179 if (sema == NULL) 180 panic("sema is NULL"); 181 semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK); 182 if (semu == NULL) 183 panic("semu is NULL"); 184 185 for (i = 0; i < seminfo.semmni; i++) { 186 sema[i].sem_base = 0; 187 sema[i].sem_perm.mode = 0; 188 } 189 for (i = 0; i < seminfo.semmnu; i++) { 190 register struct sem_undo *suptr = SEMU(i); 191 suptr->un_proc = NULL; 192 } 193 semu_list = NULL; 194 semexit_hook = &semexit_myhook; 195} 196 197static int 198semunload(void) 199{ 200 201 if (semtot != 0) 202 return (EBUSY); 203 204 free(sem, M_SEM); 205 free(sema, M_SEM); 206 free(semu, M_SEM); 207 semexit_hook = NULL; 208 return (0); 209} 210 211static int 212sysvsem_modload(struct module *module, int cmd, void *arg) 213{ 214 int error = 0; 215 216 switch (cmd) { 217 case MOD_LOAD: 218 seminit(); 219 break; 220 case MOD_UNLOAD: 221 error = semunload(); 222 break; 223 case MOD_SHUTDOWN: 224 break; 225 default: 226 error = EINVAL; 227 break; 228 } 229 return (error); 230} 231 232static moduledata_t sysvsem_mod = { 233 "sysvsem", 234 &sysvsem_modload, 235 NULL 236}; 237 238SYSCALL_MODULE_HELPER(semsys, 5); 239SYSCALL_MODULE_HELPER(__semctl, 4); 240SYSCALL_MODULE_HELPER(semget, 3); 241SYSCALL_MODULE_HELPER(semop, 3); 242 243DECLARE_MODULE(sysvsem, sysvsem_mod, 244 SI_SUB_SYSV_SEM, SI_ORDER_FIRST); 245MODULE_VERSION(sysvsem, 1); 246 247/* 248 * Entry point for all SEM calls 249 * 250 * MPSAFE 251 */ 252int 253semsys(p, uap) 254 struct proc *p; 255 /* XXX actually varargs. */ 256 struct semsys_args /* { 257 u_int which; 258 int a2; 259 int a3; 260 int a4; 261 int a5; 262 } */ *uap; 263{ 264 int error; 265 266 mtx_lock(&Giant); 267 268 if (!jail_sysvipc_allowed && jailed(p->p_ucred)) { 269 error = ENOSYS; 270 goto done2; 271 } 272 273 if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0])) { 274 error = EINVAL; 275 goto done2; 276 } 277 error = (*semcalls[uap->which])(p, &uap->a2); 278done2: 279 mtx_unlock(&Giant); 280 return (error); 281} 282 283/* 284 * Allocate a new sem_undo structure for a process 285 * (returns ptr to structure or NULL if no more room) 286 */ 287 288static struct sem_undo * 289semu_alloc(p) 290 struct proc *p; 291{ 292 register int i; 293 register struct sem_undo *suptr; 294 register struct sem_undo **supptr; 295 int attempt; 296 297 /* 298 * Try twice to allocate something. 299 * (we'll purge any empty structures after the first pass so 300 * two passes are always enough) 301 */ 302 303 for (attempt = 0; attempt < 2; attempt++) { 304 /* 305 * Look for a free structure. 306 * Fill it in and return it if we find one. 307 */ 308 309 for (i = 0; i < seminfo.semmnu; i++) { 310 suptr = SEMU(i); 311 if (suptr->un_proc == NULL) { 312 suptr->un_next = semu_list; 313 semu_list = suptr; 314 suptr->un_cnt = 0; 315 suptr->un_proc = p; 316 return(suptr); 317 } 318 } 319 320 /* 321 * We didn't find a free one, if this is the first attempt 322 * then try to free some structures. 323 */ 324 325 if (attempt == 0) { 326 /* All the structures are in use - try to free some */ 327 int did_something = 0; 328 329 supptr = &semu_list; 330 while ((suptr = *supptr) != NULL) { 331 if (suptr->un_cnt == 0) { 332 suptr->un_proc = NULL; 333 *supptr = suptr->un_next; 334 did_something = 1; 335 } else 336 supptr = &(suptr->un_next); 337 } 338 339 /* If we didn't free anything then just give-up */ 340 if (!did_something) 341 return(NULL); 342 } else { 343 /* 344 * The second pass failed even though we freed 345 * something after the first pass! 346 * This is IMPOSSIBLE! 347 */ 348 panic("semu_alloc - second attempt failed"); 349 } 350 } 351 return (NULL); 352} 353 354/* 355 * Adjust a particular entry for a particular proc 356 */ 357 358static int 359semundo_adjust(p, supptr, semid, semnum, adjval) 360 register struct proc *p; 361 struct sem_undo **supptr; 362 int semid, semnum; 363 int adjval; 364{ 365 register struct sem_undo *suptr; 366 register struct undo *sunptr; 367 int i; 368 369 /* Look for and remember the sem_undo if the caller doesn't provide 370 it */ 371 372 suptr = *supptr; 373 if (suptr == NULL) { 374 for (suptr = semu_list; suptr != NULL; 375 suptr = suptr->un_next) { 376 if (suptr->un_proc == p) { 377 *supptr = suptr; 378 break; 379 } 380 } 381 if (suptr == NULL) { 382 if (adjval == 0) 383 return(0); 384 suptr = semu_alloc(p); 385 if (suptr == NULL) 386 return(ENOSPC); 387 *supptr = suptr; 388 } 389 } 390 391 /* 392 * Look for the requested entry and adjust it (delete if adjval becomes 393 * 0). 394 */ 395 sunptr = &suptr->un_ent[0]; 396 for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 397 if (sunptr->un_id != semid || sunptr->un_num != semnum) 398 continue; 399 if (adjval == 0) 400 sunptr->un_adjval = 0; 401 else 402 sunptr->un_adjval += adjval; 403 if (sunptr->un_adjval == 0) { 404 suptr->un_cnt--; 405 if (i < suptr->un_cnt) 406 suptr->un_ent[i] = 407 suptr->un_ent[suptr->un_cnt]; 408 } 409 return(0); 410 } 411 412 /* Didn't find the right entry - create it */ 413 if (adjval == 0) 414 return(0); 415 if (suptr->un_cnt != seminfo.semume) { 416 sunptr = &suptr->un_ent[suptr->un_cnt]; 417 suptr->un_cnt++; 418 sunptr->un_adjval = adjval; 419 sunptr->un_id = semid; sunptr->un_num = semnum; 420 } else 421 return(EINVAL); 422 return(0); 423} 424 425static void 426semundo_clear(semid, semnum) 427 int semid, semnum; 428{ 429 register struct sem_undo *suptr; 430 431 for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) { 432 register struct undo *sunptr = &suptr->un_ent[0]; 433 register int i = 0; 434 435 while (i < suptr->un_cnt) { 436 if (sunptr->un_id == semid) { 437 if (semnum == -1 || sunptr->un_num == semnum) { 438 suptr->un_cnt--; 439 if (i < suptr->un_cnt) { 440 suptr->un_ent[i] = 441 suptr->un_ent[suptr->un_cnt]; 442 continue; 443 } 444 } 445 if (semnum != -1) 446 break; 447 } 448 i++, sunptr++; 449 } 450 } 451} 452 453/* 454 * Note that the user-mode half of this passes a union, not a pointer 455 */ 456#ifndef _SYS_SYSPROTO_H_ 457struct __semctl_args { 458 int semid; 459 int semnum; 460 int cmd; 461 union semun *arg; 462}; 463#endif 464 465/* 466 * MPSAFE 467 */ 468int 469__semctl(p, uap) 470 struct proc *p; 471 register struct __semctl_args *uap; 472{ 473 int semid = uap->semid; 474 int semnum = uap->semnum; 475 int cmd = uap->cmd; 476 union semun *arg = uap->arg; 477 union semun real_arg; 478 struct ucred *cred = p->p_ucred; 479 int i, rval, error; 480 struct semid_ds sbuf; 481 register struct semid_ds *semaptr; 482 483#ifdef SEM_DEBUG 484 printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg); 485#endif 486 mtx_lock(&Giant); 487 488 if (!jail_sysvipc_allowed && jailed(p->p_ucred)) { 489 error = ENOSYS; 490 goto done2; 491 } 492 493 semid = IPCID_TO_IX(semid); 494 if (semid < 0 || semid >= seminfo.semmsl) { 495 error = EINVAL; 496 goto done2; 497 } 498 499 semaptr = &sema[semid]; 500 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || 501 semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) { 502 error = EINVAL; 503 goto done2; 504 } 505 506 error = 0; 507 rval = 0; 508 509 switch (cmd) { 510 case IPC_RMID: 511 if ((error = ipcperm(p, &semaptr->sem_perm, IPC_M))) 512 goto done2; 513 semaptr->sem_perm.cuid = cred->cr_uid; 514 semaptr->sem_perm.uid = cred->cr_uid; 515 semtot -= semaptr->sem_nsems; 516 for (i = semaptr->sem_base - sem; i < semtot; i++) 517 sem[i] = sem[i + semaptr->sem_nsems]; 518 for (i = 0; i < seminfo.semmni; i++) { 519 if ((sema[i].sem_perm.mode & SEM_ALLOC) && 520 sema[i].sem_base > semaptr->sem_base) 521 sema[i].sem_base -= semaptr->sem_nsems; 522 } 523 semaptr->sem_perm.mode = 0; 524 semundo_clear(semid, -1); 525 wakeup((caddr_t)semaptr); 526 break; 527 528 case IPC_SET: 529 if ((error = ipcperm(p, &semaptr->sem_perm, IPC_M))) 530 goto done2; 531 if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 532 goto done2; 533 if ((error = copyin(real_arg.buf, (caddr_t)&sbuf, 534 sizeof(sbuf))) != 0) { 535 goto done2; 536 } 537 semaptr->sem_perm.uid = sbuf.sem_perm.uid; 538 semaptr->sem_perm.gid = sbuf.sem_perm.gid; 539 semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) | 540 (sbuf.sem_perm.mode & 0777); 541 semaptr->sem_ctime = time_second; 542 break; 543 544 case IPC_STAT: 545 if ((error = ipcperm(p, &semaptr->sem_perm, IPC_R))) 546 goto done2; 547 if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 548 goto done2; 549 error = copyout((caddr_t)semaptr, real_arg.buf, 550 sizeof(struct semid_ds)); 551 break; 552 553 case GETNCNT: 554 if ((error = ipcperm(p, &semaptr->sem_perm, IPC_R))) 555 goto done2; 556 if (semnum < 0 || semnum >= semaptr->sem_nsems) { 557 error = EINVAL; 558 goto done2; 559 } 560 rval = semaptr->sem_base[semnum].semncnt; 561 break; 562 563 case GETPID: 564 if ((error = ipcperm(p, &semaptr->sem_perm, IPC_R))) 565 goto done2; 566 if (semnum < 0 || semnum >= semaptr->sem_nsems) { 567 error = EINVAL; 568 goto done2; 569 } 570 rval = semaptr->sem_base[semnum].sempid; 571 break; 572 573 case GETVAL: 574 if ((error = ipcperm(p, &semaptr->sem_perm, IPC_R))) 575 goto done2; 576 if (semnum < 0 || semnum >= semaptr->sem_nsems) { 577 error = EINVAL; 578 goto done2; 579 } 580 rval = semaptr->sem_base[semnum].semval; 581 break; 582 583 case GETALL: 584 if ((error = ipcperm(p, &semaptr->sem_perm, IPC_R))) 585 goto done2; 586 if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 587 goto done2; 588 for (i = 0; i < semaptr->sem_nsems; i++) { 589 error = copyout((caddr_t)&semaptr->sem_base[i].semval, 590 &real_arg.array[i], sizeof(real_arg.array[0])); 591 if (error != 0) 592 break; 593 } 594 break; 595 596 case GETZCNT: 597 if ((error = ipcperm(p, &semaptr->sem_perm, IPC_R))) 598 goto done2; 599 if (semnum < 0 || semnum >= semaptr->sem_nsems) { 600 error = EINVAL; 601 goto done2; 602 } 603 rval = semaptr->sem_base[semnum].semzcnt; 604 break; 605 606 case SETVAL: 607 if ((error = ipcperm(p, &semaptr->sem_perm, IPC_W))) 608 goto done2; 609 if (semnum < 0 || semnum >= semaptr->sem_nsems) { 610 error = EINVAL; 611 goto done2; 612 } 613 if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 614 goto done2; 615 semaptr->sem_base[semnum].semval = real_arg.val; 616 semundo_clear(semid, semnum); 617 wakeup((caddr_t)semaptr); 618 break; 619 620 case SETALL: 621 if ((error = ipcperm(p, &semaptr->sem_perm, IPC_W))) 622 goto done2; 623 if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 624 goto done2; 625 for (i = 0; i < semaptr->sem_nsems; i++) { 626 error = copyin(&real_arg.array[i], 627 (caddr_t)&semaptr->sem_base[i].semval, 628 sizeof(real_arg.array[0])); 629 if (error != 0) 630 break; 631 } 632 semundo_clear(semid, -1); 633 wakeup((caddr_t)semaptr); 634 break; 635 636 default: 637 error = EINVAL; 638 break; 639 } 640 641 if (error == 0) 642 p->p_retval[0] = rval; 643done2: 644 mtx_unlock(&Giant); 645 return(error); 646} 647 648#ifndef _SYS_SYSPROTO_H_ 649struct semget_args { 650 key_t key; 651 int nsems; 652 int semflg; 653}; 654#endif 655 656/* 657 * MPSAFE 658 */ 659int 660semget(p, uap) 661 struct proc *p; 662 register struct semget_args *uap; 663{ 664 int semid, error = 0; 665 int key = uap->key; 666 int nsems = uap->nsems; 667 int semflg = uap->semflg; 668 struct ucred *cred = p->p_ucred; 669 670#ifdef SEM_DEBUG 671 printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg); 672#endif 673 mtx_lock(&Giant); 674 675 if (!jail_sysvipc_allowed && jailed(p->p_ucred)) { 676 error = ENOSYS; 677 goto done2; 678 } 679 680 if (key != IPC_PRIVATE) { 681 for (semid = 0; semid < seminfo.semmni; semid++) { 682 if ((sema[semid].sem_perm.mode & SEM_ALLOC) && 683 sema[semid].sem_perm.key == key) 684 break; 685 } 686 if (semid < seminfo.semmni) { 687#ifdef SEM_DEBUG 688 printf("found public key\n"); 689#endif 690 if ((error = ipcperm(p, &sema[semid].sem_perm, 691 semflg & 0700))) { 692 goto done2; 693 } 694 if (nsems > 0 && sema[semid].sem_nsems < nsems) { 695#ifdef SEM_DEBUG 696 printf("too small\n"); 697#endif 698 error = EINVAL; 699 goto done2; 700 } 701 if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 702#ifdef SEM_DEBUG 703 printf("not exclusive\n"); 704#endif 705 error = EEXIST; 706 goto done2; 707 } 708 goto found; 709 } 710 } 711 712#ifdef SEM_DEBUG 713 printf("need to allocate the semid_ds\n"); 714#endif 715 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 716 if (nsems <= 0 || nsems > seminfo.semmsl) { 717#ifdef SEM_DEBUG 718 printf("nsems out of range (0<%d<=%d)\n", nsems, 719 seminfo.semmsl); 720#endif 721 error = EINVAL; 722 goto done2; 723 } 724 if (nsems > seminfo.semmns - semtot) { 725#ifdef SEM_DEBUG 726 printf("not enough semaphores left (need %d, got %d)\n", 727 nsems, seminfo.semmns - semtot); 728#endif 729 error = ENOSPC; 730 goto done2; 731 } 732 for (semid = 0; semid < seminfo.semmni; semid++) { 733 if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0) 734 break; 735 } 736 if (semid == seminfo.semmni) { 737#ifdef SEM_DEBUG 738 printf("no more semid_ds's available\n"); 739#endif 740 error = ENOSPC; 741 goto done2; 742 } 743#ifdef SEM_DEBUG 744 printf("semid %d is available\n", semid); 745#endif 746 sema[semid].sem_perm.key = key; 747 sema[semid].sem_perm.cuid = cred->cr_uid; 748 sema[semid].sem_perm.uid = cred->cr_uid; 749 sema[semid].sem_perm.cgid = cred->cr_gid; 750 sema[semid].sem_perm.gid = cred->cr_gid; 751 sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 752 sema[semid].sem_perm.seq = 753 (sema[semid].sem_perm.seq + 1) & 0x7fff; 754 sema[semid].sem_nsems = nsems; 755 sema[semid].sem_otime = 0; 756 sema[semid].sem_ctime = time_second; 757 sema[semid].sem_base = &sem[semtot]; 758 semtot += nsems; 759 bzero(sema[semid].sem_base, 760 sizeof(sema[semid].sem_base[0])*nsems); 761#ifdef SEM_DEBUG 762 printf("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base, 763 &sem[semtot]); 764#endif 765 } else { 766#ifdef SEM_DEBUG 767 printf("didn't find it and wasn't asked to create it\n"); 768#endif 769 error = ENOENT; 770 goto done2; 771 } 772 773found: 774 p->p_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm); 775done2: 776 mtx_unlock(&Giant); 777 return (error); 778} 779 780#ifndef _SYS_SYSPROTO_H_ 781struct semop_args { 782 int semid; 783 struct sembuf *sops; 784 u_int nsops; 785}; 786#endif 787 788/* 789 * MPSAFE 790 */ 791int 792semop(p, uap) 793 struct proc *p; 794 register struct semop_args *uap; 795{ 796 int semid = uap->semid; 797 u_int nsops = uap->nsops; 798 struct sembuf sops[MAX_SOPS]; 799 register struct semid_ds *semaptr; 800 register struct sembuf *sopptr; 801 register struct sem *semptr; 802 struct sem_undo *suptr = NULL; 803 int i, j, error = 0; 804 int do_wakeup, do_undos; 805 806#ifdef SEM_DEBUG 807 printf("call to semop(%d, 0x%x, %u)\n", semid, sops, nsops); 808#endif 809 810 mtx_lock(&Giant); 811 812 if (!jail_sysvipc_allowed && jailed(p->p_ucred)) { 813 error = ENOSYS; 814 goto done2; 815 } 816 817 semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 818 819 if (semid < 0 || semid >= seminfo.semmsl) { 820 error = EINVAL; 821 goto done2; 822 } 823 824 semaptr = &sema[semid]; 825 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) { 826 error = EINVAL; 827 goto done2; 828 } 829 if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) { 830 error = EINVAL; 831 goto done2; 832 } 833 834 if ((error = ipcperm(p, &semaptr->sem_perm, IPC_W))) { 835#ifdef SEM_DEBUG 836 printf("error = %d from ipcperm\n", error); 837#endif 838 goto done2; 839 } 840 841 if (nsops > MAX_SOPS) { 842#ifdef SEM_DEBUG 843 printf("too many sops (max=%d, nsops=%u)\n", MAX_SOPS, nsops); 844#endif 845 error = E2BIG; 846 goto done2; 847 } 848 849 if ((error = copyin(uap->sops, &sops, nsops * sizeof(sops[0]))) != 0) { 850#ifdef SEM_DEBUG 851 printf("error = %d from copyin(%08x, %08x, %u)\n", error, 852 uap->sops, &sops, nsops * sizeof(sops[0])); 853#endif 854 goto done2; 855 } 856 857 /* 858 * Loop trying to satisfy the vector of requests. 859 * If we reach a point where we must wait, any requests already 860 * performed are rolled back and we go to sleep until some other 861 * process wakes us up. At this point, we start all over again. 862 * 863 * This ensures that from the perspective of other tasks, a set 864 * of requests is atomic (never partially satisfied). 865 */ 866 do_undos = 0; 867 868 for (;;) { 869 do_wakeup = 0; 870 871 for (i = 0; i < nsops; i++) { 872 sopptr = &sops[i]; 873 874 if (sopptr->sem_num >= semaptr->sem_nsems) { 875 error = EFBIG; 876 goto done2; 877 } 878 879 semptr = &semaptr->sem_base[sopptr->sem_num]; 880 881#ifdef SEM_DEBUG 882 printf("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n", 883 semaptr, semaptr->sem_base, semptr, 884 sopptr->sem_num, semptr->semval, sopptr->sem_op, 885 (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait"); 886#endif 887 888 if (sopptr->sem_op < 0) { 889 if (semptr->semval + sopptr->sem_op < 0) { 890#ifdef SEM_DEBUG 891 printf("semop: can't do it now\n"); 892#endif 893 break; 894 } else { 895 semptr->semval += sopptr->sem_op; 896 if (semptr->semval == 0 && 897 semptr->semzcnt > 0) 898 do_wakeup = 1; 899 } 900 if (sopptr->sem_flg & SEM_UNDO) 901 do_undos = 1; 902 } else if (sopptr->sem_op == 0) { 903 if (semptr->semval > 0) { 904#ifdef SEM_DEBUG 905 printf("semop: not zero now\n"); 906#endif 907 break; 908 } 909 } else { 910 if (semptr->semncnt > 0) 911 do_wakeup = 1; 912 semptr->semval += sopptr->sem_op; 913 if (sopptr->sem_flg & SEM_UNDO) 914 do_undos = 1; 915 } 916 } 917 918 /* 919 * Did we get through the entire vector? 920 */ 921 if (i >= nsops) 922 goto done; 923 924 /* 925 * No ... rollback anything that we've already done 926 */ 927#ifdef SEM_DEBUG 928 printf("semop: rollback 0 through %d\n", i-1); 929#endif 930 for (j = 0; j < i; j++) 931 semaptr->sem_base[sops[j].sem_num].semval -= 932 sops[j].sem_op; 933 934 /* 935 * If the request that we couldn't satisfy has the 936 * NOWAIT flag set then return with EAGAIN. 937 */ 938 if (sopptr->sem_flg & IPC_NOWAIT) { 939 error = EAGAIN; 940 goto done2; 941 } 942 943 if (sopptr->sem_op == 0) 944 semptr->semzcnt++; 945 else 946 semptr->semncnt++; 947 948#ifdef SEM_DEBUG 949 printf("semop: good night!\n"); 950#endif 951 error = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH, 952 "semwait", 0); 953#ifdef SEM_DEBUG 954 printf("semop: good morning (error=%d)!\n", error); 955#endif 956 957 suptr = NULL; /* sem_undo may have been reallocated */ 958 959 if (error != 0) { 960 error = EINTR; 961 goto done2; 962 } 963#ifdef SEM_DEBUG 964 printf("semop: good morning!\n"); 965#endif 966 967 /* 968 * Make sure that the semaphore still exists 969 */ 970 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || 971 semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) { 972 error = EIDRM; 973 goto done2; 974 } 975 976 /* 977 * The semaphore is still alive. Readjust the count of 978 * waiting processes. 979 */ 980 if (sopptr->sem_op == 0) 981 semptr->semzcnt--; 982 else 983 semptr->semncnt--; 984 } 985 986done: 987 /* 988 * Process any SEM_UNDO requests. 989 */ 990 if (do_undos) { 991 for (i = 0; i < nsops; i++) { 992 /* 993 * We only need to deal with SEM_UNDO's for non-zero 994 * op's. 995 */ 996 int adjval; 997 998 if ((sops[i].sem_flg & SEM_UNDO) == 0) 999 continue; 1000 adjval = sops[i].sem_op; 1001 if (adjval == 0) 1002 continue; 1003 error = semundo_adjust(p, &suptr, semid, 1004 sops[i].sem_num, -adjval); 1005 if (error == 0) 1006 continue; 1007 1008 /* 1009 * Oh-Oh! We ran out of either sem_undo's or undo's. 1010 * Rollback the adjustments to this point and then 1011 * rollback the semaphore ups and down so we can return 1012 * with an error with all structures restored. We 1013 * rollback the undo's in the exact reverse order that 1014 * we applied them. This guarantees that we won't run 1015 * out of space as we roll things back out. 1016 */ 1017 for (j = i - 1; j >= 0; j--) { 1018 if ((sops[j].sem_flg & SEM_UNDO) == 0) 1019 continue; 1020 adjval = sops[j].sem_op; 1021 if (adjval == 0) 1022 continue; 1023 if (semundo_adjust(p, &suptr, semid, 1024 sops[j].sem_num, adjval) != 0) 1025 panic("semop - can't undo undos"); 1026 } 1027 1028 for (j = 0; j < nsops; j++) 1029 semaptr->sem_base[sops[j].sem_num].semval -= 1030 sops[j].sem_op; 1031 1032#ifdef SEM_DEBUG 1033 printf("error = %d from semundo_adjust\n", error); 1034#endif 1035 goto done2; 1036 } /* loop through the sops */ 1037 } /* if (do_undos) */ 1038 1039 /* We're definitely done - set the sempid's */ 1040 for (i = 0; i < nsops; i++) { 1041 sopptr = &sops[i]; 1042 semptr = &semaptr->sem_base[sopptr->sem_num]; 1043 semptr->sempid = p->p_pid; 1044 } 1045 1046 /* Do a wakeup if any semaphore was up'd. */ 1047 if (do_wakeup) { 1048#ifdef SEM_DEBUG 1049 printf("semop: doing wakeup\n"); 1050#endif 1051 wakeup((caddr_t)semaptr); 1052#ifdef SEM_DEBUG 1053 printf("semop: back from wakeup\n"); 1054#endif 1055 } 1056#ifdef SEM_DEBUG 1057 printf("semop: done\n"); 1058#endif 1059 p->p_retval[0] = 0; 1060done2: 1061 mtx_unlock(&Giant); 1062 return (error); 1063} 1064 1065/* 1066 * Go through the undo structures for this process and apply the adjustments to 1067 * semaphores. 1068 */ 1069static void 1070semexit_myhook(p) 1071 struct proc *p; 1072{ 1073 register struct sem_undo *suptr; 1074 register struct sem_undo **supptr; 1075 int did_something; 1076 1077 did_something = 0; 1078 1079 /* 1080 * Go through the chain of undo vectors looking for one 1081 * associated with this process. 1082 */ 1083 1084 for (supptr = &semu_list; (suptr = *supptr) != NULL; 1085 supptr = &suptr->un_next) { 1086 if (suptr->un_proc == p) 1087 break; 1088 } 1089 1090 if (suptr == NULL) 1091 return; 1092 1093#ifdef SEM_DEBUG 1094 printf("proc @%08x has undo structure with %d entries\n", p, 1095 suptr->un_cnt); 1096#endif 1097 1098 /* 1099 * If there are any active undo elements then process them. 1100 */ 1101 if (suptr->un_cnt > 0) { 1102 int ix; 1103 1104 for (ix = 0; ix < suptr->un_cnt; ix++) { 1105 int semid = suptr->un_ent[ix].un_id; 1106 int semnum = suptr->un_ent[ix].un_num; 1107 int adjval = suptr->un_ent[ix].un_adjval; 1108 struct semid_ds *semaptr; 1109 1110 semaptr = &sema[semid]; 1111 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) 1112 panic("semexit - semid not allocated"); 1113 if (semnum >= semaptr->sem_nsems) 1114 panic("semexit - semnum out of range"); 1115 1116#ifdef SEM_DEBUG 1117 printf("semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n", 1118 suptr->un_proc, suptr->un_ent[ix].un_id, 1119 suptr->un_ent[ix].un_num, 1120 suptr->un_ent[ix].un_adjval, 1121 semaptr->sem_base[semnum].semval); 1122#endif 1123 1124 if (adjval < 0) { 1125 if (semaptr->sem_base[semnum].semval < -adjval) 1126 semaptr->sem_base[semnum].semval = 0; 1127 else 1128 semaptr->sem_base[semnum].semval += 1129 adjval; 1130 } else 1131 semaptr->sem_base[semnum].semval += adjval; 1132 1133 wakeup((caddr_t)semaptr); 1134#ifdef SEM_DEBUG 1135 printf("semexit: back from wakeup\n"); 1136#endif 1137 } 1138 } 1139 1140 /* 1141 * Deallocate the undo vector. 1142 */ 1143#ifdef SEM_DEBUG 1144 printf("removing vector\n"); 1145#endif 1146 suptr->un_proc = NULL; 1147 *supptr = suptr->un_next; 1148} 1149 1150static int 1151sysctl_sema(SYSCTL_HANDLER_ARGS) 1152{ 1153 1154 return (SYSCTL_OUT(req, sema, 1155 sizeof(struct semid_ds) * seminfo.semmni)); 1156} 1157