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