Annotation of coherent/b/STREAMS/coh.386/rlock.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * coh/rlock.c
                      3:  * COHERENT record locking.
                      4:  * Modified 5/92 by steve from tsm's old source.
                      5:  * All record locking functions meet the system V standard.
                      6:  */
                      7: 
                      8: #include <kernel/_sleep.h>
                      9: #include <sys/coherent.h>
                     10: #include <sys/errno.h>
                     11: #include <fcntl.h>
                     12: #include <sys/fd.h>
                     13: #include <sys/proc.h>
                     14: #include <sys/sched.h>
                     15: #include <sys/file.h>
                     16: #include <sys/inode.h>
                     17: #include <sys/uproc.h>
                     18: #include <unistd.h>
                     19: 
                     20: #include <kernel/rlock.h>
                     21: 
                     22: /* Globals. */
                     23: RLOCK  *freerl;
                     24: GATE   rlgate = { 0, 0};
                     25: unsigned RLOCKS = 100;                 /* patchable */
                     26: 
                     27: /* Forward. */
                     28: int            rlock();
                     29: int            rlinit();
                     30: static int     nextblock();
                     31: static int     nextmeet();
                     32: static RLOCK   *getlock();
                     33: static RLOCK   *freelock();
                     34: static int     extract();
                     35: static int     remlock();
                     36: static int     addlock();
                     37: static int     waitlock();
                     38: static int     waiting();
                     39: 
                     40: /*
                     41:  * Record locking.
                     42:  */
                     43: int
                     44: rlock(fdp, cmd, flp) register FD *fdp; register struct flock *flp;
                     45: {
                     46:        register RLOCK  *org;
                     47:        register int    retval;
                     48:        RLOCK           srl;
                     49:        RLOCK           *rlp;
                     50: 
                     51:        org = (RLOCK *)&fdp->f_ip->i_rl;
                     52:        retval = -1;
                     53:        srl.rl_proc = SELF;
                     54:        srl.rl_type = flp->l_type==F_RDLCK ? 0:1;
                     55:        srl.rl_start = flp->l_start;
                     56:        if (flp->l_whence == SEEK_CUR)
                     57:                srl.rl_start += fdp->f_seek;
                     58:        else if (flp->l_whence == SEEK_END)
                     59:                srl.rl_start += fdp->f_ip->i_size;
                     60:        srl.rl_end = srl.rl_start;
                     61:        if (flp->l_len > 0)
                     62:                srl.rl_end += flp->l_len - 1;
                     63:        else if (flp->l_len == 0)
                     64:                srl.rl_end = -1;
                     65:        else {
                     66:                srl.rl_start += flp->l_len;
                     67:                srl.rl_end--;
                     68:        }
                     69:        if (srl.rl_start < 0  ||  srl.rl_end < -1
                     70:            || srl.rl_end != -1 && srl.rl_start > srl.rl_end) {
                     71:                u.u_error = EINVAL;
                     72:                return -1;
                     73:        }
                     74:        lock(rlgate);
                     75:        rlp = org;
                     76:        if (cmd == F_GETLK) {
                     77:                if (!nextblock(&rlp, &srl))
                     78:                        flp->l_type = F_UNLCK;
                     79:                else {
                     80:                        flp->l_type = rlp->rl_type ? F_WRLCK:F_RDLCK;
                     81:                        flp->l_whence = SEEK_SET;
                     82:                        flp->l_start = rlp->rl_start;
                     83:                        if (rlp->rl_end == -1)
                     84:                                flp->l_len = 0;
                     85:                        else
                     86:                                flp->l_len = rlp->rl_end - flp->l_start + 1;
                     87:                        flp->l_pid = rlp->rl_proc->p_pid;
                     88:                }
                     89:                retval = 0;
                     90:        } else if (flp->l_type == F_UNLCK)
                     91:                retval =  remlock(org, &srl);
                     92:        else if (srl.rl_type && !fdp->f_flag & IPW
                     93:              || !srl.rl_type && !fdp->f_flag & IPR)
                     94:                u.u_error = EINVAL;
                     95:        else if (cmd == F_SETLKW)
                     96:                retval = waitlock(org, &srl);
                     97:        else if (!nextblock(&rlp, &srl))
                     98:                retval = addlock(org, &srl);
                     99:        else
                    100:                u.u_error = EACCES;
                    101:        unlock(rlgate);
                    102:        if (cmd != F_GETLK)
                    103:                wakeup(org);
                    104:        return retval;
                    105: }
                    106: 
                    107: /* Allocate and initialize free record lock list. */
                    108: int
                    109: rlinit()
                    110: {
                    111:        register RLOCK  *rl;
                    112: 
                    113:        if (RLOCKS == 0) {
                    114:                freerl = NULL;
                    115:                return 0;
                    116:        }
                    117:        freerl = kalloc(RLOCKS * sizeof(RLOCK));
                    118:        if (freerl == NULL)
                    119:                panic("rlinit: no space for RLOCKs");
                    120:        rl = &freerl[RLOCKS-1];
                    121:        rl->rl_next = NULL;
                    122:        while (--rl >= freerl)
                    123:                rl->rl_next = rl+1;
                    124:        return 1;
                    125: }
                    126: 
                    127: /*
                    128:  * Record locking subroutines.
                    129:  * Most of them assume that rlgate is locked.
                    130:  * The user is guaranteed no unwanted unlocks regardless of error.
                    131:  * rlgate is locked whenever the lock list contents or free list is used.
                    132:  * Be careful if you change anything that these things remain true.
                    133:  */
                    134: 
                    135: /*
                    136:  * In nextblock and nextmeet,
                    137:  * list is a ptr to an RLOCK * which is owned by the caller.
                    138:  * This allows calls to proceed down an rlock list.
                    139:  * These routines should NOT be called with *list == NULL.
                    140:  */
                    141: 
                    142: /* Set *list = next element in list conflicting with lock. */
                    143: static
                    144: int
                    145: nextblock(list, lock) register RLOCK **list, *lock;
                    146: {
                    147:        while (nextmeet(list, lock)) {
                    148:                if (lock->rl_proc != (*list)->rl_proc
                    149:                   && (lock->rl_type || (*list)->rl_type)) {
                    150:                        return 1;
                    151:                }
                    152:        }
                    153:        return 0;
                    154: }
                    155: 
                    156: /* Set *list = next element of list referencing a loc referenced by lock */
                    157: static
                    158: int
                    159: nextmeet(list, lock) RLOCK **list, *lock;
                    160: {
                    161:        register RLOCK  *block;
                    162:        register long top, bot;
                    163: 
                    164:        top = lock->rl_start;
                    165:        bot = lock->rl_end;
                    166:        for (block = (*list)->rl_next; block != NULL; block = block->rl_next) {
                    167:                if (bot == -1) {
                    168:                        if (block->rl_end == -1 || block->rl_end >= top)
                    169:                                break;
                    170:                } else if (bot >= block->rl_start)
                    171:                        if (block->rl_end == -1 || block->rl_end >= top)
                    172:                                break;
                    173:        }
                    174:        if ((*list = block) != NULL)
                    175:                return 1;
                    176:        return 0;
                    177: }
                    178: 
                    179: /* Remove and return a lock from the free list. */
                    180: static
                    181: RLOCK *
                    182: getlock()
                    183: {
                    184:        register RLOCK *rl;
                    185: 
                    186:        rl = freerl;
                    187:        if (rl != NULL)
                    188:                freerl = rl->rl_next;
                    189:        else
                    190:                u.u_error = ENOLCK;
                    191:        return rl;
                    192: }
                    193: 
                    194: /*
                    195:  * Remove element from the lock list beginning at org and add it to the free list.
                    196:  * Return pointer to (what used to be) its predecessor.
                    197:  */
                    198: static
                    199: RLOCK *
                    200: freelock(org, elt) register RLOCK *org, *elt;
                    201: {
                    202:        while (elt != org->rl_next)
                    203:                org = org->rl_next;
                    204:        org->rl_next = elt->rl_next;
                    205:        elt->rl_next = freerl;
                    206:        freerl = elt;
                    207:        return org;
                    208: }
                    209: 
                    210: /*
                    211:  * Remove new lock from old. 
                    212:  * Returns:
                    213:  *     1 if caller should free old.
                    214:  *     0 if caller should do nothing.
                    215:  *     -1 if error (out of locks).
                    216:  */
                    217: static
                    218: int
                    219: extract(old, new) register RLOCK *old, *new;
                    220: {
                    221:        long            tend;
                    222:        register RLOCK  *lock;
                    223: 
                    224:        if (new->rl_start <= old->rl_start) {
                    225:                if (new->rl_end == -1
                    226:                   || old->rl_end != -1 && new->rl_end >= old->rl_end)
                    227:                        return 1;
                    228:                old->rl_start = new->rl_end+1;
                    229:                return 0;
                    230:        }
                    231:        tend = old->rl_end;
                    232:        old->rl_end = new->rl_start - 1;
                    233:        if (new->rl_end == -1
                    234:           ||  tend != -1  &&  new->rl_end >= tend)
                    235:                return 0;
                    236:        if ((lock = getlock()) == NULL) {
                    237:                old->rl_end = tend;
                    238:                return -1;
                    239:        }
                    240:        lock->rl_type = old->rl_type;
                    241:        lock->rl_proc = old->rl_proc;
                    242:        lock->rl_start = new->rl_end+1;
                    243:        lock->rl_end = tend;
                    244:        lock->rl_next = old->rl_next;
                    245:        old->rl_next = lock;
                    246:        return 0;
                    247: }
                    248: 
                    249: /* Extract lock from each element of list. */
                    250: static
                    251: int
                    252: remlock(list, lock) RLOCK *list; register RLOCK *lock;
                    253: {
                    254:        RLOCK *org;
                    255: 
                    256:        org = list;
                    257:        while (nextmeet(&list, lock)) {
                    258:                if (list->rl_proc != lock->rl_proc)
                    259:                        continue;
                    260:                switch(extract(list, lock)) {
                    261:                        case 1:
                    262:                                list = freelock(org, list);
                    263:                        case 0:
                    264:                                break;
                    265:                        default:
                    266:                                return -1;
                    267:                }
                    268:        }
                    269:        return 0;
                    270: }
                    271: 
                    272: /*
                    273:  * Install lock in list.
                    274:  * Combine lock with neighbouring locks of same type and owner.
                    275:  * Get space for new lock (best done here - OK since rllock locked).
                    276:  * Remove old locks (always different type, same owner) and attach new lock.
                    277:  * To avoid removing desired locks, addlock allows redundant locks to appear.
                    278:  * This is always rectified by the future unlock and is rare.
                    279:  */
                    280: static
                    281: int
                    282: addlock(list, lock) RLOCK *list; register RLOCK *lock;
                    283: {
                    284:        RLOCK   *new, *org;
                    285:        register long top, bot;
                    286: 
                    287:        org = list;
                    288:        top = lock->rl_start;
                    289:        bot = lock->rl_end;
                    290:        if (top != 0)
                    291:                lock->rl_start--;
                    292:        if (bot != -1)
                    293:                lock->rl_end++;
                    294:        while (nextmeet(&list, lock)) {
                    295:                if (list->rl_proc != lock->rl_proc
                    296:                   || list->rl_type != lock->rl_type)
                    297:                        continue;
                    298:                if (list->rl_start < top)
                    299:                        top = list->rl_start;
                    300:                if (bot != -1 && (list->rl_end == -1 || list->rl_end >= bot))
                    301:                                bot = list->rl_end;
                    302:                list = freelock(org, list);
                    303:        }
                    304:        if ((new = getlock()) == NULL)
                    305:                return -1;
                    306:        new->rl_proc = lock->rl_proc;
                    307:        new->rl_type = lock->rl_type;
                    308:        lock = new;
                    309:        lock->rl_start = top;
                    310:        lock->rl_end = bot;
                    311:        remlock(org, lock);
                    312:        lock->rl_next = org->rl_next;
                    313:        org->rl_next = lock;
                    314:        return 0;
                    315: }
                    316: 
                    317: /* Sleep until possible to install rl in list then do so. */
                    318: #define cleanup()  SELF->p_prl = NULL;  rl->rl_next = freerl;  freerl = rl
                    319: static
                    320: int
                    321: waitlock(list, srl) RLOCK *list, *srl;
                    322: {
                    323:        register RLOCK *org;
                    324: 
                    325:        org = list;
                    326:        if (nextblock(&list, srl)) {
                    327:                register RLOCK *rl = getlock();
                    328:        
                    329:                if (rl == NULL)
                    330:                        return -1;
                    331:                *rl = *srl;
                    332:                rl->rl_next = org;
                    333:                SELF->p_prl = rl;
                    334:                do {
                    335:                        __sleep_t       sleep;
                    336: 
                    337:                        do {
                    338:                                if (waiting(list->rl_proc)) {
                    339:                                        u.u_error = EDEADLK;
                    340:                                        cleanup();
                    341:                                        return -1;
                    342:                                }
                    343:                        } while (nextblock(&list, rl));
                    344:                        unlock(rlgate);
                    345:                        sleep = x_sleep (org, primed, slpriSigCatch, "rlock");
                    346:                        lock(rlgate);
                    347:                        if (sleep == PROCESS_SIGNALLED) {
                    348:                                u.u_error = EINTR;
                    349:                                cleanup();
                    350:                                return -1;
                    351:                        }
                    352:                        list = org;
                    353:                } while (nextblock(&list, rl));
                    354:                cleanup();
                    355:        }
                    356:        return addlock(org, srl);
                    357: }
                    358: 
                    359: /* True if pp has requested a lock (even indirectly) pending on SELF. */
                    360: static
                    361: int
                    362: waiting(pp) PROC *pp;
                    363: {
                    364:        RLOCK           *list;
                    365:        register RLOCK  *lock;
                    366: 
                    367:        lock = pp->p_prl;
                    368:        if (lock == NULL)
                    369:                return 0;
                    370:        list = lock->rl_next;
                    371:        while (nextblock(&list, lock)) {
                    372:                if (list->rl_proc == SELF)
                    373:                        return 1;
                    374:                if (waiting(list->rl_proc))
                    375:                        return 1;
                    376:        }
                    377:        return 0;
                    378: }
                    379: 
                    380: /* end of coh/rlock.c */

unix.superglobalmegacorp.com

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