1: /* Program Name: vmf.c 2: * Author: S.M. Schultz 3: * 4: * ----------- Modification History ------------ 5: * Version Date Reason For Modification 6: * 1.0 1JAN80 1. Initial release. 7: * 2.0 31Mar83 2. Cleanup. 8: * 2.1 19Oct87 3. Experiment increasing number of segments. 9: * 2.2 03Dec90 4. Merged error.c into this because it had 10: * been reduced to two write() statements. 11: * 3.0 08Sep93 5. Polish it up for use in 'ld.c' (2.11BSD). 12: * Release into the Public Domain. 13: * -------------------------------------------------- 14: */ 15: 16: #include <vmf.h> 17: #include <errno.h> 18: #include <stdio.h> 19: #include <sys/file.h> 20: 21: /* 22: * Choose ONE and only one of the following swap policies 23: */ 24: /* #define LRU /* Least Recently Used */ 25: /* #define PERC 3 /* Percolation */ 26: #define LRS /* Least Recently Swapped */ 27: 28: #ifndef DEBUG 29: #define debugseg(s,m) /* do nothing */ 30: #else 31: static void debugseg(); 32: #endif 33: 34: /* 35: * This is vfm.c, the file of virtual memory management primitives. 36: * Call vminit first to get the in memory segments set up. 37: * Then call vmopen for each virtual space to be used. 38: * Normal transactions against segments are handled via vmmapseg. 39: * At wrapup time, call vmflush if any modified segments are 40: * assigned to permanent files. 41: */ 42: 43: #define NOSEGNO (-1) /* can never match a segment number */ 44: 45: static struct dlink seghead[1]; 46: long nswaps, nmapsegs; /* statistics */ 47: extern int read(), write(), errno; 48: static int swap(); 49: static void promote(), vmerror(); 50: 51: /* 52: * vminit --- initialize virtual memory system with 'n' in-memory segments 53: */ 54: 55: int 56: vminit(n) 57: int n; 58: { 59: register struct vseg *s; 60: static struct vseg *segs; 61: 62: segs = (struct vseg *)calloc(n, sizeof (struct vseg)); 63: if (!segs) 64: { 65: errno = ENOMEM; 66: return(-1); 67: } 68: seghead[0].fwd = seghead[0].back = seghead; /* selfpoint */ 69: 70: for (s = segs; s < &segs[n] ; s++) 71: { 72: s->s_link.fwd = seghead; 73: s->s_link.back = seghead[0].back; 74: s->s_link.back->fwd = s->s_link.fwd->back = (struct dlink *)s; 75: s->s_segno = NOSEGNO; 76: s->s_vspace = NULL; 77: s->s_lock_count = 0; /* vmunlocked */ 78: s->s_flags = 0; /* not DIRTY */ 79: } 80: return(0); 81: } 82: 83: /* 84: * vmmapseg --- convert segment number to real memory address 85: */ 86: 87: struct vseg * 88: vmmapseg(vspace, segno) 89: struct vspace *vspace; 90: u_short segno; 91: { 92: register struct vseg *s; 93: 94: nmapsegs++; 95: 96: if (segno >= vspace->v_maxsegno || segno < 0) 97: { 98: #ifdef DEBUG 99: fprintf(stderr,"vmmapseg vspace0%o segno%d\n", vspace, segno); 100: #endif 101: vmerror("vmmapseg: bad segno"); 102: } 103: 104: /* look for segment in memory */ 105: for (s = (struct vseg *)seghead[0].fwd; 106: s->s_segno != segno || s->s_vspace != vspace; 107: s = (struct vseg *)s->s_link.fwd) 108: { 109: if (s == (struct vseg *)seghead) 110: { /* not in memory */ 111: int status; 112: 113: for (s = (struct vseg *)s->s_link.back; s->s_lock_count != 0; 114: s = (struct vseg *)s->s_link.back) 115: { 116: if (s == (struct vseg *)seghead) 117: vmerror("Too many locked segs!"); 118: debugseg(s, "back skip"); 119: } 120: debugseg(s, "dump on"); 121: if (s->s_flags & S_DIRTY) 122: if (swap(s, write) != 0) 123: { 124: fprintf(stderr, 125: "write swap, v=%d fd=%d\n", 126: s->s_vspace,s->s_vspace->v_fd); 127: exit(-2); 128: } 129: s->s_vspace = vspace; 130: s->s_segno = segno; 131: s->s_flags &= ~S_DIRTY; 132: status = swap(s, read); 133: if (status == -2) 134: { 135: fprintf(stderr, "can't read swap file"); 136: exit(-2); 137: } 138: else if (status == -1) 139: (void)vmclrseg(s); 140: #ifdef LRS /* Least Recently Swapped */ 141: promote(s); 142: #endif 143: break; 144: } 145: debugseg(s, "forward skip"); 146: } 147: #ifdef PERC 148: { /* percolate just-referenced segment up list */ 149: register struct dlink *neighbor, *target; 150: int count; 151: 152: s->fwd->back = s->back; /* delete */ 153: s->back->fwd = s->fwd; 154: 155: count = PERC; /* upward mobility */ 156: for (target = s; target != seghead && count-- > 0; ) 157: target = target->back; 158: neighbor = target->fwd; 159: s->back = target; /* reinsert */ 160: s->fwd = neighbor; 161: target->fwd = neighbor->back = s; 162: } 163: #endif 164: #ifdef LRU /* Least Recently Used */ 165: promote(s); 166: #endif 167: debugseg(s, "vmmapseg returns"); 168: return(s); 169: } 170: 171: /* 172: * swap --- swap a segment in or out 173: * (called only from this file) 174: */ 175: 176: static int 177: swap(seg, iofunc) /* used only from this file */ 178: register struct vseg *seg; 179: int (*iofunc)(); 180: { 181: off_t file_address; 182: register struct vspace *v; 183: 184: v = seg->s_vspace; 185: nswaps++; 186: file_address = seg->s_segno; 187: file_address *= (BYTESPERSEG); 188: file_address += v->v_foffset; 189: #ifdef SWAPTRACE 190: printf("fd%d blk%d\tswap %s\n", v->v_fd, file_address, 191: iofunc == read ? "in" : "out"); 192: #endif 193: if (lseek(v->v_fd, file_address, L_SET) == -1L) 194: return(-2); 195: 196: switch ((*iofunc)(v->v_fd, seg->s_cinfo, BYTESPERSEG)) 197: { 198: case BYTESPERSEG: 199: return(0); 200: case 0: 201: return(-1); 202: default: 203: return(-2); 204: } 205: } 206: 207: void 208: vmclrseg(seg) 209: register struct vseg *seg; 210: { 211: 212: (void)bzero(seg->s_cinfo, BYTESPERSEG); 213: vmmodify(seg); 214: } 215: 216: /* 217: * vmlock --- vmlock a segment into real memory 218: */ 219: 220: void 221: vmlock(seg) 222: register struct vseg *seg; 223: { 224: 225: seg->s_lock_count++; 226: if (seg->s_lock_count < 0) 227: vmerror("vmlock: overflow"); 228: } 229: 230: /* 231: * vmunlock --- unlock a segment 232: */ 233: 234: void 235: vmunlock(seg) 236: register struct vseg *seg; 237: { 238: 239: --seg->s_lock_count; 240: if (seg->s_lock_count < 0) 241: vmerror("vmlock: underflow"); 242: } 243: 244: /* 245: * vmmodify --- declare a segment to have been modified 246: */ 247: 248: void 249: vmmodify(seg) 250: register struct vseg *seg; 251: { 252: 253: VMMODIFY(seg); 254: debugseg(seg, "vmmodify"); 255: } 256: 257: /* 258: * vmflush --- flush out virtual space buffers 259: */ 260: 261: void 262: vmflush() 263: { 264: register struct vseg *s; 265: 266: for (s = (struct vseg *)seghead[0].fwd; s != (struct vseg *)seghead; 267: s = (struct vseg *)s->s_link.fwd) 268: if (s->s_flags & S_DIRTY) 269: swap(s, write); 270: } 271: 272: /* 273: * debugseg --- output debugging information about a seg in mem 274: */ 275: #ifdef DEBUG 276: static void 277: debugseg(s, msg) 278: char *msg; 279: register struct vseg *s; 280: { 281: fprintf(stderr, "seg%o vspace%o segno%d flags%o vmlock%d %s\r\n", 282: s, s->s_vspace, s->s_segno, s->s_flags, s->s_lock_count, msg); 283: } 284: #endif 285: 286: /* 287: * vmopen --- open a virtual space associated with a file 288: */ 289: 290: int 291: vmopen(vs, filename) 292: register struct vspace *vs; 293: char *filename; 294: { 295: register int fd; 296: char junk[32]; 297: 298: if (!filename) 299: { 300: strcpy(junk, "/tmp/vmXXXXXX"); 301: fd = mkstemp(junk); 302: unlink(junk); 303: } 304: else 305: fd = open(filename, O_RDWR|O_CREAT, 0664); 306: 307: if (fd != -1) 308: { 309: vs->v_fd = fd; 310: vs->v_foffset = 0; 311: vs->v_maxsegno = MAXSEGNO; 312: } 313: return(fd); 314: } 315: 316: /* 317: * vmclose --- closes a virtual space associated with a file 318: * invalidates all segments associated with that file 319: */ 320: 321: void 322: vmclose(vs) 323: register struct vspace *vs; 324: { 325: register struct vseg *s; 326: 327: vmflush(); 328: /* invalidate all segments associated with that file */ 329: for (s = (struct vseg *)seghead[0].fwd; s != (struct vseg *)seghead; 330: s = (struct vseg *)s->s_link.fwd) 331: { 332: if (s->s_vspace == vs) 333: { 334: s->s_segno = NOSEGNO; 335: s->s_vspace = NULL; 336: s->s_lock_count = 0; /* vmunlocked */ 337: s->s_flags &= ~S_DIRTY; 338: } 339: } 340: close(vs->v_fd); 341: } 342: 343: /* 344: * promote --- put a segment at the top of the list 345: */ 346: 347: static void 348: promote(s) 349: register struct vseg *s; 350: { 351: 352: s->s_link.fwd->back = s->s_link.back; /* delete */ 353: s->s_link.back->fwd = s->s_link.fwd; 354: 355: s->s_link.fwd = seghead[0].fwd; /* insert at top of totem pole */ 356: s->s_link.back = seghead; 357: seghead[0].fwd = s->s_link.fwd->back = (struct dlink *)s; 358: } 359: 360: /* 361: * vmerror --- print error message and commit suicide 362: * Message should always make clear where called from. 363: * Example: vmerror("In floogle: can't happen!"); 364: */ 365: 366: static void 367: vmerror(msg) 368: char *msg; 369: { 370: fprintf(stderr, "%s\n", msg); 371: abort(); /* terminate process with core dump */ 372: }