Annotation of coherent/b/kernel/io.386/sem386.c, revision 1.1.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.