|
|
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 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.