Annotation of coherent/b/kernel/io.386/sem386.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.