|
|
1.1 ! root 1: /* ! 2: * File: sem1.c ! 3: * ! 4: * Purpose: This module provides System V compatible semaphore operations. ! 5: * ! 6: * $Log: sem386.c,v $ ! 7: * Revision 1.2 93/04/20 10:00:32 bin ! 8: * kernel 77: vlad: sem_undo and other changes ! 9: * ! 10: * Revision 1.1 93/04/09 08:48:23 bin ! 11: * Initial revision ! 12: * ! 13: */ ! 14: ! 15: /* ! 16: * ---------------------------------------------------------------------- ! 17: * Includes. ! 18: */ ! 19: #include <sys/coherent.h> ! 20: #include <sys/sched.h> ! 21: #if 0 ! 22: #include <sys/proc.h> ! 23: #endif ! 24: #include <sys/types.h> ! 25: #include <sys/uproc.h> ! 26: #include <errno.h> ! 27: #include <sys/stat.h> ! 28: #include <sys/con.h> ! 29: #include <sys/sem.h> ! 30: ! 31: /* ! 32: * ---------------------------------------------------------------------- ! 33: * Definitions. ! 34: * Constants. ! 35: * Macros with argument lists. ! 36: * Typedefs. ! 37: * Enums. ! 38: */ ! 39: ! 40: /* ! 41: * ---------------------------------------------------------------------- ! 42: * Functions. ! 43: * Import Functions. ! 44: * Export Functions. ! 45: * Local Functions. ! 46: */ ! 47: int iSemPerm(); /* Check permissions */ ! 48: int iSanityCheck(); /* Sanity check */ ! 49: int iSemInit(); /* Init semaphores */ ! 50: void vClearAdj(); /* Clear the adjust value */ ! 51: int iSubAdj(); /* Subtract value from the sem adjust */ ! 52: /* ! 53: * ---------------------------------------------------------------------- ! 54: * Global Data. ! 55: * Import Variables. ! 56: * Export Variables. ! 57: * Local Variables. ! 58: */ ! 59: /* Patchable values */ ! 60: int SEMMNI = 10; /* max # of the semaphore sets, systemwide */ ! 61: int SEMMNS = 60; /* max # of semaphores, systemwide */ ! 62: int SEMMSL = 25; /* max # of semaphores per set */ ! 63: int SEMVMX = 32767; /* max value of any semaphore */ ! 64: ! 65: struct semid_ds *semids = NULL; /* Array of semaphore sets */ ! 66: int iSemTotal = 0; /* Total number of semaphores, systemwide */ ! 67: GATE gSemGate; /* Semaphore gate. */ ! 68: unsigned short usSEM_R = 0444; /* Permission definition for read */ ! 69: unsigned short usSEM_A = 0222; /* and alter */ ! 70: ! 71: /* ! 72: * ---------------------------------------------------------------------- ! 73: * Code. ! 74: */ ! 75: ! 76: /* ! 77: * Semget gets set of semaphores. Returns semaphore set id on suuccess, ! 78: * or sets u.u_error on error. ! 79: */ ! 80: usemget(skey, nsems, semflg) ! 81: key_t skey; /* Semaphore key */ ! 82: int nsems, /* # of semaphores in the set */ ! 83: semflg; /* Permission flag */ ! 84: { ! 85: register struct semid_ds *semidp; /* Semaphore set */ ! 86: register struct sem *semp; /* Semaphores */ ! 87: struct semid_ds *freeidp = 0; /* Oldest free set */ ! 88: ! 89: if (iSanityCheck(nsems)) ! 90: return; ! 91: ! 92: /* Allocate memmory on the first semget. This memory (~300 bytes) ! 93: * will stay alloc up to the next reboot. The alloced unused memory ! 94: * is smaller than code that will allow to manage it more sophisticated. ! 95: * Allocaton is used to allow patchability of the semaphores. ! 96: */ ! 97: if (semids == NULL) { ! 98: if (iSemInit()) { ! 99: u.u_error = ENOSPC; ! 100: return; ! 101: } ! 102: } ! 103: lock(gSemGate); /* Lock semaphore operations */ ! 104: ! 105: /* Now we will go through all semaphores. */ ! 106: for (semidp = semids; semidp < semids + SEMMNI; semidp++) { ! 107: /* If set is free look for the oldest */ ! 108: if ((semidp->sem_perm.mode & IPC_ALLOC) == 0) { ! 109: if ((freeidp == 0) || ! 110: (freeidp->sem_ctime > semidp->sem_ctime)) ! 111: freeidp = semidp; ! 112: continue; ! 113: } ! 114: ! 115: /* Check if a request was for the private set */ ! 116: if (skey == IPC_PRIVATE) ! 117: continue; ! 118: ! 119: if (skey != semidp->sem_perm.key) ! 120: continue; ! 121: /* Found */ ! 122: /* Exclusive set cannot be created */ ! 123: if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { ! 124: unlock(gSemGate); ! 125: u.u_error = EEXIST; ! 126: return; ! 127: } ! 128: ! 129: /* Check the permissions */ ! 130: if (iSemPerm(semidp, semflg)) { ! 131: unlock(gSemGate); ! 132: return; ! 133: } ! 134: ! 135: /* Check the requested number of semaphores */ ! 136: if (semidp->sem_nsems < nsems) { ! 137: unlock(gSemGate); ! 138: u.u_error = EINVAL; ! 139: return; ! 140: } ! 141: /* Semaphore set id number is the number of an array element */ ! 142: unlock(gSemGate); ! 143: return semidp - semids; ! 144: } ! 145: ! 146: /* Set does not exist. So, we have to create it */ ! 147: /* Now nsems should be > 0 */ ! 148: if (nsems < 1) { ! 149: unlock(gSemGate); ! 150: u.u_error = EINVAL; ! 151: return; ! 152: } ! 153: ! 154: /* Check the total number of semaphores */ ! 155: if ((iSemTotal + nsems > SEMMNS)) { ! 156: unlock(gSemGate); ! 157: u.u_error = ENOSPC; ! 158: return; ! 159: } ! 160: ! 161: /* Check if there is the request for creation */ ! 162: if (!(semflg & IPC_CREAT)) { ! 163: unlock(gSemGate); ! 164: u.u_error = ENOENT; ! 165: return; ! 166: } ! 167: ! 168: /* Out of system limits */ ! 169: if (freeidp == 0) { ! 170: unlock(gSemGate); ! 171: u.u_error = ENOSPC; ! 172: return; ! 173: } ! 174: ! 175: /* Now we have to creat a new set. freeidp points to the oldest free ! 176: * set which we will use. ! 177: */ ! 178: semidp = freeidp; ! 179: /* Get space for semaphores */ ! 180: semidp->sem_base = kalloc(nsems * sizeof(struct sem)); ! 181: if (semidp->sem_base == 0) { ! 182: unlock(gSemGate); ! 183: u.u_error = ENOSPC; ! 184: return; ! 185: } ! 186: ! 187: /* Initialize created set */ ! 188: /* ipc_perm */ ! 189: semidp->sem_perm.cuid = semidp->sem_perm.uid = u.u_uid; ! 190: semidp->sem_perm.cgid = semidp->sem_perm.gid = u.u_gid; ! 191: semidp->sem_perm.mode = (semflg & 0777) | IPC_ALLOC; ! 192: semidp->sem_perm.key = skey; ! 193: semidp->sem_perm.seq = semidp - semids; ! 194: ! 195: semidp->sem_nsems = nsems; ! 196: semidp->sem_otime = 0; ! 197: semidp->sem_ctime = timer.t_time; ! 198: ! 199: /* Increment number of semaphores in used */ ! 200: iSemTotal += nsems; ! 201: ! 202: /* Set values of the semaphores to 0. ! 203: * SVR3 does not do it and suggests set up sem struct using ! 204: * semctl() call. SVR4 manual says nothing about it. ! 205: */ ! 206: for (semp = semidp->sem_base; semp < semidp->sem_base + nsems; semp++){ ! 207: semp->semval = semp->sempid = semp->semncnt = semp->semzcnt = 0; ! 208: } ! 209: unlock(gSemGate); ! 210: return semidp - semids; ! 211: } ! 212: ! 213: /* ! 214: * Semctl provides semaphore control operation as specify by cmd. ! 215: * On success return value depends on cmd, sets u.u_error on error. ! 216: */ ! 217: usemctl(semid, semnum, cmd, arg) ! 218: int semid, /* Semaphore set id */ ! 219: cmd; /* Command */ ! 220: int semnum; /* Semaphore # */ ! 221: union semun { ! 222: int val; /* Used for SETVAL only */ ! 223: struct semid_ds *buf; /* Used for IPC_STAT and IPC_SET */ ! 224: unsigned short *array; /* Used for IPC_GET_ALL and IPC_SETALL */ ! 225: } arg; ! 226: ! 227: { ! 228: register struct semid_ds *semidp; /* Semaphore set */ ! 229: register struct sem *semp; /* Semaphore */ ! 230: int val; /* Semaphore value */ ! 231: int i; /* Loopindex */ ! 232: unsigned short *pusUserAr; /* User array */ ! 233: ! 234: if (iSanityCheck(semnum)) ! 235: return; ! 236: ! 237: /* Check if there was any successfull semget before. ! 238: * Problem may be if somebody does semctl() before semids was ! 239: * alloced. ! 240: */ ! 241: if (semids == 0) { ! 242: u.u_error = EINVAL; ! 243: return; ! 244: } ! 245: ! 246: /* semid cannot be < 0 and more than systemwide limit */ ! 247: if (semid < 0 || semid >= SEMMNI) { ! 248: u.u_error = EINVAL; ! 249: return; ! 250: } ! 251: semidp = semids + semid; ! 252: ! 253: /* Check if the requested set is alloced */ ! 254: if ((semidp->sem_perm.mode & IPC_ALLOC) == 0) { ! 255: u.u_error = EINVAL; ! 256: return; ! 257: } ! 258: ! 259: /* Check if semnum is a correct semaphore number. ! 260: * SV would do it only when there is request for a ! 261: * single semaphore value, as GETVAL or SETVAL. ! 262: */ ! 263: if (semnum >= semidp->sem_nsems) { ! 264: u.u_error = EFBIG; ! 265: return; ! 266: } ! 267: ! 268: semp = semidp->sem_base + semnum; ! 269: ! 270: switch (cmd) { ! 271: case GETVAL: /* Return value of semval */ ! 272: if (iSemPerm(semidp, usSEM_R)) /* cannot read */ ! 273: return; ! 274: return semp->semval; ! 275: case SETVAL: /* Set semval. Clear all semadj values on success. */ ! 276: if (iSemPerm(semidp, usSEM_A)) /* cannot alter */ ! 277: return; ! 278: /* semval always >= 0 */ ! 279: if (arg.val > SEMVMX || arg.val < 0) { /* illegal value */ ! 280: u.u_error = ERANGE; ! 281: return; ! 282: } ! 283: /* Set semval and wakeup whatever should be */ ! 284: if (semp->semval = arg.val) { ! 285: if (semp->semncnt) ! 286: wakeup(&semp->semncnt); ! 287: } else { ! 288: if (semp->semzcnt) ! 289: wakeup(&semp->semzcnt); ! 290: } ! 291: semidp->sem_ctime = timer.t_time; ! 292: /* Clear corresponding adjust value in all processes */ ! 293: vClearAdj(semid, semnum); ! 294: return 0; ! 295: case GETPID: /* Return value of sempid */ ! 296: if (iSemPerm(semidp, usSEM_R)) /* cannot read */ ! 297: return; ! 298: return semp->sempid; ! 299: case GETNCNT: /* Return value of semncnt */ ! 300: if (iSemPerm(semidp, usSEM_R)) /* cannot read */ ! 301: return; ! 302: return semp->semncnt; ! 303: case GETZCNT: /* Return value of semzcnt */ ! 304: if (iSemPerm(semidp, usSEM_R)) /* cannot read */ ! 305: return; ! 306: return semp->semzcnt; ! 307: case GETALL: /* Return semvals array */ ! 308: if (iSemPerm(semidp, usSEM_R)) /* cannot read */ ! 309: return; ! 310: /* Copy all values to user array */ ! 311: semp = semidp->sem_base; ! 312: pusUserAr = arg.array; ! 313: for (i = 0; i < semidp->sem_nsems; i++) { ! 314: putusd(pusUserAr, semp->semval); ! 315: if (u.u_error) ! 316: return; ! 317: semp++; ! 318: pusUserAr++; ! 319: } ! 320: return 0; ! 321: case SETALL: /* Set semvals array */ ! 322: if (iSemPerm(semidp, SEM_A)) /* cannot alter */ ! 323: return; ! 324: ! 325: /* Set semvals accoding to the arg.array */ ! 326: semp = semidp->sem_base; ! 327: pusUserAr = arg.array; ! 328: lock(gSemGate); ! 329: for (i = 0; i < semidp->sem_nsems; i++) { ! 330: val = getusd(pusUserAr++); ! 331: if (u.u_error) { ! 332: unlock(gSemGate); ! 333: return; ! 334: } ! 335: if (val < 0 || val > SEMVMX) { ! 336: u.u_error = ERANGE; ! 337: unlock(gSemGate); ! 338: return; ! 339: } ! 340: semp->semval = val; ! 341: /* Clear corresponding adjust value in all processes. */ ! 342: vClearAdj(semid, i); ! 343: semp++; ! 344: } ! 345: semidp->sem_ctime = timer.t_time; ! 346: unlock(gSemGate); ! 347: return 0; ! 348: case IPC_STAT: ! 349: if (iSemPerm(semidp, usSEM_R)) /* cannot read */ ! 350: return; ! 351: kucopy(semidp, arg.buf, sizeof(struct semid_ds)); ! 352: return 0; ! 353: case IPC_SET: ! 354: if (iSemPerm(semidp, SEM_A)) /* cannot alter */ ! 355: return; ! 356: semidp->sem_perm.uid = getusd(&((arg.buf)->sem_perm.uid)); ! 357: semidp->sem_perm.gid = getusd(&((arg.buf)->sem_perm.gid)); ! 358: semidp->sem_perm.mode = ! 359: (getusd(&((arg.buf)->sem_perm.mode))&0777) | IPC_ALLOC; ! 360: semidp->sem_ctime = timer.t_time; ! 361: return 0; ! 362: case IPC_RMID: ! 363: if ((u.u_uid != 0) && (u.u_uid != semidp->sem_perm.uid) ! 364: && u.u_uid != semidp->sem_perm.cuid) { ! 365: u.u_error = EPERM; ! 366: return; ! 367: } ! 368: ! 369: /* We have to wake up all waiting proccesses */ ! 370: for (semp = semidp->sem_base; semp < semidp->sem_base + ! 371: semidp->sem_nsems; semp++) { ! 372: if (semp->semncnt) ! 373: wakeup(&semp->semncnt); ! 374: if (semp->semzcnt) ! 375: wakeup(&semp->semzcnt); ! 376: } ! 377: /* We do not cleane up adjust values here */ ! 378: iSemTotal -= semidp->sem_nsems; ! 379: semidp->sem_perm.mode = 0; ! 380: kfree(semidp->sem_base); ! 381: return 0; ! 382: default: ! 383: u.u_error = EINVAL; ! 384: return; ! 385: } ! 386: } ! 387: ! 388: /* ! 389: * Semop - Semaphore Operations. ! 390: */ ! 391: usemop(iSemId, pstSops, uNsops) ! 392: int iSemId; /* Semaphore identifier */ ! 393: struct sembuf *pstSops; /* Array of sem. operations */ ! 394: unsigned uNsops; /* # of elements in the array */ ! 395: { ! 396: register struct semid_ds *rpstSemSet; /* Semaphore set */ ! 397: register struct sem *rpstSem; /* Semaphore */ ! 398: struct sembuf *pstSemBuf; /* Operations */ ! 399: unsigned short usSemNum; /* Semaphore number */ ! 400: short sSemFlg; /* Semaphore flag */ ! 401: short sSemOper; /* Operation */ ! 402: int i; /* Loop index */ ! 403: short change = 0; /* Sem was changed */ ! 404: ! 405: /* Check if semids was alloced */ ! 406: if (semids == 0) { ! 407: u.u_error = EINVAL; ! 408: return; ! 409: } ! 410: /* iSemId cannot be < 0 and more than systemwide limit */ ! 411: if (iSemId < 0 || iSemId >= SEMMNI) { ! 412: u.u_error = EINVAL; ! 413: return; ! 414: } ! 415: if (!useracc(pstSops, sizeof(struct sembuf) * uNsops, 0) || uNsops<1) { ! 416: u.u_error = EFAULT; ! 417: return; ! 418: } ! 419: ! 420: rpstSemSet = semids + iSemId; /* Requested set */ ! 421: ! 422: if ((rpstSemSet->sem_perm.mode & IPC_ALLOC) == 0) { ! 423: u.u_error = EINVAL; ! 424: return -1; ! 425: } ! 426: TRY_AGAIN: /* Repeat the semaphore set */ ! 427: ! 428: /* Lock semaphore system */ ! 429: lock(gSemGate); ! 430: ! 431: /* do semaphore ops */ ! 432: for (i = 0, pstSemBuf = pstSops; i < uNsops; i++, pstSemBuf++) { ! 433: usSemNum = getusd(&(pstSemBuf->sem_num)); ! 434: sSemOper = getusd(&(pstSemBuf->sem_op)); ! 435: sSemFlg = getusd(&(pstSemBuf->sem_flg)); ! 436: ! 437: if (sSemOper < -SEMVMX || sSemOper > SEMVMX) { ! 438: semundo(rpstSemSet, pstSops, i); ! 439: u.u_error = E2BIG; ! 440: unlock(gSemGate); ! 441: return; ! 442: } ! 443: if ((u.u_error != 0) || (usSemNum >= rpstSemSet->sem_nsems)) { ! 444: /* We have falure here. undo all previous ! 445: * operations. ! 446: */ ! 447: semundo(rpstSemSet, pstSops, i); ! 448: /* If u_error was not set it means that sem_number ! 449: * is bad. So, set error to EFBIG. ! 450: */ ! 451: if (u.u_error == 0) ! 452: u.u_error = EFBIG; ! 453: unlock(gSemGate); ! 454: return; ! 455: } ! 456: ! 457: /* Go to proper semaphore */ ! 458: rpstSem = rpstSemSet->sem_base + usSemNum; ! 459: ! 460: /* We can have 3 different cases: sSemOper < 0, ! 461: * sSemOper == 0, & sSemOper > 0. ! 462: */ ! 463: if (sSemOper < 0) { /* want to decrement semval */ ! 464: /* We do not have to undo anything. If we cannot alter ! 465: * we did not change any value in the set. But we ! 466: * have to check here because other requests could be ! 467: * for read (sSemOper=0) ! 468: */ ! 469: if (iSemPerm(rpstSemSet, SEM_A)) { /* cannot alter */ ! 470: unlock(gSemGate); ! 471: return; ! 472: } ! 473: ! 474: /* If we can decrement semval, do it. If ! 475: * semval becomes 0 wakeup all processes ! 476: * waiting for semval==0. ! 477: */ ! 478: if (rpstSem->semval >= -sSemOper) { ! 479: if (!(rpstSem->semval += sSemOper)) ! 480: if (rpstSem->semzcnt) ! 481: wakeup(&rpstSem->semzcnt); ! 482: if (sSemFlg & SEM_UNDO) { ! 483: if (iSubAdj(iSemId,usSemNum,sSemOper)) { ! 484: semundo(rpstSemSet, pstSops, i); ! 485: unlock(gSemGate); ! 486: return; ! 487: } ! 488: } ! 489: change++; ! 490: continue; ! 491: } ! 492: /* Can't decrement. */ ! 493: semundo(rpstSemSet, pstSops, i); ! 494: if (sSemFlg & IPC_NOWAIT) { ! 495: if (u.u_error == 0) ! 496: u.u_error = EAGAIN; ! 497: unlock(gSemGate); ! 498: return; ! 499: } else {/* Go to sleep */ ! 500: unlock(gSemGate); ! 501: if (semwait(iSemId, &rpstSem->semncnt) < 0) { ! 502: return; ! 503: } ! 504: /* Now we can retry semaphore set */ ! 505: goto TRY_AGAIN; ! 506: } ! 507: } ! 508: if (sSemOper == 0) { ! 509: if (iSemPerm(rpstSemSet, SEM_R)) { /* cannot read */ ! 510: /* If somebody cannot read it does not ! 511: * mean that one couldn't alter. ! 512: */ ! 513: if (iSemPerm(rpstSemSet, SEM_A)) ! 514: semundo(rpstSemSet, pstSops, i); ! 515: ! 516: unlock(gSemGate); ! 517: return; ! 518: } ! 519: if (rpstSem->semval == 0) { ! 520: continue; ! 521: } ! 522: /* Semaphore value isn't 0. Undo all previous ! 523: * operations. ! 524: */ ! 525: semundo(rpstSemSet, pstSops, i); ! 526: ! 527: if (sSemFlg & IPC_NOWAIT) { ! 528: if (u.u_error == 0) ! 529: u.u_error = EAGAIN; ! 530: unlock(gSemGate); ! 531: return; ! 532: } ! 533: ! 534: unlock(gSemGate); ! 535: if (semwait(iSemId, &rpstSem->semzcnt) < 0) { ! 536: return; ! 537: } ! 538: goto TRY_AGAIN; ! 539: } ! 540: if (sSemOper > 0) { ! 541: if (iSemPerm(rpstSemSet, SEM_A)) { /* cannot alter */ ! 542: unlock(gSemGate); ! 543: return; ! 544: } ! 545: if (sSemFlg & SEM_UNDO) { ! 546: if (iSubAdj(iSemId, usSemNum, sSemOper)) { ! 547: semundo(rpstSemSet, pstSops, i); ! 548: unlock(gSemGate); ! 549: return; ! 550: } ! 551: } ! 552: if (rpstSem->semval > SEMVMX - sSemOper) { ! 553: semundo(rpstSemSet, pstSops, i); ! 554: /* semundo would not adjust current semaphore */ ! 555: if (sSemFlg & SEM_UNDO) { ! 556: iSubAdj(iSemId, usSemNum, -sSemOper); ! 557: } ! 558: u.u_error = ERANGE; ! 559: unlock(gSemGate); ! 560: return; ! 561: } ! 562: rpstSem->semval += sSemOper; ! 563: ! 564: /* Wake up waiting processes */ ! 565: if (rpstSem->semncnt) ! 566: wakeup(&rpstSem->semncnt); ! 567: change++; ! 568: continue; ! 569: } ! 570: } ! 571: rpstSemSet->sem_otime = timer.t_time; /* adjust semop time */ ! 572: if (change) /* Semaphore was changed */ ! 573: rpstSemSet->sem_ctime = timer.t_time; ! 574: ! 575: /* Go through all set again and set pid of last semop */ ! 576: for (i = 0, pstSemBuf = pstSops; i < uNsops; i++, pstSemBuf++) { ! 577: usSemNum = getusd(&(pstSemBuf->sem_num)); ! 578: rpstSem = rpstSemSet->sem_base + usSemNum; ! 579: rpstSem->sempid = SELF->p_pid; ! 580: } ! 581: unlock(gSemGate); ! 582: return 0; /* return last prev semval */ ! 583: } ! 584: ! 585: /* ! 586: * Wait for an event. ! 587: */ ! 588: semwait(iSemId, usSleepEvent) ! 589: int iSemId; /* Semaphore set id */ ! 590: unsigned short *usSleepEvent; /* Could be semcnt or semzcnt */ ! 591: { ! 592: register struct semid_ds *rpstSemSet; /* Semaphore set */ ! 593: ! 594: (*usSleepEvent)++; ! 595: ! 596: rpstSemSet = semids + iSemId; ! 597: ! 598: x_sleep(usSleepEvent, pritty, slpriSigCatch, "semwait"); ! 599: ! 600: if (!(rpstSemSet->sem_perm.mode & IPC_ALLOC)) { /* Semaphore gone */ ! 601: u.u_error = EIDRM; ! 602: return -1; ! 603: } ! 604: (*usSleepEvent)--; ! 605: ! 606: if (SELF->p_ssig && nondsig()) { /* Signal received */ ! 607: u.u_error = EINTR; ! 608: return -1; ! 609: } ! 610: return 0; ! 611: } ! 612: ! 613: /* ! 614: * Undo a Semaphore Operation. It should undo an adjust values too. ! 615: */ ! 616: semundo(pstSemSet, pstSemOp, iUndo) ! 617: struct semid_ds *pstSemSet; /* Pointer to the semaphore set */ ! 618: struct sembuf *pstSemOp; /* Pointer to the undo operation */ ! 619: int iUndo; /* Number of semaphores to undo */ ! 620: { ! 621: register struct sem *rpstSem; /* */ ! 622: register struct sembuf *rpstBuf; /* */ ! 623: register int i; /* Loop index */ ! 624: int iSemId; /* Semaphore id */ ! 625: unsigned short usSemNum; /* Semaphore number */ ! 626: short sSemOper; /* Value to undo */ ! 627: short sSemFlg; /* Semaphore flag */ ! 628: ! 629: rpstSem = pstSemSet->sem_base; ! 630: rpstBuf = pstSemOp; ! 631: iSemId = pstSemSet - semids; ! 632: for (i = 0; i < iUndo; i++) { ! 633: usSemNum = getusd( &(rpstBuf->sem_num) ); ! 634: sSemOper = getusd( &(rpstBuf->sem_op) ); ! 635: sSemFlg = getusd( &(rpstBuf->sem_flg) ); ! 636: rpstSem->semval -= sSemOper; ! 637: if (sSemFlg & SEM_UNDO) { ! 638: iSubAdj(iSemId, usSemNum, -sSemOper); ! 639: } ! 640: rpstBuf++; ! 641: rpstSem++; ! 642: } ! 643: } ! 644: ! 645: /* ! 646: * Check permissions of the semaphore set. ! 647: * Return 0 on success, -1 and set errno on error. ! 648: */ ! 649: int iSemPerm(pstSemId, iSemFlg) ! 650: struct semid_ds *pstSemId; /* Pointer to the semaphor set */ ! 651: int iSemFlg; /* Requested permissions */ ! 652: { ! 653: int iSemMode; ! 654: ! 655: /* Check if resource is alloced */ ! 656: if ((pstSemId->sem_perm.mode & IPC_ALLOC) == 0) { ! 657: u.u_error = EINVAL; ! 658: return -1; ! 659: } ! 660: ! 661: /* We need 9 lower order bits. There is a question what we have to do ! 662: * if someone sets an execute bits on. At this point we just ignore ! 663: * them. ! 664: */ ! 665: iSemMode = iSemFlg & 0666; ! 666: ! 667: /* For superuser or if mode is 0 */ ! 668: if (u.u_uid == 0 || !iSemMode) ! 669: return 0; ! 670: ! 671: /* For owner or creator */ ! 672: if (u.u_uid == pstSemId->sem_perm.uid || u.u_uid ! 673: == pstSemId->sem_perm.cuid) { ! 674: if ((iSemMode & pstSemId->sem_perm.mode) & 0600) ! 675: return 0; ! 676: else { ! 677: u.u_error = EACCES; ! 678: return -1; ! 679: } ! 680: } ! 681: /* For group */ ! 682: if (u.u_gid == pstSemId->sem_perm.gid ! 683: || u.u_gid == pstSemId->sem_perm.cgid) { ! 684: if ((iSemMode & pstSemId->sem_perm.mode) & 060) ! 685: return 0; ! 686: else { ! 687: u.u_error = EACCES; ! 688: return -1; ! 689: } ! 690: } ! 691: /* For the rest of the world */ ! 692: if ((iSemMode & pstSemId->sem_perm.mode) & 06) ! 693: return 0; ! 694: else { ! 695: u.u_error = EACCES; ! 696: return -1; ! 697: } ! 698: /* We should never come here */ ! 699: u.u_error = EACCES; ! 700: return -1; ! 701: } ! 702: ! 703: /* ! 704: * Allocate and clear space for semapohore sets ! 705: * Return 0 on success, -1 and set errno on error. ! 706: */ ! 707: iSemInit() ! 708: { ! 709: unsigned uSize; /* Size of the alloc memmory */ ! 710: ! 711: uSize = sizeof(struct semid_ds) * SEMMNI; ! 712: ! 713: if ((semids = (struct semid_ds *) kalloc(uSize)) == NULL) ! 714: return -1; ! 715: memset((char *) semids, 0, uSize); ! 716: return 0; ! 717: } ! 718: ! 719: /* ! 720: * Check if semaphore number is a valid number. ! 721: */ ! 722: iSanityCheck(iSemNumber) ! 723: int iSemNumber; /* Requested number of the semaphores in the set */ ! 724: { ! 725: /* Just to be on safe side */ ! 726: if (u.u_error) ! 727: return -1; ! 728: ! 729: /* Check if we are inside system limits. */ ! 730: if (iSemNumber >= SEMMSL || iSemNumber < 0) { ! 731: u.u_error = EINVAL; ! 732: return -1; ! 733: } ! 734: return 0; ! 735: } ! 736: ! 737: /* ! 738: * Subtract iValue from the adjust value for the specified ! 739: * semaphore for the specified process. ! 740: */ ! 741: int iSubAdj(iSemId, usSemNum, sValue) ! 742: int iSemId; /* Semaphore set id */ ! 743: unsigned short usSemNum; /* Semaphore number */ ! 744: short sValue; /* Adjust value */ ! 745: { ! 746: PROC *pp; /* Current process */ ! 747: struct sem_undo *unPrev, /* Previous and next pointers to */ ! 748: *unNext; /* sem_undo structures link list */ ! 749: int newAdjust; /* New adjust value */ ! 750: ! 751: pp = SELF; /* Get the current process */ ! 752: ! 753: /* Look if adjust value for semaphore was set */ ! 754: for (unNext = pp->p_semu; unNext != NULL; unNext = unPrev->un_np) { ! 755: if (unNext->un_num == usSemNum && unNext->un_id == iSemId) { ! 756: newAdjust = unNext->un_aoe - sValue; ! 757: if (newAdjust < -SEMVMX || newAdjust > SEMVMX) { ! 758: u.u_error = ERANGE; ! 759: return -1; ! 760: } ! 761: unNext->un_aoe = newAdjust; /* Found and adjust */ ! 762: return 0; ! 763: } ! 764: unPrev = unNext; ! 765: } ! 766: /* There is no adjust value for semaphore. ! 767: * We have to allocate space and creat a new adjust value. ! 768: */ ! 769: if ((unNext = kalloc(sizeof(struct sem_undo))) == NULL) { ! 770: u.u_error = ENOSPC; ! 771: return -1; ! 772: } ! 773: /* Set values for the next entry */ ! 774: unNext->un_np = NULL; ! 775: unNext->un_aoe -= sValue; ! 776: unNext->un_num = usSemNum; ! 777: unNext->un_id = iSemId; ! 778: ! 779: /* Put new entry at the end of link list */ ! 780: if (pp->p_semu == NULL) ! 781: pp->p_semu = unNext; /* New link list */ ! 782: else /* Add entry to the existing list */ ! 783: unPrev->un_np = unNext; /* unPrev is a last entry in the list */ ! 784: return 0; ! 785: } ! 786: ! 787: /* ! 788: * Clear adjust value for all process. ! 789: */ ! 790: void vClearAdj(iSemId, usSemNum) ! 791: int iSemId; /* Semaphore set id */ ! 792: int usSemNum; /* Semaphore number */ ! 793: { ! 794: PROC *pp; /* process */ ! 795: struct sem_undo *unNext; /* sem_undo structures */ ! 796: ! 797: /* Go through all processes and zero the proper undo entry */ ! 798: for (pp = &procq; (pp = pp->p_nforw) != &procq; ) { ! 799: /* Look if adjust value for semaphore was set. */ ! 800: for (unNext = pp->p_semu; unNext != NULL; ! 801: unNext = unNext->un_np) { ! 802: if (unNext->un_num == usSemNum ! 803: && unNext->un_id == iSemId) ! 804: unNext->un_aoe = 0; /* Found */ ! 805: } ! 806: } ! 807: } ! 808: ! 809: /* ! 810: * Adjust all semaphores and remove sem_undo link list. ! 811: */ ! 812: semAllAdjust(pp) ! 813: PROC *pp; ! 814: { ! 815: struct sem_undo *unPrev, /* Previous and next pointers to */ ! 816: *unNext; /* sem_undo structures link list */ ! 817: struct semid_ds *pstSemSet; /* Semaphore set */ ! 818: struct sem *pstSem; /* Semaphore */ ! 819: ! 820: if ((unNext = pp->p_semu) == NULL) ! 821: return; ! 822: ! 823: while (unNext != NULL) { ! 824: pstSemSet = semids + unNext->un_id; /* Requested set */ ! 825: pstSem = pstSemSet->sem_base + unNext->un_num; ! 826: pstSem->semval += unNext->un_aoe; ! 827: pstSem->sempid = SELF->p_pid; ! 828: pstSemSet->sem_ctime = timer.t_time; ! 829: unPrev = unNext; ! 830: unNext = unPrev->un_np; ! 831: kfree(unPrev); ! 832: } ! 833: /*kfree(pp->p_semu);*/ ! 834: pp->p_semu = NULL; ! 835: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.