Annotation of XNU/bsd/kern/sysv_sem.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * Implementation of SVID semaphores
                     24:  *
                     25:  * Author:  Daniel Boulet
                     26:  *
                     27:  * This software is provided ``AS IS'' without any warranties of any kind.
                     28:  */
                     29: 
                     30: #include <sys/param.h>
                     31: #include <sys/systm.h>
                     32: #include <sys/sysproto.h>
                     33: #include <sys/kernel.h>
                     34: #include <sys/proc.h>
                     35: #include <sys/sem.h>
                     36: #include <sys/sysent.h>
                     37: 
                     38: static void seminit __P((void *));
                     39: SYSINIT(sysv_sem, SI_SUB_SYSV_SEM, SI_ORDER_FIRST, seminit, NULL)
                     40: 
                     41: #ifndef _SYS_SYSPROTO_H_
                     42: struct __semctl_args;
                     43: int __semctl __P((struct proc *p, struct __semctl_args *uap));
                     44: struct semget_args;
                     45: int semget __P((struct proc *p, struct semget_args *uap));
                     46: struct semop_args;
                     47: int semop __P((struct proc *p, struct semop_args *uap));
                     48: struct semconfig_args;
                     49: int semconfig __P((struct proc *p, struct semconfig_args *uap));
                     50: #endif
                     51: 
                     52: static struct sem_undo *semu_alloc __P((struct proc *p));
                     53: static int semundo_adjust __P((struct proc *p, struct sem_undo **supptr, 
                     54:                int semid, int semnum, int adjval));
                     55: static void semundo_clear __P((int semid, int semnum));
                     56: 
                     57: /* XXX casting to (sy_call_t *) is bogus, as usual. */
                     58: static sy_call_t *semcalls[] = {
                     59:        (sy_call_t *)__semctl, (sy_call_t *)semget,
                     60:        (sy_call_t *)semop, (sy_call_t *)semconfig
                     61: };
                     62: 
                     63: static int     semtot = 0;
                     64: struct semid_ds *sema;         /* semaphore id pool */
                     65: struct sem *sem;               /* semaphore pool */
                     66: static struct sem_undo *semu_list;     /* list of active undo structures */
                     67: int    *semu;                  /* undo structure pool */
                     68: 
                     69: static struct proc *semlock_holder = NULL;
                     70: 
                     71: void
                     72: seminit(dummy)
                     73:        void *dummy;
                     74: {
                     75:        register int i;
                     76: 
                     77:        if (sema == NULL)
                     78:                panic("sema is NULL");
                     79:        if (semu == NULL)
                     80:                panic("semu is NULL");
                     81: 
                     82:        for (i = 0; i < seminfo.semmni; i++) {
                     83:                sema[i].sem_base = 0;
                     84:                sema[i].sem_perm.mode = 0;
                     85:        }
                     86:        for (i = 0; i < seminfo.semmnu; i++) {
                     87:                register struct sem_undo *suptr = SEMU(i);
                     88:                suptr->un_proc = NULL;
                     89:        }
                     90:        semu_list = NULL;
                     91: }
                     92: 
                     93: /*
                     94:  * Entry point for all SEM calls
                     95:  */
                     96: int
                     97: semsys(p, uap)
                     98:        struct proc *p;
                     99:        /* XXX actually varargs. */
                    100:        struct semsys_args /* {
                    101:                u_int   which;
                    102:                int     a2;
                    103:                int     a3;
                    104:                int     a4;
                    105:                int     a5;
                    106:        } */ *uap;
                    107: {
                    108: 
                    109:        while (semlock_holder != NULL && semlock_holder != p)
                    110:                (void) tsleep((caddr_t)&semlock_holder, (PZERO - 4), "semsys", 0);
                    111: 
                    112:        if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0]))
                    113:                return (EINVAL);
                    114:        return ((*semcalls[uap->which])(p, &uap->a2));
                    115: }
                    116: 
                    117: /*
                    118:  * Lock or unlock the entire semaphore facility.
                    119:  *
                    120:  * This will probably eventually evolve into a general purpose semaphore
                    121:  * facility status enquiry mechanism (I don't like the "read /dev/kmem"
                    122:  * approach currently taken by ipcs and the amount of info that we want
                    123:  * to be able to extract for ipcs is probably beyond what the capability
                    124:  * of the getkerninfo facility.
                    125:  *
                    126:  * At the time that the current version of semconfig was written, ipcs is
                    127:  * the only user of the semconfig facility.  It uses it to ensure that the
                    128:  * semaphore facility data structures remain static while it fishes around
                    129:  * in /dev/kmem.
                    130:  */
                    131: 
                    132: #ifndef _SYS_SYSPROTO_H_
                    133: struct semconfig_args {
                    134:        semconfig_ctl_t flag;
                    135: };
                    136: #endif
                    137: 
                    138: int
                    139: semconfig(p, uap)
                    140:        struct proc *p;
                    141:        struct semconfig_args *uap;
                    142: {
                    143:        int eval = 0;
                    144: 
                    145:        switch (uap->flag) {
                    146:        case SEM_CONFIG_FREEZE:
                    147:                semlock_holder = p;
                    148:                break;
                    149: 
                    150:        case SEM_CONFIG_THAW:
                    151:                semlock_holder = NULL;
                    152:                wakeup((caddr_t)&semlock_holder);
                    153:                break;
                    154: 
                    155:        default:
                    156:                printf("semconfig: unknown flag parameter value (%d) - ignored\n",
                    157:                    uap->flag);
                    158:                eval = EINVAL;
                    159:                break;
                    160:        }
                    161: 
                    162:        p->p_retval[0] = 0;
                    163:        return(eval);
                    164: }
                    165: 
                    166: /*
                    167:  * Allocate a new sem_undo structure for a process
                    168:  * (returns ptr to structure or NULL if no more room)
                    169:  */
                    170: 
                    171: static struct sem_undo *
                    172: semu_alloc(p)
                    173:        struct proc *p;
                    174: {
                    175:        register int i;
                    176:        register struct sem_undo *suptr;
                    177:        register struct sem_undo **supptr;
                    178:        int attempt;
                    179: 
                    180:        /*
                    181:         * Try twice to allocate something.
                    182:         * (we'll purge any empty structures after the first pass so
                    183:         * two passes are always enough)
                    184:         */
                    185: 
                    186:        for (attempt = 0; attempt < 2; attempt++) {
                    187:                /*
                    188:                 * Look for a free structure.
                    189:                 * Fill it in and return it if we find one.
                    190:                 */
                    191: 
                    192:                for (i = 0; i < seminfo.semmnu; i++) {
                    193:                        suptr = SEMU(i);
                    194:                        if (suptr->un_proc == NULL) {
                    195:                                suptr->un_next = semu_list;
                    196:                                semu_list = suptr;
                    197:                                suptr->un_cnt = 0;
                    198:                                suptr->un_proc = p;
                    199:                                return(suptr);
                    200:                        }
                    201:                }
                    202: 
                    203:                /*
                    204:                 * We didn't find a free one, if this is the first attempt
                    205:                 * then try to free some structures.
                    206:                 */
                    207: 
                    208:                if (attempt == 0) {
                    209:                        /* All the structures are in use - try to free some */
                    210:                        int did_something = 0;
                    211: 
                    212:                        supptr = &semu_list;
                    213:                        while ((suptr = *supptr) != NULL) {
                    214:                                if (suptr->un_cnt == 0)  {
                    215:                                        suptr->un_proc = NULL;
                    216:                                        *supptr = suptr->un_next;
                    217:                                        did_something = 1;
                    218:                                } else
                    219:                                        supptr = &(suptr->un_next);
                    220:                        }
                    221: 
                    222:                        /* If we didn't free anything then just give-up */
                    223:                        if (!did_something)
                    224:                                return(NULL);
                    225:                } else {
                    226:                        /*
                    227:                         * The second pass failed even though we freed
                    228:                         * something after the first pass!
                    229:                         * This is IMPOSSIBLE!
                    230:                         */
                    231:                        panic("semu_alloc - second attempt failed");
                    232:                }
                    233:        }
                    234:        return (NULL);
                    235: }
                    236: 
                    237: /*
                    238:  * Adjust a particular entry for a particular proc
                    239:  */
                    240: 
                    241: static int
                    242: semundo_adjust(p, supptr, semid, semnum, adjval)
                    243:        register struct proc *p;
                    244:        struct sem_undo **supptr;
                    245:        int semid, semnum;
                    246:        int adjval;
                    247: {
                    248:        register struct sem_undo *suptr;
                    249:        register struct undo *sunptr;
                    250:        int i;
                    251: 
                    252:        /* Look for and remember the sem_undo if the caller doesn't provide
                    253:           it */
                    254: 
                    255:        suptr = *supptr;
                    256:        if (suptr == NULL) {
                    257:                for (suptr = semu_list; suptr != NULL;
                    258:                    suptr = suptr->un_next) {
                    259:                        if (suptr->un_proc == p) {
                    260:                                *supptr = suptr;
                    261:                                break;
                    262:                        }
                    263:                }
                    264:                if (suptr == NULL) {
                    265:                        if (adjval == 0)
                    266:                                return(0);
                    267:                        suptr = semu_alloc(p);
                    268:                        if (suptr == NULL)
                    269:                                return(ENOSPC);
                    270:                        *supptr = suptr;
                    271:                }
                    272:        }
                    273: 
                    274:        /*
                    275:         * Look for the requested entry and adjust it (delete if adjval becomes
                    276:         * 0).
                    277:         */
                    278:        sunptr = &suptr->un_ent[0];
                    279:        for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
                    280:                if (sunptr->un_id != semid || sunptr->un_num != semnum)
                    281:                        continue;
                    282:                if (adjval == 0)
                    283:                        sunptr->un_adjval = 0;
                    284:                else
                    285:                        sunptr->un_adjval += adjval;
                    286:                if (sunptr->un_adjval == 0) {
                    287:                        suptr->un_cnt--;
                    288:                        if (i < suptr->un_cnt)
                    289:                                suptr->un_ent[i] =
                    290:                                    suptr->un_ent[suptr->un_cnt];
                    291:                }
                    292:                return(0);
                    293:        }
                    294: 
                    295:        /* Didn't find the right entry - create it */
                    296:        if (adjval == 0)
                    297:                return(0);
                    298:        if (suptr->un_cnt != seminfo.semume) {
                    299:                sunptr = &suptr->un_ent[suptr->un_cnt];
                    300:                suptr->un_cnt++;
                    301:                sunptr->un_adjval = adjval;
                    302:                sunptr->un_id = semid; sunptr->un_num = semnum;
                    303:        } else
                    304:                return(EINVAL);
                    305:        return(0);
                    306: }
                    307: 
                    308: static void
                    309: semundo_clear(semid, semnum)
                    310:        int semid, semnum;
                    311: {
                    312:        register struct sem_undo *suptr;
                    313: 
                    314:        for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) {
                    315:                register struct undo *sunptr = &suptr->un_ent[0];
                    316:                register int i = 0;
                    317: 
                    318:                while (i < suptr->un_cnt) {
                    319:                        if (sunptr->un_id == semid) {
                    320:                                if (semnum == -1 || sunptr->un_num == semnum) {
                    321:                                        suptr->un_cnt--;
                    322:                                        if (i < suptr->un_cnt) {
                    323:                                                suptr->un_ent[i] =
                    324:                                                  suptr->un_ent[suptr->un_cnt];
                    325:                                                continue;
                    326:                                        }
                    327:                                }
                    328:                                if (semnum != -1)
                    329:                                        break;
                    330:                        }
                    331:                        i++, sunptr++;
                    332:                }
                    333:        }
                    334: }
                    335: 
                    336: /*
                    337:  * Note that the user-mode half of this passes a union, not a pointer
                    338:  */
                    339: #ifndef _SYS_SYSPROTO_H_
                    340: struct __semctl_args {
                    341:        int     semid;
                    342:        int     semnum;
                    343:        int     cmd;
                    344:        union   semun *arg;
                    345: };
                    346: #endif
                    347: 
                    348: int
                    349: __semctl(p, uap)
                    350:        struct proc *p;
                    351:        register struct __semctl_args *uap;
                    352: {
                    353:        int semid = uap->semid;
                    354:        int semnum = uap->semnum;
                    355:        int cmd = uap->cmd;
                    356:        union semun *arg = uap->arg;
                    357:        union semun real_arg;
                    358:        struct ucred *cred = p->p_ucred;
                    359:        int i, rval, eval;
                    360:        struct semid_ds sbuf;
                    361:        register struct semid_ds *semaptr;
                    362: 
                    363: #ifdef SEM_DEBUG
                    364:        printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg);
                    365: #endif
                    366: 
                    367:        semid = IPCID_TO_IX(semid);
                    368:        if (semid < 0 || semid >= seminfo.semmsl)
                    369:                return(EINVAL);
                    370: 
                    371:        semaptr = &sema[semid];
                    372:        if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
                    373:            semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
                    374:                return(EINVAL);
                    375: 
                    376:        eval = 0;
                    377:        rval = 0;
                    378: 
                    379:        switch (cmd) {
                    380:        case IPC_RMID:
                    381:                if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M)))
                    382:                        return(eval);
                    383:                semaptr->sem_perm.cuid = cred->cr_uid;
                    384:                semaptr->sem_perm.uid = cred->cr_uid;
                    385:                semtot -= semaptr->sem_nsems;
                    386:                for (i = semaptr->sem_base - sem; i < semtot; i++)
                    387:                        sem[i] = sem[i + semaptr->sem_nsems];
                    388:                for (i = 0; i < seminfo.semmni; i++) {
                    389:                        if ((sema[i].sem_perm.mode & SEM_ALLOC) &&
                    390:                            sema[i].sem_base > semaptr->sem_base)
                    391:                                sema[i].sem_base -= semaptr->sem_nsems;
                    392:                }
                    393:                semaptr->sem_perm.mode = 0;
                    394:                semundo_clear(semid, -1);
                    395:                wakeup((caddr_t)semaptr);
                    396:                break;
                    397: 
                    398:        case IPC_SET:
                    399:                if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_M)))
                    400:                        return(eval);
                    401:                if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
                    402:                        return(eval);
                    403:                if ((eval = copyin(real_arg.buf, (caddr_t)&sbuf,
                    404:                    sizeof(sbuf))) != 0)
                    405:                        return(eval);
                    406:                semaptr->sem_perm.uid = sbuf.sem_perm.uid;
                    407:                semaptr->sem_perm.gid = sbuf.sem_perm.gid;
                    408:                semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
                    409:                    (sbuf.sem_perm.mode & 0777);
                    410:                semaptr->sem_ctime = time_second;
                    411:                break;
                    412: 
                    413:        case IPC_STAT:
                    414:                if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
                    415:                        return(eval);
                    416:                if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
                    417:                        return(eval);
                    418:                eval = copyout((caddr_t)semaptr, real_arg.buf,
                    419:                    sizeof(struct semid_ds));
                    420:                break;
                    421: 
                    422:        case GETNCNT:
                    423:                if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
                    424:                        return(eval);
                    425:                if (semnum < 0 || semnum >= semaptr->sem_nsems)
                    426:                        return(EINVAL);
                    427:                rval = semaptr->sem_base[semnum].semncnt;
                    428:                break;
                    429: 
                    430:        case GETPID:
                    431:                if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
                    432:                        return(eval);
                    433:                if (semnum < 0 || semnum >= semaptr->sem_nsems)
                    434:                        return(EINVAL);
                    435:                rval = semaptr->sem_base[semnum].sempid;
                    436:                break;
                    437: 
                    438:        case GETVAL:
                    439:                if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
                    440:                        return(eval);
                    441:                if (semnum < 0 || semnum >= semaptr->sem_nsems)
                    442:                        return(EINVAL);
                    443:                rval = semaptr->sem_base[semnum].semval;
                    444:                break;
                    445: 
                    446:        case GETALL:
                    447:                if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
                    448:                        return(eval);
                    449:                if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
                    450:                        return(eval);
                    451:                for (i = 0; i < semaptr->sem_nsems; i++) {
                    452:                        eval = copyout((caddr_t)&semaptr->sem_base[i].semval,
                    453:                            &real_arg.array[i], sizeof(real_arg.array[0]));
                    454:                        if (eval != 0)
                    455:                                break;
                    456:                }
                    457:                break;
                    458: 
                    459:        case GETZCNT:
                    460:                if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
                    461:                        return(eval);
                    462:                if (semnum < 0 || semnum >= semaptr->sem_nsems)
                    463:                        return(EINVAL);
                    464:                rval = semaptr->sem_base[semnum].semzcnt;
                    465:                break;
                    466: 
                    467:        case SETVAL:
                    468:                if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
                    469:                        return(eval);
                    470:                if (semnum < 0 || semnum >= semaptr->sem_nsems)
                    471:                        return(EINVAL);
                    472:                if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
                    473:                        return(eval);
                    474:                semaptr->sem_base[semnum].semval = real_arg.val;
                    475:                semundo_clear(semid, semnum);
                    476:                wakeup((caddr_t)semaptr);
                    477:                break;
                    478: 
                    479:        case SETALL:
                    480:                if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
                    481:                        return(eval);
                    482:                if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
                    483:                        return(eval);
                    484:                for (i = 0; i < semaptr->sem_nsems; i++) {
                    485:                        eval = copyin(&real_arg.array[i],
                    486:                            (caddr_t)&semaptr->sem_base[i].semval,
                    487:                            sizeof(real_arg.array[0]));
                    488:                        if (eval != 0)
                    489:                                break;
                    490:                }
                    491:                semundo_clear(semid, -1);
                    492:                wakeup((caddr_t)semaptr);
                    493:                break;
                    494: 
                    495:        default:
                    496:                return(EINVAL);
                    497:        }
                    498: 
                    499:        if (eval == 0)
                    500:                p->p_retval[0] = rval;
                    501:        return(eval);
                    502: }
                    503: 
                    504: #ifndef _SYS_SYSPROTO_H_
                    505: struct semget_args {
                    506:        key_t   key;
                    507:        int     nsems;
                    508:        int     semflg;
                    509: };
                    510: #endif
                    511: 
                    512: int
                    513: semget(p, uap)
                    514:        struct proc *p;
                    515:        register struct semget_args *uap;
                    516: {
                    517:        int semid, eval;
                    518:        int key = uap->key;
                    519:        int nsems = uap->nsems;
                    520:        int semflg = uap->semflg;
                    521:        struct ucred *cred = p->p_ucred;
                    522: 
                    523: #ifdef SEM_DEBUG
                    524:        printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg);
                    525: #endif
                    526: 
                    527:        if (key != IPC_PRIVATE) {
                    528:                for (semid = 0; semid < seminfo.semmni; semid++) {
                    529:                        if ((sema[semid].sem_perm.mode & SEM_ALLOC) &&
                    530:                            sema[semid].sem_perm.key == key)
                    531:                                break;
                    532:                }
                    533:                if (semid < seminfo.semmni) {
                    534: #ifdef SEM_DEBUG
                    535:                        printf("found public key\n");
                    536: #endif
                    537:                        if ((eval = ipcperm(cred, &sema[semid].sem_perm,
                    538:                            semflg & 0700)))
                    539:                                return(eval);
                    540:                        if (nsems > 0 && sema[semid].sem_nsems < nsems) {
                    541: #ifdef SEM_DEBUG
                    542:                                printf("too small\n");
                    543: #endif
                    544:                                return(EINVAL);
                    545:                        }
                    546:                        if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
                    547: #ifdef SEM_DEBUG
                    548:                                printf("not exclusive\n");
                    549: #endif
                    550:                                return(EEXIST);
                    551:                        }
                    552:                        goto found;
                    553:                }
                    554:        }
                    555: 
                    556: #ifdef SEM_DEBUG
                    557:        printf("need to allocate the semid_ds\n");
                    558: #endif
                    559:        if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
                    560:                if (nsems <= 0 || nsems > seminfo.semmsl) {
                    561: #ifdef SEM_DEBUG
                    562:                        printf("nsems out of range (0<%d<=%d)\n", nsems,
                    563:                            seminfo.semmsl);
                    564: #endif
                    565:                        return(EINVAL);
                    566:                }
                    567:                if (nsems > seminfo.semmns - semtot) {
                    568: #ifdef SEM_DEBUG
                    569:                        printf("not enough semaphores left (need %d, got %d)\n",
                    570:                            nsems, seminfo.semmns - semtot);
                    571: #endif
                    572:                        return(ENOSPC);
                    573:                }
                    574:                for (semid = 0; semid < seminfo.semmni; semid++) {
                    575:                        if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0)
                    576:                                break;
                    577:                }
                    578:                if (semid == seminfo.semmni) {
                    579: #ifdef SEM_DEBUG
                    580:                        printf("no more semid_ds's available\n");
                    581: #endif
                    582:                        return(ENOSPC);
                    583:                }
                    584: #ifdef SEM_DEBUG
                    585:                printf("semid %d is available\n", semid);
                    586: #endif
                    587:                sema[semid].sem_perm.key = key;
                    588:                sema[semid].sem_perm.cuid = cred->cr_uid;
                    589:                sema[semid].sem_perm.uid = cred->cr_uid;
                    590:                sema[semid].sem_perm.cgid = cred->cr_gid;
                    591:                sema[semid].sem_perm.gid = cred->cr_gid;
                    592:                sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
                    593:                sema[semid].sem_perm.seq =
                    594:                    (sema[semid].sem_perm.seq + 1) & 0x7fff;
                    595:                sema[semid].sem_nsems = nsems;
                    596:                sema[semid].sem_otime = 0;
                    597:                sema[semid].sem_ctime = time_second;
                    598:                sema[semid].sem_base = &sem[semtot];
                    599:                semtot += nsems;
                    600:                bzero(sema[semid].sem_base,
                    601:                    sizeof(sema[semid].sem_base[0])*nsems);
                    602: #ifdef SEM_DEBUG
                    603:                printf("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base,
                    604:                    &sem[semtot]);
                    605: #endif
                    606:        } else {
                    607: #ifdef SEM_DEBUG
                    608:                printf("didn't find it and wasn't asked to create it\n");
                    609: #endif
                    610:                return(ENOENT);
                    611:        }
                    612: 
                    613: found:
                    614:        p->p_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm);
                    615:        return(0);
                    616: }
                    617: 
                    618: #ifndef _SYS_SYSPROTO_H_
                    619: struct semop_args {
                    620:        int     semid;
                    621:        struct  sembuf *sops;
                    622:        int     nsops;
                    623: };
                    624: #endif
                    625: 
                    626: int
                    627: semop(p, uap)
                    628:        struct proc *p;
                    629:        register struct semop_args *uap;
                    630: {
                    631:        int semid = uap->semid;
                    632:        int nsops = uap->nsops;
                    633:        struct sembuf sops[MAX_SOPS];
                    634:        register struct semid_ds *semaptr;
                    635:        register struct sembuf *sopptr;
                    636:        register struct sem *semptr;
                    637:        struct sem_undo *suptr = NULL;
                    638:        struct ucred *cred = p->p_ucred;
                    639:        int i, j, eval;
                    640:        int do_wakeup, do_undos;
                    641: 
                    642: #ifdef SEM_DEBUG
                    643:        printf("call to semop(%d, 0x%x, %d)\n", semid, sops, nsops);
                    644: #endif
                    645: 
                    646:        semid = IPCID_TO_IX(semid);     /* Convert back to zero origin */
                    647: 
                    648:        if (semid < 0 || semid >= seminfo.semmsl)
                    649:                return(EINVAL);
                    650: 
                    651:        semaptr = &sema[semid];
                    652:        if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
                    653:                return(EINVAL);
                    654:        if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
                    655:                return(EINVAL);
                    656: 
                    657:        if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) {
                    658: #ifdef SEM_DEBUG
                    659:                printf("eval = %d from ipaccess\n", eval);
                    660: #endif
                    661:                return(eval);
                    662:        }
                    663: 
                    664:        if (nsops > MAX_SOPS) {
                    665: #ifdef SEM_DEBUG
                    666:                printf("too many sops (max=%d, nsops=%d)\n", MAX_SOPS, nsops);
                    667: #endif
                    668:                return(E2BIG);
                    669:        }
                    670: 
                    671:        if ((eval = copyin(uap->sops, &sops, nsops * sizeof(sops[0]))) != 0) {
                    672: #ifdef SEM_DEBUG
                    673:                printf("eval = %d from copyin(%08x, %08x, %d)\n", eval,
                    674:                    uap->sops, &sops, nsops * sizeof(sops[0]));
                    675: #endif
                    676:                return(eval);
                    677:        }
                    678: 
                    679:        /*
                    680:         * Loop trying to satisfy the vector of requests.
                    681:         * If we reach a point where we must wait, any requests already
                    682:         * performed are rolled back and we go to sleep until some other
                    683:         * process wakes us up.  At this point, we start all over again.
                    684:         *
                    685:         * This ensures that from the perspective of other tasks, a set
                    686:         * of requests is atomic (never partially satisfied).
                    687:         */
                    688:        do_undos = 0;
                    689: 
                    690:        for (;;) {
                    691:                do_wakeup = 0;
                    692: 
                    693:                for (i = 0; i < nsops; i++) {
                    694:                        sopptr = &sops[i];
                    695: 
                    696:                        if (sopptr->sem_num >= semaptr->sem_nsems)
                    697:                                return(EFBIG);
                    698: 
                    699:                        semptr = &semaptr->sem_base[sopptr->sem_num];
                    700: 
                    701: #ifdef SEM_DEBUG
                    702:                        printf("semop:  semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
                    703:                            semaptr, semaptr->sem_base, semptr,
                    704:                            sopptr->sem_num, semptr->semval, sopptr->sem_op,
                    705:                            (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait");
                    706: #endif
                    707: 
                    708:                        if (sopptr->sem_op < 0) {
                    709:                                if (semptr->semval + sopptr->sem_op < 0) {
                    710: #ifdef SEM_DEBUG
                    711:                                        printf("semop:  can't do it now\n");
                    712: #endif
                    713:                                        break;
                    714:                                } else {
                    715:                                        semptr->semval += sopptr->sem_op;
                    716:                                        if (semptr->semval == 0 &&
                    717:                                            semptr->semzcnt > 0)
                    718:                                                do_wakeup = 1;
                    719:                                }
                    720:                                if (sopptr->sem_flg & SEM_UNDO)
                    721:                                        do_undos = 1;
                    722:                        } else if (sopptr->sem_op == 0) {
                    723:                                if (semptr->semval > 0) {
                    724: #ifdef SEM_DEBUG
                    725:                                        printf("semop:  not zero now\n");
                    726: #endif
                    727:                                        break;
                    728:                                }
                    729:                        } else {
                    730:                                if (semptr->semncnt > 0)
                    731:                                        do_wakeup = 1;
                    732:                                semptr->semval += sopptr->sem_op;
                    733:                                if (sopptr->sem_flg & SEM_UNDO)
                    734:                                        do_undos = 1;
                    735:                        }
                    736:                }
                    737: 
                    738:                /*
                    739:                 * Did we get through the entire vector?
                    740:                 */
                    741:                if (i >= nsops)
                    742:                        goto done;
                    743: 
                    744:                /*
                    745:                 * No ... rollback anything that we've already done
                    746:                 */
                    747: #ifdef SEM_DEBUG
                    748:                printf("semop:  rollback 0 through %d\n", i-1);
                    749: #endif
                    750:                for (j = 0; j < i; j++)
                    751:                        semaptr->sem_base[sops[j].sem_num].semval -=
                    752:                            sops[j].sem_op;
                    753: 
                    754:                /*
                    755:                 * If the request that we couldn't satisfy has the
                    756:                 * NOWAIT flag set then return with EAGAIN.
                    757:                 */
                    758:                if (sopptr->sem_flg & IPC_NOWAIT)
                    759:                        return(EAGAIN);
                    760: 
                    761:                if (sopptr->sem_op == 0)
                    762:                        semptr->semzcnt++;
                    763:                else
                    764:                        semptr->semncnt++;
                    765: 
                    766: #ifdef SEM_DEBUG
                    767:                printf("semop:  good night!\n");
                    768: #endif
                    769:                eval = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH,
                    770:                    "semwait", 0);
                    771: #ifdef SEM_DEBUG
                    772:                printf("semop:  good morning (eval=%d)!\n", eval);
                    773: #endif
                    774: 
                    775:                suptr = NULL;   /* sem_undo may have been reallocated */
                    776: 
                    777:                if (eval != 0)
                    778:                        return(EINTR);
                    779: #ifdef SEM_DEBUG
                    780:                printf("semop:  good morning!\n");
                    781: #endif
                    782: 
                    783:                /*
                    784:                 * Make sure that the semaphore still exists
                    785:                 */
                    786:                if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
                    787:                    semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
                    788:                        /* The man page says to return EIDRM. */
                    789:                        /* Unfortunately, BSD doesn't define that code! */
                    790: #ifdef EIDRM
                    791:                        return(EIDRM);
                    792: #else
                    793:                        return(EINVAL);
                    794: #endif
                    795:                }
                    796: 
                    797:                /*
                    798:                 * The semaphore is still alive.  Readjust the count of
                    799:                 * waiting processes.
                    800:                 */
                    801:                if (sopptr->sem_op == 0)
                    802:                        semptr->semzcnt--;
                    803:                else
                    804:                        semptr->semncnt--;
                    805:        }
                    806: 
                    807: done:
                    808:        /*
                    809:         * Process any SEM_UNDO requests.
                    810:         */
                    811:        if (do_undos) {
                    812:                for (i = 0; i < nsops; i++) {
                    813:                        /*
                    814:                         * We only need to deal with SEM_UNDO's for non-zero
                    815:                         * op's.
                    816:                         */
                    817:                        int adjval;
                    818: 
                    819:                        if ((sops[i].sem_flg & SEM_UNDO) == 0)
                    820:                                continue;
                    821:                        adjval = sops[i].sem_op;
                    822:                        if (adjval == 0)
                    823:                                continue;
                    824:                        eval = semundo_adjust(p, &suptr, semid,
                    825:                            sops[i].sem_num, -adjval);
                    826:                        if (eval == 0)
                    827:                                continue;
                    828: 
                    829:                        /*
                    830:                         * Oh-Oh!  We ran out of either sem_undo's or undo's.
                    831:                         * Rollback the adjustments to this point and then
                    832:                         * rollback the semaphore ups and down so we can return
                    833:                         * with an error with all structures restored.  We
                    834:                         * rollback the undo's in the exact reverse order that
                    835:                         * we applied them.  This guarantees that we won't run
                    836:                         * out of space as we roll things back out.
                    837:                         */
                    838:                        for (j = i - 1; j >= 0; j--) {
                    839:                                if ((sops[j].sem_flg & SEM_UNDO) == 0)
                    840:                                        continue;
                    841:                                adjval = sops[j].sem_op;
                    842:                                if (adjval == 0)
                    843:                                        continue;
                    844:                                if (semundo_adjust(p, &suptr, semid,
                    845:                                    sops[j].sem_num, adjval) != 0)
                    846:                                        panic("semop - can't undo undos");
                    847:                        }
                    848: 
                    849:                        for (j = 0; j < nsops; j++)
                    850:                                semaptr->sem_base[sops[j].sem_num].semval -=
                    851:                                    sops[j].sem_op;
                    852: 
                    853: #ifdef SEM_DEBUG
                    854:                        printf("eval = %d from semundo_adjust\n", eval);
                    855: #endif
                    856:                        return(eval);
                    857:                } /* loop through the sops */
                    858:        } /* if (do_undos) */
                    859: 
                    860:        /* We're definitely done - set the sempid's */
                    861:        for (i = 0; i < nsops; i++) {
                    862:                sopptr = &sops[i];
                    863:                semptr = &semaptr->sem_base[sopptr->sem_num];
                    864:                semptr->sempid = p->p_pid;
                    865:        }
                    866: 
                    867:        /* Do a wakeup if any semaphore was up'd. */
                    868:        if (do_wakeup) {
                    869: #ifdef SEM_DEBUG
                    870:                printf("semop:  doing wakeup\n");
                    871: #ifdef SEM_WAKEUP
                    872:                sem_wakeup((caddr_t)semaptr);
                    873: #else
                    874:                wakeup((caddr_t)semaptr);
                    875: #endif
                    876:                printf("semop:  back from wakeup\n");
                    877: #else
                    878:                wakeup((caddr_t)semaptr);
                    879: #endif
                    880:        }
                    881: #ifdef SEM_DEBUG
                    882:        printf("semop:  done\n");
                    883: #endif
                    884:        p->p_retval[0] = 0;
                    885:        return(0);
                    886: }
                    887: 
                    888: /*
                    889:  * Go through the undo structures for this process and apply the adjustments to
                    890:  * semaphores.
                    891:  */
                    892: void
                    893: semexit(p)
                    894:        struct proc *p;
                    895: {
                    896:        register struct sem_undo *suptr;
                    897:        register struct sem_undo **supptr;
                    898:        int did_something;
                    899: 
                    900:        /*
                    901:         * If somebody else is holding the global semaphore facility lock
                    902:         * then sleep until it is released.
                    903:         */
                    904:        while (semlock_holder != NULL && semlock_holder != p) {
                    905: #ifdef SEM_DEBUG
                    906:                printf("semaphore facility locked - sleeping ...\n");
                    907: #endif
                    908:                (void) tsleep((caddr_t)&semlock_holder, (PZERO - 4), "semext", 0);
                    909:        }
                    910: 
                    911:        did_something = 0;
                    912: 
                    913:        /*
                    914:         * Go through the chain of undo vectors looking for one
                    915:         * associated with this process.
                    916:         */
                    917: 
                    918:        for (supptr = &semu_list; (suptr = *supptr) != NULL;
                    919:            supptr = &suptr->un_next) {
                    920:                if (suptr->un_proc == p)
                    921:                        break;
                    922:        }
                    923: 
                    924:        if (suptr == NULL)
                    925:                goto unlock;
                    926: 
                    927: #ifdef SEM_DEBUG
                    928:        printf("proc @%08x has undo structure with %d entries\n", p,
                    929:            suptr->un_cnt);
                    930: #endif
                    931: 
                    932:        /*
                    933:         * If there are any active undo elements then process them.
                    934:         */
                    935:        if (suptr->un_cnt > 0) {
                    936:                int ix;
                    937: 
                    938:                for (ix = 0; ix < suptr->un_cnt; ix++) {
                    939:                        int semid = suptr->un_ent[ix].un_id;
                    940:                        int semnum = suptr->un_ent[ix].un_num;
                    941:                        int adjval = suptr->un_ent[ix].un_adjval;
                    942:                        struct semid_ds *semaptr;
                    943: 
                    944:                        semaptr = &sema[semid];
                    945:                        if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
                    946:                                panic("semexit - semid not allocated");
                    947:                        if (semnum >= semaptr->sem_nsems)
                    948:                                panic("semexit - semnum out of range");
                    949: 
                    950: #ifdef SEM_DEBUG
                    951:                        printf("semexit:  %08x id=%d num=%d(adj=%d) ; sem=%d\n",
                    952:                            suptr->un_proc, suptr->un_ent[ix].un_id,
                    953:                            suptr->un_ent[ix].un_num,
                    954:                            suptr->un_ent[ix].un_adjval,
                    955:                            semaptr->sem_base[semnum].semval);
                    956: #endif
                    957: 
                    958:                        if (adjval < 0) {
                    959:                                if (semaptr->sem_base[semnum].semval < -adjval)
                    960:                                        semaptr->sem_base[semnum].semval = 0;
                    961:                                else
                    962:                                        semaptr->sem_base[semnum].semval +=
                    963:                                            adjval;
                    964:                        } else
                    965:                                semaptr->sem_base[semnum].semval += adjval;
                    966: 
                    967: #ifdef SEM_WAKEUP
                    968:                        sem_wakeup((caddr_t)semaptr);
                    969: #else
                    970:                        wakeup((caddr_t)semaptr);
                    971: #endif
                    972: #ifdef SEM_DEBUG
                    973:                        printf("semexit:  back from wakeup\n");
                    974: #endif
                    975:                }
                    976:        }
                    977: 
                    978:        /*
                    979:         * Deallocate the undo vector.
                    980:         */
                    981: #ifdef SEM_DEBUG
                    982:        printf("removing vector\n");
                    983: #endif
                    984:        suptr->un_proc = NULL;
                    985:        *supptr = suptr->un_next;
                    986: 
                    987: unlock:
                    988:        /*
                    989:         * If the exiting process is holding the global semaphore facility
                    990:         * lock then release it.
                    991:         */
                    992:        if (semlock_holder == p) {
                    993:                semlock_holder = NULL;
                    994:                wakeup((caddr_t)&semlock_holder);
                    995:        }
                    996: }

unix.superglobalmegacorp.com

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