Annotation of XNU/bsd/kern/sysv_sem.c, revision 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.